From ceea4c88be9d06d932a83de0af42f790b47700ba Mon Sep 17 00:00:00 2001 From: dP Date: Fri, 1 Nov 2019 16:08:44 +0300 Subject: [PATCH] Merge 1.10.0-beta1 --- .gitignore | 4 + COMPILING.md | 141 ++ CONTRIBUTING.md | 134 +- COPYING.md | 339 +++++ Doxyfile | 9 +- Makefile.bundle.in | 18 +- Makefile.in | 2 +- Makefile.src.in | 8 +- README.md | 180 +-- azure-pipelines-ci.yml | 5 +- azure-pipelines/templates/release.yml | 9 +- azure-pipelines/templates/windows-build.yml | 2 +- bin/ai/compat_1.10.nut | 8 + bin/ai/compat_1.9.nut | 2 + bin/ai/regression/completeness.sh | 6 +- bin/ai/regression/regression_info.nut | 2 +- bin/ai/regression/tst_regression/main.nut | 13 + bin/ai/regression/tst_regression/result.txt | 18 +- bin/baseset/openttd.grf | Bin 502521 -> 510237 bytes bin/baseset/opntitle.dat | Bin 54172 -> 138710 bytes bin/game/compat_1.9.nut | 2 + changelog.txt | 68 +- config.lib | 180 +-- configure | 14 +- docs/admin_network.md | 235 ++++ docs/compiling_lang_files.md | 69 + docs/desync.md | 267 ++++ docs/landscape.html | 61 +- docs/landscape_grid.html | 38 +- docs/linkgraph.md | 30 + docs/multiplayer.md | 213 +++ findversion.sh | 2 +- known-bugs.txt | 8 +- media/baseset/orig_win.obm | 2 +- media/extra_grf/openttdgui.nfo | 7 +- media/extra_grf/openttdgui_build_tram.png | Bin 0 -> 1017 bytes media/extra_grf/openttdgui_convert_road.png | Bin 0 -> 1274 bytes media/extra_grf/openttdgui_convert_tram.png | Bin 0 -> 1289 bytes media/extra_grf/tramtracks.nfo | 8 +- media/extra_grf/tramtracks_bare_depot.png | Bin 0 -> 3661 bytes os/debian/changelog | 9 +- os/debian/control | 2 +- os/debian/rules | 2 +- os/os2/installer/make_installer.cmd | 2 +- os/os2/installer/openttd.wis | 4 +- os/rpm/openttd.changes | 4 +- os/rpm/openttd.spec | 10 +- os/windows/installer/install.nsi | 22 +- projects/generate | 6 +- projects/generate.vbs | 5 +- projects/generate_vs142.vcxproj | 1 - projects/openttd_vs140.vcxproj | 28 +- projects/openttd_vs140.vcxproj.filters | 56 +- projects/openttd_vs140.vcxproj.in | 8 +- projects/openttd_vs141.vcxproj | 28 +- projects/openttd_vs141.vcxproj.filters | 56 +- projects/openttd_vs141.vcxproj.in | 8 +- projects/openttd_vs142.vcxproj | 36 +- projects/openttd_vs142.vcxproj.filters | 56 +- projects/openttd_vs142.vcxproj.in | 16 +- projects/settingsgen_vs142.vcxproj | 1 - projects/strgen_vs142.vcxproj | 7 +- source.list | 210 ++- src/3rdparty/squirrel/squirrel/sqcompiler.cpp | 2 +- src/3rdparty/squirrel/squirrel/sqfuncproto.h | 13 - .../squirrel/squirrel/sqfuncstate.cpp | 4 +- src/3rdparty/squirrel/squirrel/sqmem.cpp | 8 +- src/3rdparty/squirrel/squirrel/sqvm.h | 5 +- src/ai/ai.hpp | 4 +- src/ai/ai_config.cpp | 21 +- src/ai/ai_config.hpp | 11 +- src/ai/ai_core.cpp | 64 +- src/ai/ai_gui.cpp | 132 +- src/ai/ai_info.cpp | 14 +- src/ai/ai_info.hpp | 2 +- src/ai/ai_instance.cpp | 10 +- src/ai/ai_instance.hpp | 12 +- src/ai/ai_scanner.cpp | 14 +- src/ai/ai_scanner.hpp | 28 +- src/aircraft.h | 2 +- src/aircraft_cmd.cpp | 99 +- src/aircraft_gui.cpp | 2 +- src/airport.cpp | 8 +- src/airport.h | 55 +- src/airport_gui.cpp | 41 +- src/animated_tile.cpp | 16 +- src/articulated_vehicles.cpp | 30 +- src/autoreplace.cpp | 22 +- src/autoreplace_cmd.cpp | 100 +- src/autoreplace_func.h | 4 +- src/autoreplace_gui.cpp | 230 ++- src/base_consist.cpp | 2 +- src/base_consist.h | 2 +- src/base_media_base.h | 30 +- src/base_media_func.h | 67 +- src/base_station_base.h | 12 +- src/bitmap_type.h | 137 ++ src/blitter/32bpp_anim.cpp | 4 +- src/blitter/32bpp_anim.hpp | 34 +- src/blitter/32bpp_anim_sse2.hpp | 6 +- src/blitter/32bpp_anim_sse4.hpp | 10 +- src/blitter/32bpp_base.hpp | 26 +- src/blitter/32bpp_optimized.cpp | 4 +- src/blitter/32bpp_optimized.hpp | 8 +- src/blitter/32bpp_simple.hpp | 10 +- src/blitter/32bpp_sse2.hpp | 8 +- src/blitter/32bpp_sse4.hpp | 6 +- src/blitter/32bpp_ssse3.hpp | 6 +- src/blitter/8bpp_base.hpp | 28 +- src/blitter/8bpp_optimized.cpp | 8 +- src/blitter/8bpp_optimized.hpp | 8 +- src/blitter/8bpp_simple.hpp | 8 +- src/blitter/factory.hpp | 14 +- src/blitter/null.hpp | 36 +- src/bmp.cpp | 6 +- src/bmp.h | 2 +- src/bootstrap_gui.cpp | 30 +- src/bridge_gui.cpp | 84 +- src/bridge_map.h | 32 +- src/build_vehicle_gui.cpp | 632 +++++---- src/cargo_type.h | 3 +- src/cargoaction.cpp | 16 +- src/cargomonitor.cpp | 6 +- src/cargopacket.cpp | 16 +- src/cargopacket.h | 18 +- src/cargotype.cpp | 32 +- src/cargotype.h | 8 +- src/cheat_gui.cpp | 20 +- src/clear_cmd.cpp | 10 +- src/command.cpp | 39 +- src/command_func.h | 6 +- src/command_type.h | 10 +- src/commands_gui.cpp | 2 - src/company_base.h | 11 +- src/company_cmd.cpp | 108 +- src/company_func.h | 4 +- src/company_gui.cpp | 254 ++-- src/company_type.h | 4 +- src/console.cpp | 52 +- src/console_cmds.cpp | 136 +- src/console_gui.cpp | 58 +- src/console_internal.h | 2 +- src/core/alloc_func.hpp | 24 +- src/core/alloc_type.hpp | 99 +- src/core/bitmath_func.hpp | 10 +- src/core/endian_type.hpp | 2 +- src/core/enum_type.hpp | 106 -- src/core/geometry_type.hpp | 19 +- src/core/kdtree.hpp | 486 +++++++ src/core/math_func.hpp | 18 +- src/core/mem_func.hpp | 4 +- src/core/pool_func.cpp | 9 +- src/core/pool_func.hpp | 28 +- src/core/pool_type.hpp | 34 +- src/core/smallmap_type.hpp | 82 +- src/core/smallmatrix_type.hpp | 10 +- src/core/smallstack_type.hpp | 24 +- src/core/smallvec_type.hpp | 448 +----- src/cpu.cpp | 2 +- src/crashlog.cpp | 82 +- src/crashlog.h | 2 +- src/currency.cpp | 3 + src/currency.h | 3 + src/date.cpp | 8 - src/date_gui.cpp | 24 +- src/debug.cpp | 18 +- src/debug.h | 34 +- src/dedicated.cpp | 20 +- src/depend/depend.cpp | 72 +- src/depot_cmd.cpp | 6 +- src/depot_gui.cpp | 124 +- src/direction_type.h | 6 +- src/disaster_vehicle.cpp | 28 +- src/dock_gui.cpp | 45 +- src/driver.cpp | 39 +- src/driver.h | 6 +- src/economy.cpp | 90 +- src/economy_type.h | 3 +- src/effectvehicle.cpp | 2 +- src/elrail.cpp | 6 +- src/engine.cpp | 75 +- src/engine_base.h | 14 +- src/engine_func.h | 2 +- src/engine_gui.cpp | 25 +- src/engine_gui.h | 2 +- src/engine_type.h | 4 +- src/error.h | 4 +- src/error_gui.cpp | 32 +- src/fileio.cpp | 202 ++- src/fileio_func.h | 10 +- src/fios.cpp | 157 +-- src/fios.h | 38 +- src/fios_gui.cpp | 176 ++- src/fontcache.cpp | 754 +++++++--- src/fontcache.h | 17 +- src/fontdetection.cpp | 110 +- src/fontdetection.h | 5 +- src/framerate_gui.cpp | 79 +- src/game/game.hpp | 2 - src/game/game_config.cpp | 4 +- src/game/game_config.hpp | 2 +- src/game/game_core.cpp | 78 +- src/game/game_info.cpp | 10 +- src/game/game_info.hpp | 4 +- src/game/game_instance.cpp | 6 +- src/game/game_instance.hpp | 12 +- src/game/game_scanner.cpp | 10 +- src/game/game_scanner.hpp | 28 +- src/game/game_text.cpp | 123 +- src/game/game_text.hpp | 12 +- src/gamelog.cpp | 75 +- src/genworld.cpp | 55 +- src/genworld.h | 7 +- src/genworld_gui.cpp | 64 +- src/gfx.cpp | 103 +- src/gfx_func.h | 16 +- src/gfx_layout.cpp | 233 ++-- src/gfx_layout.h | 18 +- src/gfx_type.h | 2 +- src/gfxinit.cpp | 26 +- src/goal.cpp | 14 +- src/goal_base.h | 14 +- src/goal_gui.cpp | 26 +- src/goal_type.h | 3 +- src/graph_gui.cpp | 70 +- src/ground_vehicle.cpp | 10 +- src/ground_vehicle.hpp | 10 +- src/group.h | 19 +- src/group_cmd.cpp | 95 +- src/group_gui.cpp | 203 ++- src/heightmap.cpp | 42 +- src/highscore.cpp | 11 +- src/highscore_gui.cpp | 14 +- src/hotkeys.cpp | 42 +- src/hotkeys.h | 6 +- src/industry.h | 27 +- src/industry_cmd.cpp | 310 +++-- src/industry_gui.cpp | 310 ++--- src/industrytype.h | 16 +- src/ini.cpp | 14 +- src/ini_load.cpp | 62 +- src/ini_type.h | 14 +- src/intro_gui.cpp | 26 +- src/landscape.cpp | 56 +- src/landscape.h | 8 +- src/lang/afrikaans.txt | 28 +- src/lang/arabic_egypt.txt | 26 +- src/lang/basque.txt | 28 +- src/lang/belarusian.txt | 40 +- src/lang/brazilian_portuguese.txt | 28 +- src/lang/bulgarian.txt | 42 +- src/lang/catalan.txt | 40 +- src/lang/croatian.txt | 95 +- src/lang/czech.txt | 167 ++- src/lang/danish.txt | 46 +- src/lang/dutch.txt | 95 +- src/lang/english.txt | 104 +- src/lang/english_AU.txt | 28 +- src/lang/english_US.txt | 95 +- src/lang/esperanto.txt | 26 +- src/lang/estonian.txt | 40 +- src/lang/faroese.txt | 28 +- src/lang/finnish.txt | 103 +- src/lang/french.txt | 109 +- src/lang/gaelic.txt | 28 +- src/lang/galician.txt | 28 +- src/lang/german.txt | 28 +- src/lang/greek.txt | 59 +- src/lang/hebrew.txt | 28 +- src/lang/hungarian.txt | 101 +- src/lang/icelandic.txt | 28 +- src/lang/indonesian.txt | 36 +- src/lang/irish.txt | 28 +- src/lang/italian.txt | 101 +- src/lang/japanese.txt | 28 +- src/lang/korean.txt | 163 ++- src/lang/latin.txt | 55 +- src/lang/latvian.txt | 28 +- src/lang/lithuanian.txt | 64 +- src/lang/luxembourgish.txt | 43 +- src/lang/malay.txt | 28 +- src/lang/norwegian_bokmal.txt | 95 +- src/lang/norwegian_nynorsk.txt | 28 +- src/lang/polish.txt | 35 +- src/lang/portuguese.txt | 57 +- src/lang/romanian.txt | 28 +- src/lang/russian.txt | 109 +- src/lang/serbian.txt | 34 +- src/lang/simplified_chinese.txt | 117 +- src/lang/slovak.txt | 28 +- src/lang/slovenian.txt | 28 +- src/lang/spanish.txt | 96 +- src/lang/spanish_MX.txt | 107 +- src/lang/swedish.txt | 95 +- src/lang/tamil.txt | 99 +- src/lang/thai.txt | 28 +- src/lang/traditional_chinese.txt | 29 +- src/lang/turkish.txt | 28 +- src/lang/ukrainian.txt | 46 +- src/lang/unfinished/chuvash.txt | 15 +- src/lang/unfinished/frisian.txt | 26 +- src/lang/unfinished/ido.txt | 11 + src/lang/unfinished/macedonian.txt | 18 +- src/lang/unfinished/maltese.txt | 11 + src/lang/unfinished/marathi.txt | 11 + src/lang/unfinished/persian.txt | 26 +- src/lang/unfinished/urdu.txt | 18 +- src/lang/vietnamese.txt | 28 +- src/lang/welsh.txt | 32 +- src/language.h | 10 +- src/linkgraph/demands.h | 2 +- src/linkgraph/init.h | 2 +- src/linkgraph/linkgraph.cpp | 9 +- src/linkgraph/linkgraph.h | 4 +- src/linkgraph/linkgraph_gui.cpp | 8 +- src/linkgraph/linkgraph_gui.h | 10 +- src/linkgraph/linkgraph_type.h | 3 +- src/linkgraph/linkgraphjob.cpp | 22 +- src/linkgraph/linkgraphjob.h | 14 +- src/linkgraph/linkgraphschedule.cpp | 8 +- src/linkgraph/linkgraphschedule.h | 2 +- src/linkgraph/mcf.cpp | 22 +- src/linkgraph/refresh.cpp | 24 +- src/main_gui.cpp | 58 +- src/map.cpp | 12 +- src/misc.cpp | 11 +- src/misc/binaryheap.hpp | 2 +- src/misc/blob.hpp | 16 +- src/misc/countedptr.hpp | 34 +- src/misc/dbg_helpers.h | 4 +- src/misc/fixedsizearray.hpp | 2 +- src/misc/getoptdata.cpp | 14 +- src/misc/getoptdata.h | 24 +- src/misc/hashtable.hpp | 38 +- src/misc/str.hpp | 8 +- src/misc_cmd.cpp | 18 +- src/misc_gui.cpp | 153 +- src/mixer.cpp | 8 +- src/music.cpp | 38 +- src/music/allegro_m.cpp | 16 +- src/music/allegro_m.h | 16 +- src/music/bemidi.cpp | 2 +- src/music/bemidi.h | 16 +- src/music/cocoa_m.cpp | 30 +- src/music/cocoa_m.h | 16 +- src/music/dmusic.cpp | 100 +- src/music/dmusic.h | 16 +- src/music/extmidi.cpp | 13 +- src/music/extmidi.h | 16 +- src/music/fluidsynth.cpp | 16 +- src/music/fluidsynth.h | 16 +- src/music/midifile.cpp | 75 +- src/music/midifile.hpp | 6 +- src/music/null_m.h | 16 +- src/music/os2_m.cpp | 4 +- src/music/os2_m.h | 16 +- src/music/qtmidi.cpp | 28 +- src/music/qtmidi.h | 16 +- src/music/win32_m.cpp | 73 +- src/music/win32_m.h | 16 +- src/music_gui.cpp | 23 +- src/network/core/address.cpp | 39 +- src/network/core/address.h | 20 +- src/network/core/core.cpp | 51 - src/network/core/core.h | 4 - src/network/core/game.h | 4 - src/network/core/host.cpp | 28 +- src/network/core/os_abstraction.h | 108 +- src/network/core/packet.cpp | 18 +- src/network/core/packet.h | 4 - src/network/core/tcp.cpp | 46 +- src/network/core/tcp.h | 11 +- src/network/core/tcp_admin.cpp | 6 +- src/network/core/tcp_admin.h | 6 +- src/network/core/tcp_connect.cpp | 26 +- src/network/core/tcp_content.cpp | 18 +- src/network/core/tcp_content.h | 6 +- src/network/core/tcp_game.cpp | 8 +- src/network/core/tcp_game.h | 12 +- src/network/core/tcp_http.cpp | 52 +- src/network/core/tcp_http.h | 20 +- src/network/core/tcp_listen.h | 38 +- src/network/core/udp.cpp | 50 +- src/network/core/udp.h | 10 +- src/network/network.cpp | 70 +- src/network/network.h | 18 - src/network/network_admin.cpp | 22 +- src/network/network_admin.h | 19 +- src/network/network_base.h | 3 - src/network/network_chat_gui.cpp | 32 +- src/network/network_client.cpp | 87 +- src/network/network_client.h | 60 +- src/network/network_command.cpp | 42 +- src/network/network_content.cpp | 227 ++- src/network/network_content.h | 56 +- src/network/network_content_gui.cpp | 165 ++- src/network/network_content_gui.h | 4 +- src/network/network_func.h | 5 +- src/network/network_gamelist.cpp | 55 +- src/network/network_gui.cpp | 315 +++-- src/network/network_gui.h | 12 - src/network/network_internal.h | 7 +- src/network/network_server.cpp | 164 +-- src/network/network_server.h | 47 +- src/network/network_type.h | 5 +- src/network/network_udp.cpp | 142 +- src/network/network_udp.h | 4 - src/newgrf.cpp | 1230 +++++++++++------ src/newgrf.h | 24 +- src/newgrf_airport.cpp | 54 +- src/newgrf_airport.h | 1 + src/newgrf_airporttiles.cpp | 14 +- src/newgrf_airporttiles.h | 12 +- src/newgrf_animation_base.h | 2 +- src/newgrf_canal.cpp | 12 +- src/newgrf_cargo.cpp | 10 +- src/newgrf_class_func.h | 12 +- src/newgrf_commons.cpp | 55 +- src/newgrf_commons.h | 16 +- src/newgrf_config.cpp | 195 ++- src/newgrf_config.h | 50 +- src/newgrf_debug.h | 2 +- src/newgrf_debug_gui.cpp | 88 +- src/newgrf_engine.cpp | 169 +-- src/newgrf_engine.h | 16 +- src/newgrf_generic.cpp | 16 +- src/newgrf_gui.cpp | 433 +++--- src/newgrf_house.cpp | 23 +- src/newgrf_house.h | 8 +- src/newgrf_industries.cpp | 56 +- src/newgrf_industries.h | 16 +- src/newgrf_industrytiles.cpp | 26 +- src/newgrf_industrytiles.h | 10 +- src/newgrf_object.cpp | 34 +- src/newgrf_object.h | 8 +- src/newgrf_railtype.cpp | 29 +- src/newgrf_railtype.h | 10 +- src/newgrf_roadtype.cpp | 143 ++ src/newgrf_roadtype.h | 51 + src/newgrf_sound.cpp | 18 +- src/newgrf_spritegroup.cpp | 18 +- src/newgrf_spritegroup.h | 6 +- src/newgrf_station.cpp | 98 +- src/newgrf_station.h | 17 +- src/newgrf_storage.h | 10 +- src/newgrf_text.cpp | 98 +- src/newgrf_text.h | 10 +- src/newgrf_town.cpp | 6 +- src/newgrf_town.h | 2 +- src/newgrf_townname.cpp | 30 +- src/news_func.h | 4 +- src/news_gui.cpp | 219 +-- src/news_type.h | 6 +- src/object.h | 2 +- src/object_base.h | 2 +- src/object_cmd.cpp | 48 +- src/object_gui.cpp | 34 +- src/openttd.cpp | 219 ++- src/openttd.h | 5 +- src/order_backup.cpp | 22 +- src/order_base.h | 12 +- src/order_cmd.cpp | 199 ++- src/order_gui.cpp | 106 +- src/order_type.h | 10 +- src/os/macosx/crashlog_osx.cpp | 22 +- src/os/macosx/macos.mm | 17 - src/os/macosx/osx_stdafx.h | 2 +- src/os/macosx/splash.cpp | 16 +- src/os/macosx/string_osx.cpp | 105 +- src/os/macosx/string_osx.h | 8 +- src/os/os2/os2.cpp | 27 +- src/os/unix/crashlog_unix.cpp | 8 +- src/os/unix/unix.cpp | 131 +- src/os/windows/crashlog_win.cpp | 60 +- src/os/windows/ottdres.rc.in | 4 +- src/os/windows/string_uniscribe.cpp | 121 +- src/os/windows/string_uniscribe.h | 8 +- src/os/windows/win32.cpp | 103 +- src/os/windows/win32.h | 6 - src/osk_gui.cpp | 24 +- src/pathfinder/follow_track.hpp | 46 +- src/pathfinder/npf/aystar.cpp | 18 +- src/pathfinder/npf/npf.cpp | 136 +- src/pathfinder/npf/queue.cpp | 62 +- src/pathfinder/pathfinder_type.h | 3 + src/pathfinder/pf_performance_timer.hpp | 6 +- src/pathfinder/yapf/nodelist.hpp | 20 +- src/pathfinder/yapf/yapf.h | 3 +- src/pathfinder/yapf/yapf_base.hpp | 28 +- src/pathfinder/yapf/yapf_common.hpp | 6 +- src/pathfinder/yapf/yapf_costcache.hpp | 2 +- src/pathfinder/yapf/yapf_costrail.hpp | 18 +- src/pathfinder/yapf/yapf_node.hpp | 9 +- src/pathfinder/yapf/yapf_node_rail.hpp | 12 +- src/pathfinder/yapf/yapf_node_ship.hpp | 14 +- src/pathfinder/yapf/yapf_rail.cpp | 36 +- src/pathfinder/yapf/yapf_road.cpp | 45 +- src/pathfinder/yapf/yapf_ship.cpp | 184 ++- src/pbs.cpp | 40 +- src/pbs.h | 2 +- src/progress.cpp | 8 +- src/progress.h | 16 +- src/querystring_gui.h | 6 +- src/rail.cpp | 45 +- src/rail.h | 42 +- src/rail_cmd.cpp | 203 +-- src/rail_gui.cpp | 183 +-- src/rail_gui.h | 2 +- src/rail_map.h | 3 + src/rail_type.h | 3 +- src/rev.cpp | 13 +- src/rev.cpp.in | 13 +- src/road.cpp | 234 +++- src/road.h | 316 +++++ src/road_cmd.cpp | 1176 ++++++++++++---- src/road_func.h | 88 +- src/road_gui.cpp | 604 +++++--- src/road_gui.h | 6 +- src/road_internal.h | 4 +- src/road_map.cpp | 6 +- src/road_map.h | 263 ++-- src/road_type.h | 30 +- src/roadstop.cpp | 42 +- src/roadveh.h | 37 +- src/roadveh_cmd.cpp | 175 ++- src/roadveh_gui.cpp | 6 +- src/safeguards.h | 2 +- src/saveload/afterload.cpp | 287 ++-- src/saveload/ai_sl.cpp | 10 +- src/saveload/airport_sl.cpp | 4 +- src/saveload/animated_tile_sl.cpp | 18 +- src/saveload/autoreplace_sl.cpp | 2 +- src/saveload/cargomonitor_sl.cpp | 4 +- src/saveload/cargopacket_sl.cpp | 2 +- src/saveload/cheat_sl.cpp | 2 +- src/saveload/company_sl.cpp | 53 +- src/saveload/depot_sl.cpp | 2 +- src/saveload/economy_sl.cpp | 16 +- src/saveload/engine_sl.cpp | 21 +- src/saveload/game_sl.cpp | 48 +- src/saveload/gamelog_sl.cpp | 8 +- src/saveload/goal_sl.cpp | 2 +- src/saveload/group_sl.cpp | 2 +- src/saveload/industry_sl.cpp | 11 +- src/saveload/labelmaps_sl.cpp | 18 +- src/saveload/linkgraph_sl.cpp | 18 +- src/saveload/map_sl.cpp | 105 +- src/saveload/misc_sl.cpp | 8 +- src/saveload/newgrf_sl.cpp | 6 +- src/saveload/object_sl.cpp | 4 +- src/saveload/oldloader.cpp | 22 +- src/saveload/oldloader.h | 14 +- src/saveload/oldloader_sl.cpp | 54 +- src/saveload/order_sl.cpp | 8 +- src/saveload/saveload.cpp | 210 ++- src/saveload/saveload.h | 36 +- src/saveload/saveload_filter.h | 2 +- src/saveload/saveload_internal.h | 2 +- src/saveload/signs_sl.cpp | 2 +- src/saveload/station_sl.cpp | 32 +- src/saveload/storage_sl.cpp | 2 +- src/saveload/story_sl.cpp | 4 +- src/saveload/strings_sl.cpp | 10 +- src/saveload/subsidy_sl.cpp | 2 +- src/saveload/town_sl.cpp | 5 +- src/saveload/vehicle_sl.cpp | 106 +- src/saveload/waypoint_sl.cpp | 86 +- src/screenshot.cpp | 24 +- src/script/api/ai/ai_engine.hpp.sq | 2 + src/script/api/ai/ai_event.hpp.sq | 1 + src/script/api/ai/ai_event_types.hpp.sq | 16 + src/script/api/ai/ai_group.hpp.sq | 4 + src/script/api/ai/ai_rail.hpp.sq | 2 +- src/script/api/ai/ai_road.hpp.sq | 16 + src/script/api/ai/ai_roadtypelist.hpp.sq | 25 + src/script/api/ai/ai_vehicle.hpp.sq | 2 + src/script/api/ai_changelog.hpp | 29 +- src/script/api/game/game_engine.hpp.sq | 2 + src/script/api/game/game_event.hpp.sq | 1 + src/script/api/game/game_rail.hpp.sq | 2 +- src/script/api/game/game_road.hpp.sq | 16 + src/script/api/game/game_roadtypelist.hpp.sq | 25 + src/script/api/game/game_vehicle.hpp.sq | 2 + src/script/api/game/game_window.hpp.sq | 16 +- src/script/api/game_changelog.hpp | 16 + src/script/api/script_admin.cpp | 2 - src/script/api/script_airport.cpp | 20 +- src/script/api/script_basestation.cpp | 6 +- src/script/api/script_basestation.hpp | 2 +- src/script/api/script_bridge.cpp | 12 +- src/script/api/script_cargo.cpp | 2 +- src/script/api/script_cargo.hpp | 2 +- src/script/api/script_cargomonitor.cpp | 8 +- src/script/api/script_client.cpp | 32 +- src/script/api/script_client.hpp | 2 +- src/script/api/script_clientlist.cpp | 4 - src/script/api/script_company.cpp | 10 +- src/script/api/script_company.hpp | 4 +- src/script/api/script_controller.cpp | 4 +- src/script/api/script_engine.cpp | 26 +- src/script/api/script_engine.hpp | 22 + src/script/api/script_error.hpp | 2 +- src/script/api/script_event.cpp | 10 +- src/script/api/script_event.hpp | 1 + src/script/api/script_event_types.cpp | 24 +- src/script/api/script_event_types.hpp | 44 +- src/script/api/script_game.cpp | 4 - src/script/api/script_gamesettings.cpp | 2 +- src/script/api/script_goal.cpp | 24 +- src/script/api/script_goal.hpp | 10 +- src/script/api/script_group.cpp | 40 +- src/script/api/script_group.hpp | 32 +- src/script/api/script_industry.cpp | 6 +- src/script/api/script_industrytype.cpp | 9 +- src/script/api/script_infrastructure.cpp | 6 +- src/script/api/script_list.cpp | 14 +- src/script/api/script_list.hpp | 4 +- src/script/api/script_log.cpp | 4 +- src/script/api/script_marine.cpp | 6 +- src/script/api/script_news.cpp | 2 +- src/script/api/script_news.hpp | 2 +- src/script/api/script_object.cpp | 16 +- src/script/api/script_object.hpp | 4 +- src/script/api/script_order.cpp | 42 +- src/script/api/script_rail.cpp | 14 +- src/script/api/script_rail.hpp | 2 +- src/script/api/script_road.cpp | 101 +- src/script/api/script_road.hpp | 94 +- src/script/api/script_roadtypelist.cpp | 24 + src/script/api/script_roadtypelist.hpp | 31 + src/script/api/script_sign.cpp | 8 +- src/script/api/script_sign.hpp | 4 +- src/script/api/script_station.cpp | 12 +- src/script/api/script_stationlist.cpp | 12 +- src/script/api/script_story_page.cpp | 14 +- src/script/api/script_story_page.hpp | 8 +- src/script/api/script_text.cpp | 20 +- src/script/api/script_text.hpp | 6 +- src/script/api/script_tile.cpp | 36 +- src/script/api/script_tile.hpp | 5 +- src/script/api/script_tilelist.cpp | 44 +- src/script/api/script_town.cpp | 14 +- src/script/api/script_town.hpp | 4 +- src/script/api/script_tunnel.cpp | 6 +- src/script/api/script_vehicle.cpp | 56 +- src/script/api/script_vehicle.hpp | 42 +- src/script/api/script_vehiclelist.cpp | 2 +- src/script/api/script_waypoint.cpp | 2 +- src/script/api/script_waypointlist.cpp | 2 +- src/script/api/script_window.cpp | 6 +- src/script/api/script_window.hpp | 19 +- src/script/api/squirrel_export.awk | 6 +- src/script/api/squirrel_export.vbs | 6 +- .../api/template/template_accounting.hpp.sq | 2 +- src/script/api/template/template_admin.hpp.sq | 2 +- .../api/template/template_airport.hpp.sq | 2 +- src/script/api/template/template_base.hpp.sq | 2 +- .../api/template/template_basestation.hpp.sq | 2 +- .../api/template/template_bridge.hpp.sq | 2 +- .../api/template/template_bridgelist.hpp.sq | 4 +- src/script/api/template/template_cargo.hpp.sq | 2 +- .../api/template/template_cargolist.hpp.sq | 8 +- .../api/template/template_cargomonitor.hpp.sq | 2 +- .../api/template/template_client.hpp.sq | 2 +- .../api/template/template_clientlist.hpp.sq | 4 +- .../api/template/template_company.hpp.sq | 2 +- .../api/template/template_companymode.hpp.sq | 2 +- src/script/api/template/template_date.hpp.sq | 2 +- .../api/template/template_depotlist.hpp.sq | 2 +- .../api/template/template_engine.hpp.sq | 2 +- .../api/template/template_enginelist.hpp.sq | 2 +- src/script/api/template/template_error.hpp.sq | 2 +- src/script/api/template/template_event.hpp.sq | 4 +- .../api/template/template_event_types.hpp.sq | 65 +- .../api/template/template_execmode.hpp.sq | 2 +- src/script/api/template/template_game.hpp.sq | 2 +- .../api/template/template_gamesettings.hpp.sq | 2 +- src/script/api/template/template_goal.hpp.sq | 2 +- src/script/api/template/template_group.hpp.sq | 2 +- .../api/template/template_grouplist.hpp.sq | 2 +- .../api/template/template_industry.hpp.sq | 2 +- .../api/template/template_industrylist.hpp.sq | 6 +- .../api/template/template_industrytype.hpp.sq | 2 +- .../template/template_industrytypelist.hpp.sq | 2 +- .../template/template_infrastructure.hpp.sq | 2 +- src/script/api/template/template_list.hpp.sq | 2 +- src/script/api/template/template_log.hpp.sq | 2 +- src/script/api/template/template_map.hpp.sq | 2 +- .../api/template/template_marine.hpp.sq | 2 +- src/script/api/template/template_news.hpp.sq | 2 +- src/script/api/template/template_order.hpp.sq | 2 +- src/script/api/template/template_rail.hpp.sq | 2 +- .../api/template/template_railtypelist.hpp.sq | 2 +- src/script/api/template/template_road.hpp.sq | 4 +- .../api/template/template_roadtypelist.hpp.sq | 21 + src/script/api/template/template_sign.hpp.sq | 2 +- .../api/template/template_signlist.hpp.sq | 2 +- .../api/template/template_station.hpp.sq | 2 +- .../api/template/template_stationlist.hpp.sq | 26 +- .../api/template/template_story_page.hpp.sq | 2 +- .../template_storypageelementlist.hpp.sq | 2 +- .../template/template_storypagelist.hpp.sq | 2 +- .../api/template/template_subsidy.hpp.sq | 2 +- .../api/template/template_subsidylist.hpp.sq | 2 +- .../api/template/template_testmode.hpp.sq | 2 +- src/script/api/template/template_text.hpp.sq | 2 +- src/script/api/template/template_tile.hpp.sq | 2 +- .../api/template/template_tilelist.hpp.sq | 8 +- src/script/api/template/template_town.hpp.sq | 2 +- .../api/template/template_townlist.hpp.sq | 4 +- .../api/template/template_tunnel.hpp.sq | 2 +- .../api/template/template_vehicle.hpp.sq | 2 +- .../api/template/template_vehiclelist.hpp.sq | 12 +- .../api/template/template_viewport.hpp.sq | 2 +- .../api/template/template_waypoint.hpp.sq | 2 +- .../api/template/template_waypointlist.hpp.sq | 4 +- .../api/template/template_window.hpp.sq | 2 +- src/script/script_config.cpp | 38 +- src/script/script_config.hpp | 10 +- src/script/script_info.cpp | 22 +- src/script/script_info.hpp | 24 +- src/script/script_info_dummy.cpp | 4 +- src/script/script_instance.cpp | 112 +- src/script/script_instance.hpp | 5 +- src/script/script_scanner.cpp | 39 +- src/script/script_scanner.hpp | 4 +- src/script/script_storage.hpp | 8 +- src/script/squirrel.cpp | 179 ++- src/script/squirrel.hpp | 36 +- src/script/squirrel_class.hpp | 10 +- src/script/squirrel_helper.hpp | 52 +- src/script/squirrel_helper_type.hpp | 2 +- src/script/squirrel_std.cpp | 4 +- src/settings.cpp | 243 ++-- src/settings_func.h | 12 +- src/settings_gui.cpp | 288 ++-- src/settings_gui.h | 2 +- src/settings_internal.h | 8 +- src/settings_type.h | 48 +- src/settingsgen/settingsgen.cpp | 103 +- src/ship.h | 14 +- src/ship_cmd.cpp | 103 +- src/signal.cpp | 16 +- src/signs_base.h | 2 +- src/signs_cmd.cpp | 5 +- src/signs_gui.cpp | 70 +- src/smallmap_gui.cpp | 106 +- src/smallmap_gui.h | 22 +- src/sortlist_type.h | 32 +- src/sound.cpp | 20 +- src/sound/allegro_s.cpp | 16 +- src/sound/allegro_s.h | 10 +- src/sound/cocoa_s.cpp | 16 +- src/sound/cocoa_s.h | 8 +- src/sound/null_s.h | 8 +- src/sound/sdl2_s.cpp | 70 + src/sound/sdl_s.cpp | 2 +- src/sound/sdl_s.h | 10 +- src/sound/win32_s.cpp | 15 +- src/sound/win32_s.h | 8 +- src/sound/xaudio2_s.cpp | 8 +- src/sound/xaudio2_s.h | 8 +- src/sprite.cpp | 2 +- src/spritecache.cpp | 38 +- src/spritecache.h | 2 +- src/spriteloader/grf.cpp | 14 +- src/station.cpp | 221 ++- src/station_base.h | 49 +- src/station_cmd.cpp | 987 +++++++------ src/station_func.h | 10 +- src/station_gui.cpp | 288 ++-- src/station_kdtree.h | 42 + src/station_map.h | 24 +- src/station_type.h | 14 +- src/statusbar_gui.cpp | 22 +- src/stdafx.h | 75 +- src/story.cpp | 6 +- src/story_base.h | 11 +- src/story_gui.cpp | 136 +- src/strgen/strgen.cpp | 53 +- src/strgen/strgen.h | 2 +- src/strgen/strgen_base.cpp | 144 +- src/string.cpp | 80 +- src/string_func.h | 6 +- src/string_type.h | 6 + src/stringfilter.cpp | 36 +- src/stringfilter_type.h | 10 +- src/strings.cpp | 218 +-- src/strings_func.h | 27 +- src/strings_type.h | 3 +- src/subsidy.cpp | 32 +- src/subsidy_base.h | 16 +- src/subsidy_gui.cpp | 10 +- src/subsidy_type.h | 5 +- src/table/airport_defaults.h | 6 +- src/table/airport_movement.h | 456 +++--- src/table/bridge_land.h | 2 +- src/table/build_industry.h | 322 ++--- src/table/cargo_const.h | 2 +- src/table/company_settings.ini | 4 +- src/table/currency_settings.ini | 8 +- src/table/elrail_data.h | 2 +- src/table/engines.h | 4 +- src/table/gameopt_settings.ini | 14 +- src/table/misc_settings.ini | 62 +- src/table/newgrf_debug_data.h | 231 ++-- src/table/railtypes.h | 18 +- src/table/road_land.h | 29 - src/table/roadtypes.h | 183 +++ src/table/roadveh_movement.h | 66 +- src/table/settings.h.preamble | 42 +- src/table/settings.ini | 189 +-- src/table/sprites.h | 17 +- src/table/station_land.h | 2 +- src/table/win32_settings.ini | 6 +- src/table/window_settings.ini | 6 +- src/tar_type.h | 2 +- src/terraform_cmd.cpp | 8 +- src/terraform_gui.cpp | 55 +- src/terraform_gui.h | 2 +- src/textbuf.cpp | 12 +- src/textbuf_gui.h | 1 + src/textbuf_type.h | 2 +- src/texteff.cpp | 55 +- src/textfile_gui.cpp | 60 +- src/textfile_gui.h | 36 +- src/tgp.cpp | 14 +- src/thread.h | 81 ++ src/tile_cmd.h | 19 +- src/tile_map.cpp | 16 +- src/tile_map.h | 16 +- src/tilearea.cpp | 21 + src/tilearea_type.h | 2 + src/tilehighlight_type.h | 2 + src/tilematrix_type.hpp | 2 +- src/timetable_cmd.cpp | 55 +- src/timetable_gui.cpp | 44 +- src/toolbar_gui.cpp | 404 +++--- src/town.h | 40 +- src/town_cmd.cpp | 453 ++++-- src/town_gui.cpp | 272 ++-- src/town_kdtree.h | 22 + src/town_type.h | 22 +- src/townname.cpp | 12 +- src/townname_func.h | 4 +- src/track_func.h | 6 +- src/track_type.h | 12 +- src/train.h | 17 +- src/train_cmd.cpp | 283 ++-- src/train_gui.cpp | 53 +- src/transparency_gui.cpp | 10 +- src/tree_cmd.cpp | 22 +- src/tree_gui.cpp | 16 +- src/tree_map.h | 6 +- src/tunnel_map.h | 8 +- src/tunnelbridge.h | 13 + src/tunnelbridge_cmd.cpp | 441 +++--- src/vehicle.cpp | 261 ++-- src/vehicle_base.h | 56 +- src/vehicle_cmd.cpp | 176 ++- src/vehicle_func.h | 6 +- src/vehicle_gui.cpp | 335 +++-- src/vehicle_gui.h | 10 +- src/vehicle_gui_base.h | 2 +- src/vehicle_type.h | 12 +- src/vehiclelist.cpp | 34 +- src/vehiclelist.h | 2 +- src/video/allegro_v.cpp | 65 +- src/video/allegro_v.h | 20 +- src/video/cocoa/cocoa_keys.h | 2 +- src/video/cocoa/cocoa_v.h | 20 +- src/video/cocoa/cocoa_v.mm | 20 +- src/video/cocoa/event.mm | 1 + src/video/cocoa/fullscreen.mm | 3 +- src/video/dedicated_v.cpp | 36 +- src/video/dedicated_v.h | 18 +- src/video/null_v.cpp | 4 +- src/video/null_v.h | 18 +- src/video/sdl2_v.cpp | 830 +++++++++++ src/video/sdl2_v.h | 53 + src/video/sdl_v.cpp | 157 +-- src/video/sdl_v.h | 24 +- src/video/video_driver.hpp | 4 +- src/video/win32_v.cpp | 194 ++- src/video/win32_v.h | 26 +- src/viewport.cpp | 840 +++++++---- src/viewport_func.h | 14 +- src/viewport_gui.cpp | 16 +- src/viewport_kdtree.h | 83 ++ src/viewport_sprite_sorter.h | 2 +- src/viewport_sprite_sorter_sse4.cpp | 8 +- src/viewport_type.h | 4 +- src/void_cmd.cpp | 12 +- src/watch_gui.cpp | 10 +- src/watch_gui.h | 2 +- src/water.h | 1 + src/water_cmd.cpp | 83 +- src/water_map.h | 31 +- src/waypoint.cpp | 2 + src/waypoint_base.h | 14 +- src/waypoint_cmd.cpp | 54 +- src/waypoint_gui.cpp | 16 +- src/widget.cpp | 266 ++-- src/widget_type.h | 82 +- src/widgets/autoreplace_widget.h | 4 +- src/widgets/company_widget.h | 2 + src/widgets/dropdown.cpp | 110 +- src/widgets/dropdown_type.h | 41 +- src/widgets/framerate_widget.h | 2 + src/widgets/misc_widget.h | 1 + src/widgets/network_widget.h | 1 + src/widgets/road_widget.h | 3 +- src/widgets/station_widget.h | 1 + src/widgets/toolbar_widget.h | 9 +- src/widgets/town_widget.h | 3 + src/window.cpp | 335 +++-- src/window_gui.h | 38 +- src/zoning_cmd.cpp | 12 +- src/zoom_func.h | 4 - src/zoom_type.h | 14 +- 920 files changed, 26309 insertions(+), 16944 deletions(-) create mode 100644 COMPILING.md create mode 100644 COPYING.md create mode 100644 bin/ai/compat_1.10.nut create mode 100644 docs/admin_network.md create mode 100644 docs/compiling_lang_files.md create mode 100644 docs/desync.md create mode 100644 docs/linkgraph.md create mode 100644 docs/multiplayer.md create mode 100644 media/extra_grf/openttdgui_build_tram.png create mode 100644 media/extra_grf/openttdgui_convert_road.png create mode 100644 media/extra_grf/openttdgui_convert_tram.png create mode 100644 media/extra_grf/tramtracks_bare_depot.png create mode 100644 src/bitmap_type.h create mode 100644 src/core/kdtree.hpp create mode 100644 src/newgrf_roadtype.cpp create mode 100644 src/newgrf_roadtype.h create mode 100644 src/road.h create mode 100644 src/script/api/ai/ai_roadtypelist.hpp.sq create mode 100644 src/script/api/game/game_roadtypelist.hpp.sq create mode 100644 src/script/api/script_roadtypelist.cpp create mode 100644 src/script/api/script_roadtypelist.hpp create mode 100644 src/script/api/template/template_roadtypelist.hpp.sq create mode 100644 src/sound/sdl2_s.cpp create mode 100644 src/station_kdtree.h create mode 100644 src/table/roadtypes.h create mode 100644 src/thread.h create mode 100644 src/town_kdtree.h create mode 100644 src/video/sdl2_v.cpp create mode 100644 src/video/sdl2_v.h create mode 100644 src/viewport_kdtree.h diff --git a/.gitignore b/.gitignore index e30aabe37c..eae0670b62 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,7 @@ src/os/windows/ottdres.rc !/config.lib !*.in *.tmp + +/bin/data/* +/game +/openttd \ No newline at end of file diff --git a/COMPILING.md b/COMPILING.md new file mode 100644 index 0000000000..46de5e09e2 --- /dev/null +++ b/COMPILING.md @@ -0,0 +1,141 @@ +# Compiling OpenTTD + +## Required/optional libraries + +The following libraries are used by OpenTTD for: + +- 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 (Linux only) +- libSDL2: hardware access (video, sound, mouse) (not required for Windows or macOS) + +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. + +## Windows: + +You need Microsoft Visual Studio 2015 Update 3 or newer. + +You can download the free Visual Studio Community Edition from Microsoft at +https://visualstudio.microsoft.com/vs/community/. + +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 download it as [MS Windows Platform SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk). + +Install the SDK by following the instructions as given. + +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` instructions 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: + +- liblzma +- libpng +- lzo +- zlib + +To install both the x64 (64bit) and x86 (32bit) variants (though only one is necessary), you can use: + +```ps +.\vcpkg install liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static zlib:x64-windows-static +.\vcpkg install liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static zlib:x86-windows-static +``` + +Open the relevant project file and it should build automatically. +- 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` + +The OpenTTD wiki may provide additional help with [compiling for Windows](https://wiki.openttd.org/Compiling_on_Windows_using_Microsoft_Visual_C%2B%2B_2015). + +You can also build OpenTTD with MSYS2/MinGW-w64 or Cygwin/MinGW using the Makefile. The OpenTTD wiki may provide additional help with [MSYS2](https://wiki.openttd.org/Compiling_on_Windows_using_MSYS2) + +## Linux, Unix, Solaris: + +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. + +The OpenTTD wiki may provide additional help with: + +- [compiling for Linux and *BSD](https://wiki.openttd.org/Compiling_on_%28GNU/%29Linux_and_*BSD) +- [compiling for Solaris](https://wiki.openttd.org/Compiling_on_Solaris) + + +## 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 --enable-universal`' +instead of '`./configure`'. + +The OpenTTD wiki may provide additional help with [compiling for macOS](https://wiki.openttd.org/Compiling_on_Mac_OS_X). + +## Haiku: + +Use '`make`', but do a '`./configure`' before the first build. + +The OpenTTD wiki may provide additional help with [compiling for Haiku](https://wiki.openttd.org/Compiling_on_Haiku). + +## OS/2: + +A comprehensive GNU build environment is required to build the OS/2 version. + +The OpenTTD wiki may provide additional help with [compiling for OS/2](https://wiki.openttd.org/Compiling_on_OS/2). + +## Supported compilers + +The following compilers are tested with and known to compile OpenTTD: + +- Microsoft Visual C++ (MSVC) 2015, 2017 and 2019. +- GNU Compiler Collection (GCC) 4.8 - 9. +- Clang/LLVM 3.9 - 8 + +The following compilers are known not to compile OpenTTD: + +In general, this is because these old versions do not (fully) support modern +C++11 language features. + +- Microsoft Visual C++ (MSVC) 2013 and earlier. +- GNU Compiler Collection (GCC) 4.7 and earlier. +- Clang/LLVM 3.8 and earlier. + +If any of these, or any other, compilers can compile OpenTTD, let us know. +Pull requests to support more compilers are welcome. + +## 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. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c7ce528c9..40aad630c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,21 +5,26 @@ 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. +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** 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. +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. -* 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 @@ -69,13 +74,15 @@ Example: > 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. +Before opening a feature request, please take a moment to find out whether your idea fits with the [scope and goals](./CONTRIBUTING.md#project-goals) 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. +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. @@ -88,14 +95,18 @@ Many of those ideas etc do have a place on the [forums](https://www.tt-forums.ne 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. +Pull requests should fit with the [goals of the project](./CONTRIBUTING.md#project-goals). -Please adhere to the [coding guidelines](#code-guidelines) used throughout the project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). +**Please do 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. + +Every pull request should have a clear scope, with no unrelated commits. + +[Code style](https://wiki.openttd.org/Coding_style) must be complied with for pull requests to be accepted; this also includes [commit message format](https://wiki.openttd.org/Coding_style#Commit_message). Adhering to the following process is the best way to get your work included in the project: @@ -147,17 +158,8 @@ 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). +**IMPORTANT**: By submitting a pull request or patch, you agree to the [License](#license) and the [Privacy Notice](CONTRIBUTING.md#privacy-notice). -### 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 @@ -165,15 +167,99 @@ Continuous integration (CI) tools monitor pull requests, and help us identify bu 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. +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 +Tip: [commit message format](https://wiki.openttd.org/Coding_style#Commit_message) is a common reason for pull requests to fail validation. -[Code style](https://wiki.openttd.org/Coding_style) must be adhered to for pull requests to be accepted -## License +### Are there any development docs? + +There is no single source for OpenTTD development docs. It's a complex project with a long history, and multiple APIs. + +A good entry point is [Development](https://wiki.openttd.org/Development) on the OpenTTD wiki; this provides links to wiki documentation and other sources. + +The GitHub repo also includes some non-comprehensive documentation in [/docs](./docs). + +You may also want the guide to [compiling OpenTTD](./COMPILING.md). + + +## Project goals + +### What are the goals of the official branch? + +The main goals of the official branch are: + +- Stay faithful to the original gameplay from Transport Tycoon Deluxe +- Improve the user interface +- Allow extending the gameplay with add-ons / mods via supported content APIs +- Provide a (relatively) stable core for both players of the official branch, and for authors of add-ons and maintainers of patchpacks + +In contrast, extending or altering the gameplay of the base game is not encouraged. + +The rationale behind these goals is that people have different opinions about what OpenTTD is and what it should be. +When it comes to gameplay, there are at least these groups of people: + +- *Model railway (mostly singleplayer)*: build "realistic" landscapes, roleplay a world, or even replicate historical scenarios +- *Economical challenge (mostly singleplayer)*: run a business with economical challenges +- *Transport challenge (singleplayer or cooperative multiplayer)*: build efficient track layouts with high cargo throughput and tons of vehicles +- *Competitive speed run (competitive multiplayer)*: maximize some goal in some limited amount of time + +When it comes to gameplay features there are at least these groups of interests: + +- *Control freak:* micromanagement like conditional orders, refitting and loading etc. +- *Casual:* automatisation like cargodist, path based signalling etc. + +To please everyone, the official branch tries to stay close to the original gameplay; after all, that is what everyone brought here. +The preferred method to alter and extent the gameplay is via add-ons like NewGRF and GameScripts. + +For a long time, the official branch was also open to features which could be enabled/disabled, but the corner-cases that came with some configurations have rendered some parts of the code very complicated. +Today, new features have to work with all the already existing features, which is not only challenging in corner cases, but also requires spending considerable more work than just "making it work in the game mode that I play". + +The preferred method to introduce new gameplay features is to extend the content APIs, supporting ever more add-on content / mods. + +This moves conflict-solving away from the codebase to content authors / players. +It is more accepted for add-ons not working together than the base game not working with certain setting combinations. + +In general the game should allow anything that doesn't violate basic rules, but it should warn players if they take potentially dangerous or "stupid" actions. + +For example, players are not prevented from starting vehicles without orders, but will receive a warning about vehicles having too few orders. +This lack of limitation has led to players challenging themselves to create networks where all vehicles have no orders, increasing gameplay possibilities. + +### I do not agree with the goals of the official branch, what can I do instead? + +Fork! There is a rich history of experimental patches for OpenTTD. + +Many of these will never be accepted for core, but are creative and interesting ways to modify OpenTTD. + +Sometimes patches are combined into long-running patchpacks, modified OpenTTD versions which can be downloaded by anyone, or modified OpenTTD clients for dedicated multiplayer servers. + +One of the reasons to keep core relatively stable is to make life easier for patch authors and patchpack maintainers where possible. + +Patchpack discussions and related topics may be found in community sites such as [TT-Forums development section](https://www.tt-forums.net/viewforum.php?f=33). + + +## Legal stuff + +### License + +By contributing your code, you agree to license your contribution under the [GPL v2](https://github.com/OpenTTD/OpenTTD/blob/master/COPYING.md). + + +### 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. -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 diff --git a/COPYING.md b/COPYING.md new file mode 100644 index 0000000000..2c2818d14c --- /dev/null +++ b/COPYING.md @@ -0,0 +1,339 @@ +This is the license which applies to OpenTTD with the exception of some +3rd party modules. See [./README.md](./README.md) for details + +GNU General Public License +========================== + +_Version 2, June 1991_ +_Copyright © 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. + +### 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 index 251b36be15..5677118c54 100644 --- a/Doxyfile +++ b/Doxyfile @@ -289,16 +289,15 @@ EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = ENABLE_NETWORK \ - WITH_ZLIB \ +PREDEFINED = WITH_ZLIB \ WITH_LZO \ - WITH_LZMA \ + WITH_LIBLZMA \ WITH_SDL \ WITH_PNG \ WITH_FONTCONFIG \ WITH_FREETYPE \ - WITH_ICU_SORT \ - WITH_ICU_LAYOUT \ + WITH_ICU_I18N \ + WITH_ICU_LX \ UNICODE \ _UNICODE \ _GNU_SOURCE \ diff --git a/Makefile.bundle.in b/Makefile.bundle.in index eaf7134dde..163f545ffb 100644 --- a/Makefile.bundle.in +++ b/Makefile.bundle.in @@ -69,10 +69,10 @@ endif $(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)/README.md" "$(BUNDLE_DIR)/" + $(Q)cp "$(ROOT_DIR)/COPYING.md" "$(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)/docs/multiplayer.md" "$(BUNDLE_DIR)/docs/" $(Q)cp "$(ROOT_DIR)/changelog.txt" "$(BUNDLE_DIR)/" ifdef MAN_DIR $(Q)mkdir -p "$(BUNDLE_DIR)/man/" @@ -88,13 +88,7 @@ ifdef MENU_DIR $(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 + $(Q)unix2dos "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/README.md" "$(BUNDLE_DIR)/COPYING.md" "$(BUNDLE_DIR)/changelog.txt" "$(BUNDLE_DIR)/known-bugs.txt" endif ### Packing the current bundle into several compressed file formats ### @@ -159,7 +153,7 @@ bundle_dmg: bundle 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)unix2dos "$(ROOT_DIR)/docs/"* "$(ROOT_DIR)/README.md" "$(ROOT_DIR)/COPYING.md" "$(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" @@ -196,7 +190,7 @@ ifndef DO_NOT_INSTALL_CHANGELOG endif ifndef DO_NOT_INSTALL_LICENSE $(Q)install -d "$(INSTALL_DOC_DIR)" - $(Q)install -m 644 "$(BUNDLE_DIR)/COPYING" "$(INSTALL_DOC_DIR)" + $(Q)install -m 644 "$(BUNDLE_DIR)/COPYING.md" "$(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 diff --git a/Makefile.in b/Makefile.in index d33d8a0d2a..17636f7958 100644 --- a/Makefile.in +++ b/Makefile.in @@ -50,7 +50,7 @@ RES := $(shell if [ ! -f $(CONFIG_CACHE_SOURCE_LIST) ] || [ -n "`cmp $(CONFIG_CA 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 + @if [ -z "`echo '$(MFLAGS)' | grep '\-j'`" ]; then echo; echo "WARNING: you enabled distcc support, but you don't seem to be using the -jN parameter"; echo; fi endif @for dir in $(DIRS); do \ $(MAKE) -C $$dir all || exit 1; \ diff --git a/Makefile.src.in b/Makefile.src.in index 6b235be9d3..3a4db6c171 100644 --- a/Makefile.src.in +++ b/Makefile.src.in @@ -139,7 +139,7 @@ $(OBJS_CPP:%.o=%.d): %.d: $(SRC_DIR)/%.cpp $(FILE_DEP) $(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):@' > $@ + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -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)' @@ -249,7 +249,7 @@ $(filter %sse4.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP) $(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP) $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)' - $(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $< + $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -o $@ $< $(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP) $(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)' @@ -270,10 +270,6 @@ $(TTD): $(OBJS) $(CONFIG_CACHE_LINKER) 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 diff --git a/README.md b/README.md index e621dc0215..c59ebbca59 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ ## Table of contents - 1.0) [About](#10-about) + - 1.1) [Compiling OpenTTD](#11-compiling-openttd) + - 1.2) [Contributing to OpenTTD](#12-contributing-to-openttd) - 2.0) [Contacting](#20-contacting) - 2.1) [Reporting bugs](#21-reporting-bugs) - 2.2) [Reporting desyncs](#22-reporting-desyncs) @@ -16,15 +18,11 @@ - 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) +- 7.0) [Translating](#70-translating) + - 7.1) [Translation](#71-translation) + - 7.2) [Previewing](#72-previewing) +- 8.0) [Troubleshooting](#80-troubleshooting) +- 9.0) [Licensing](#90-licensing) - X.X) [Credits](#xx-credits) ## 1.0) About @@ -37,6 +35,14 @@ 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. +## 1.1) Compiling OpenTTD + +Instructions for compiling OpenTTD can be found in [./COMPILING.md](COMPILING.md) + +## 1.2) Contributing to OpenTTD + +We welcome contributors to OpenTTD. More information for contributors can be found in [./CONTRIBUTING.md](CONTRIBUTING.md) + ## 2.0) Contacting The easiest way to contact the OpenTTD team is by submitting bug reports or @@ -152,12 +158,10 @@ 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) +- Haiku (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) @@ -513,136 +517,7 @@ 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 +## 7.0) Translating See https://www.openttd.org/development for up-to-date information. @@ -657,7 +532,7 @@ 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 +### 7.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 @@ -675,7 +550,7 @@ Note: Do not alter the following parts of the file: - Lines beginning with ## (such as ##id), other than the first two lines of the file -### 8.2) Previewing +### 7.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 @@ -695,7 +570,7 @@ should also be. That is all! You should now be able to select the language in the game options. -## 9.0) Troubleshooting +## 8.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. @@ -740,10 +615,10 @@ 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 +## 9.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 +the complete license text, see the file 'COPYING.md'. This license applies to all files in this distribution, except as noted below. The squirrel implementation in src/3rdparty/squirrel is licensed under @@ -760,16 +635,6 @@ 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 @@ -786,6 +651,7 @@ terms for Bootstrap documentation. - 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) +- Charles Pigott (LordAro) - General / Correctness police (since 1.9) - 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) diff --git a/azure-pipelines-ci.yml b/azure-pipelines-ci.yml index 19c185894c..43448f345c 100644 --- a/azure-pipelines-ci.yml +++ b/azure-pipelines-ci.yml @@ -25,6 +25,7 @@ jobs: - template: azure-pipelines/templates/windows-build.yml parameters: BuildPlatform: $(BuildPlatform) + BuildConfiguration: Debug - script: | call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 cd projects @@ -40,8 +41,8 @@ jobs: matrix: commit-checker: Tag: 'commit-checker' - linux-amd64-clang-3.8: - Tag: 'linux-amd64-clang-3.8' + linux-amd64-clang-3.9: + Tag: 'linux-amd64-clang-3.9' linux-amd64-gcc-6: Tag: 'linux-amd64-gcc-6' linux-i386-gcc-6: diff --git a/azure-pipelines/templates/release.yml b/azure-pipelines/templates/release.yml index a1438c4a58..00e5b1040a 100644 --- a/azure-pipelines/templates/release.yml +++ b/azure-pipelines/templates/release.yml @@ -88,6 +88,7 @@ jobs: - template: windows-build.yml parameters: BuildPlatform: $(BuildPlatform) + BuildConfiguration: Release - bash: | set -ex make -f Makefile.msvc bundle_pdb bundle_zip PLATFORM=$(BundlePlatform) BUNDLE_NAME=openttd-$(Build.BuildNumber)-windows-$(BundlePlatform) @@ -118,14 +119,14 @@ jobs: 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' + linux-debian-buster-i386-gcc: + Tag: 'linux-debian-buster-i386-gcc' + linux-debian-buster-amd64-gcc: + Tag: 'linux-debian-buster-amd64-gcc' steps: - template: release-fetch-source.yml diff --git a/azure-pipelines/templates/windows-build.yml b/azure-pipelines/templates/windows-build.yml index 5e12f2243f..117dd062c1 100644 --- a/azure-pipelines/templates/windows-build.yml +++ b/azure-pipelines/templates/windows-build.yml @@ -7,5 +7,5 @@ steps: inputs: solution: 'projects/openttd_vs141.sln' platform: ${{ parameters.BuildPlatform }} - configuration: Release + configuration: ${{ parameters.BuildConfiguration }} maximumCpuCount: true diff --git a/bin/ai/compat_1.10.nut b/bin/ai/compat_1.10.nut new file mode 100644 index 0000000000..fe985b90d0 --- /dev/null +++ b/bin/ai/compat_1.10.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/compat_1.9.nut b/bin/ai/compat_1.9.nut index fe985b90d0..6dae3ebc0b 100644 --- a/bin/ai/compat_1.9.nut +++ b/bin/ai/compat_1.9.nut @@ -6,3 +6,5 @@ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU 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.9 API compatibility in effect."); diff --git a/bin/ai/regression/completeness.sh b/bin/ai/regression/completeness.sh index 9f5e96eb0b..2e42401550 100755 --- a/bin/ai/regression/completeness.sh +++ b/bin/ai/regression/completeness.sh @@ -46,9 +46,9 @@ cat ai/regression/tst_*/main.nut | tr ';' '\n' | awk ' } } } - # 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 + # We want to remove everything before the FIRST occurrence of AI. + # If we do not remove any other occurrences of AI from the string + # we will remove everything before the LAST occurrence of AI, so # do some little magic to make it work the way we want. sub("AI", "AXXXXY") gsub("AI", "AXXXXX") diff --git a/bin/ai/regression/regression_info.nut b/bin/ai/regression/regression_info.nut index 341d13a085..d5c3f7dd29 100644 --- a/bin/ai/regression/regression_info.nut +++ b/bin/ai/regression/regression_info.nut @@ -6,7 +6,7 @@ class Regression extends AIInfo { 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 GetAPIVersion() { return "1.10"; } function GetDate() { return "2007-03-18"; } function CreateInstance() { return "Regression"; } } diff --git a/bin/ai/regression/tst_regression/main.nut b/bin/ai/regression/tst_regression/main.nut index 7315f33f82..baece09d08 100644 --- a/bin/ai/regression/tst_regression/main.nut +++ b/bin/ai/regression/tst_regression/main.nut @@ -1704,6 +1704,19 @@ function Regression::Vehicle() print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 3)); print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 3)); + print(" --Refit--"); + print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28479, 211, 255)); + print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28479, 211, 0)); + print(" GetBuildWithRefitCapacity(): " + AIVehicle.GetBuildWithRefitCapacity(28479, 211, 9)); + print(" BuildVehicleWithRefit(): " + AIVehicle.BuildVehicleWithRefit(28479, 211, 9)); + print(" GetCapacity(): " + AIVehicle.GetCapacity(20, 9)); + print(" GetCapacity(): " + AIVehicle.GetCapacity(20, 5)); + print(" GetRefitCapacity(): " + AIVehicle.GetRefitCapacity(20, 5)); + print(" RefitVehicle(): " + AIVehicle.RefitVehicle(20, 5)); + print(" GetCapacity(): " + AIVehicle.GetCapacity(20, 9)); + print(" GetCapacity(): " + AIVehicle.GetCapacity(20, 5)); + print(" SellVehicle(): " + AIVehicle.SellVehicle(20)); + print(" --Errors--"); print(" RefitVehicle(): " + AIVehicle.RefitVehicle(12, 0)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); diff --git a/bin/ai/regression/tst_regression/result.txt b/bin/ai/regression/tst_regression/result.txt index e93b2e2343..18ae14cb7a 100644 --- a/bin/ai/regression/tst_regression/result.txt +++ b/bin/ai/regression/tst_regression/result.txt @@ -8534,9 +8534,8 @@ ERROR: IsEnd() is invalid as Begin() is never called 19693 => 8 --TileList_IndustryProducing-- - Count(): 92 + Count(): 90 Location ListDump: - 46920 => 1 46919 => 1 46918 => 1 46917 => 1 @@ -8545,7 +8544,6 @@ ERROR: IsEnd() is invalid as Begin() is never called 46914 => 1 46913 => 1 46912 => 1 - 46911 => 1 46664 => 1 46663 => 1 46662 => 1 @@ -9128,6 +9126,18 @@ ERROR: IsEnd() is invalid as Begin() is never called GetWagonAge(): 0 GetWagonEngineType(): 65535 GetWagonAge(): -1 + --Refit-- + GetBuildWithRefitCapacity(): -1 + GetBuildWithRefitCapacity(): 0 + GetBuildWithRefitCapacity(): 160 + BuildVehicleWithRefit(): 20 + GetCapacity(): 160 + GetCapacity(): 0 + GetRefitCapacity(): 160 + RefitVehicle(): true + GetCapacity(): 0 + GetCapacity(): 160 + SellVehicle(): true --Errors-- RefitVehicle(): false GetLastErrorString(): ERR_VEHICLE_NOT_IN_DEPOT @@ -9175,7 +9185,7 @@ ERROR: IsEnd() is invalid as Begin() is never called 13 => 5489 12 => 5489 CurrentSpeed ListDump: - 12 => 21 + 12 => 27 17 => 0 16 => 0 14 => 0 diff --git a/bin/baseset/openttd.grf b/bin/baseset/openttd.grf index ea5f55ce1dcb859d86f74620b4869a07158a1f9a..111004c175ba03f894e0b8f3a2bf67b29df4d524 100644 GIT binary patch delta 1442 zcmex)Rc`Jic@`Fi|2G<0T3HxdS(sW`n76X9NU1QEZUPT)JZv^LUf!MN zFGM*!Y&<-?e7a3>I*(-{E8}U9BgE>x83Gu>84?(>87dfB8745yWLUtklwmo;N`}=8 zYZ=xvY-HHXu$5su!%l|X40{>&GaQ7t?gfWPBLh=2gN+SSD?@d)hYeFZgSVI015UP1 z1|KhPuNxw)-3&h7-YNZjCM_V)I9A;akLK=p+_lehN^ZpQW-sxL&CS{cM{2rxA> zyinMXzM*hKbq7DAgB`=6|L3P0USt#A?oi6oDX=~EI7|3+#vR+Y#<8YMt)IcjC?diD z0&ENn42+D7FPJZ|F)=c}5PTra!OYCf%*?{d@`9a-iRp$Y6C=|DUM3dS8zPL%Cqx*T zFNiR*+>mBuUZ8Qo=70tZ6Du><1)CS_8*Cnkys&v8eZYp1`GLlR3T7^5)&mtcL^^Dk znVC5+RJ>rnu=T-$7a|X~FmihDSis15L-E0u7y27cY_Qo-!N`7L%M11mDKA7Gd|+m0 zW}Tt&-~%K3f)qx!3m;yv?_^Sh@K)Sy>N= zayi^b%u;xFu(9c@@&h%ho-5M^g)WoKizaa|$I#K!)> zo`sFohW$nU37ZH0jI1x1A4EI|xKP2&!ou=`S@8n*i+~#on3tIc+XR`r2c17aGPmH{eIN(lhypgy`h>4H?g&YUm z-HRA)RvB^e^TFM&$O3Zv3I|qRko#X|GPAL=-f(&$&&a$&fsyxu0wenk{g zao~a?%nvu@7d&9(yO8kkOwxXFlo zj58V@b3Al-ne;N1iJ9ev-0Ps-MYlR0CSA@y!LdT&h0cxLHx69jVrFOO+`Z|A_k~#( z7F<~NLJ@n!aB{Q3BZixkg_#o^G3+)BjBIRdY!Advh%!6ca6eFEXJ=z$=j3L&p~dEC z!@|bM_`-sb`-Lbo8#mhvdp1WKHcoEF7q(2?EH6?Rxo?QF*l@EkzYu<419G4v8#^bv z4IBH5LS{xr<_msSjNA`c9z-*;y-0cC^`eJ`n}wPA!Q=xV`ChDj@Bre==MTC&8bH2m0QvGc3o{Eh zI5uA>F|vW;^F<6J<72eweCYVl^#BJW`-_u1AF#5sgVXi}HkJ!KFBID)zp!qX{KEEN F8vsI&&QSmW delta 59 zcmbO`N&e?mITjX%|7ROnT3HxdS(sW`n76X9NU1OuZkJbKv0J?T?md?9>5QAVo0hSr QOl`LnV%u&j#QtC#09<(#cmMzZ diff --git a/bin/baseset/opntitle.dat b/bin/baseset/opntitle.dat index 8fef09fee89303e82f75096b6a3a23664439bdc9..264aaff60b5e58cad978bd390ad459da6cc06808 100644 GIT binary patch literal 138710 zcmeYd35jB0VPvS7^JZ`MWSN_lYSXT-I<@B18K=j6k_@~FZ7L3YFC`0hC^5BW$I{$m+z3)#> zuF7HvY58;1hoSe~t6fiu&sFcA`}y1Vf2AVs7gyhp+rQT>{Pr>3{~xPPPd{4NBOd#& z``(?~F%$23?y0nX_i+1;-C{2uCo+C`EFItB|EA2=@ZUlHx(nO%|1A}B%fDt9QP=f# z-QDfUfATlau8F-}<~gaPO7-OIcmG;z=2buX|NKY%4YkTYyV4`32qxHkICeYZ=PnD+ z>hg!)_sjFEBDJ~IxJC2tDtvVRFZ5&TiIdg;+-?c}=bJCxUw^08)y+n>%>L!CoUONd z?Gw6B9DE-fxkg2Q0Qx_J=Qy#zsynQ|xv9B;9V`C%V5n;j#0_M;7diL)lk}zdiq^(Y)AU0t zj>o=_2-moD_u_$_7iWL7|90W;bc-_Y8Q(ImSM7Y1|D`p0j`u!&28+sxJ6Hv{DiVD} zVy3s1)v!-rYnyvq)^f+Ddi@ZU!sSz+KaO~L?`~q#+rE$7lVdmWDb|GsME_v^*Wvl` zTjGyLaxWY0|82b3zIIyl>>sUnLl2pHY`(YmA8Y>E_iG>aiyU~tH7#?8?PW*48>_|b zr=5TM!O?U1t+TbBhfeQs_;&D~-;;^r9&anYmpxQ}{9vt~CbQK}=85%;-UWe z_0@WRV6>FM4#7LqcON+T>6+~hjvu~qAI|rCO3G&TzFzZx#~K9WVzIT)MRovDa zZ!Yk|F-9aS)}}y7Wwma@{rWnoX-5v5-^&aQZwWED#y|bn%R|M7e#cxCaX2gS;>%hV z&(qOY*81E0lPEYOdhp-t+dW?jWFG97dEEbWr9#Q~*$oW2>;Gy6-#c;mSK$JtBIfVM zqm4K%)o&5xh6tbe;} zO15VA-}xHVw$uCd`enn9%ocIGckjP*yTkgU$l#zt8g7ExsM`tK`QMmkr-PsTS8id97u@-Euv8!;;Ceal2<&G}?+f^Y4&;AN>7M zoY*1ZDU&AOcR9Z+q;B^&ds&O5&yS9un!O?<*vx0ela(*q|Elldi(hx6{%6=WTUExC zm=?Q&42PRa!WwyOLX&UT3a(xvtbJf_+1r0#_Zok$QdQmao#T9ka#H>LBl@>oS`X>{ zi7`tLerUO4Zr+w_2?zXG>#~2(7pQ;!)VE{)_O9T@+%`^yU8dZU4LWU!9$0{&4%D9_5GDhvZv72upccf3z+;_S<#h+Aj`VU!0x) zG(YqIn!jCAa`EJQZ9nW={*{-g{@Ne!`0?cO$xI5rt8^NEu`m8B|F$maU1NuR$7#m* zZ3oTo)xYp&@M8YupZotUYuvx1T=9Pj{+k)*Y&mjGKzl|HXa5i8tJjY;#Yc24>wEA< zSg+yT@2;c+wLw-H2WC84&&w-+XVT4#qSuQ5f8Q3!gqvSR7`$x?q$O6R^%+N}O~=y}N{Y>Y*#qC4#y!rl{{4U!UPhTYWA^G+j$vQ^2AEk_E_H0`3Wfl8e zdEv4StN(Ru_7M#!%>O^k=KFo0b+zfC`8{zry<`*vOQ$_`$~YqWZvUevX>ShQ&t!3q zP~cp5_QZ!5|6blIvhC4zu`PMY6|ETP{_;pYF>7HO)jJ@#X<@1GltN6-KL z{>RqAGx3&0x%MB!I@4KaY;J9{<2~?Hd+%wNw?0+hbdzK~R~Kzq-W59S#iScOMf?)> zGxDwO)dvJi+w5EU(`16ucg1J8m2sS)b?g!cdP*VEk4~~bwacqBY6VYxa zz;Zxyj{?8-J}H;`4feuE=f0TLew|~#(1v%--(N+)v(71Sv%WO-(_Re`qw4}u4Vrq~ z8eu2+{v?H~D*suV+j3uqMQ@VbS0VOtyBzfg>1BapFV4SIcw}3*G2-f)`vnt^Uu65M zIwvHwIgR(&p6z^nO^a2HY;(?>J1+XCuH#Va+=S|Ts)tp3mI^6*hNf!Qy?Vh?xX-0m z?BP8-k*Hk^k$K^4O&?YZUOKuV?#lVMZXtQfw}g(n9pq8t7-sF_#n06q3&+{W+6(4ccf{*Tsy`$oT%%(-THd6sqFvZ|Z;g^hLpZocIQ>@7FkRWIkw&wUr< zb;;=Ga>qx!f37Soc@cht>yDL9y_UuIfHN7K`IrA3*vFs1S-h^YbL|tA0*yIlAAYai z`k^%aQp?AyM?PfRNVDy@{O!~~;oCKb`0txdu~eJAM~>-_;lGyc@78Voz59^u8k4vy z(J@P0S@`cfT&%exws}RqQgx9*q_f@{_J>p0W_3xkez$pRI;++6+qP|wB78UFTZYOmgQ$!V7}73-IA~T|J4U>H`eZ+9pAj-`VWrC-aZvC#|vuDxYtN9L@m{N zB=Wy;vX7sQZ$ZDXuwQfxgJOfV&n@weRu7LOu^fF8t9ixO27Yo(Te3^-ulB!l|8KqD zduN&MLiMk{ufDI=+RnFAYx*6FZGw+ZESLCUAEWU2??JuN{GtMj$*&8HVty`I-n}{_VMv|-)C|jGk;jV{oRpQ7pEk(PT49Xe5pp^ ztB4CvOQEQ8(8O>NzjsD*rZ?ZLdw%}-y`A?Kd))}1^-Mx1cwOVeZy(s3FCCf$L^6}H0m-+39vOVD{yI#WeMZ--W z#ZcC{ZqGVwAMU>KbY=Wc<)1G;K5keTY`W0q-?jD5HeJ1aO)nO+2K?c&zi3hC@PDO8 z2j@J&9}dz#9(I*X(u!Qo6`{>&@L+D0vxJ@G|L&RQ3-5mVvAEx7F1wh+zQ+4&FT2NC zG4HSb%_GP-`S+Iny9+Ny?iLK@5>I&gG;38}wTzYPOoOkCVhR_(a|q?V`oLJH9oH_k zSu6bRzw{eQp?^0$HMnaXapjPJ(B)UV`Wx=+H|W~FJjt!zoyzkgT&zEJn)6#Zsl&>D zq^`@yAFyweul|!ZWz9AA;Ds;myy?&m;uD(VUc}xQs~$e}Z|eW*T?Y+=8f6b_=4Mx} zSXW&0*TUe%o+pgjYkVzwbtl^eT<#R=y(JaX!}z~@n{;bQxukhkUT~0#g=)7V zO3z8uuU;?Uox-}-{j+-POhNT8_se~bP55WZen)kc(A{!*+puoAi~8DZ%Kx^$^_RJ0 zQzP50dgMe+t~Ym;AIyqIG)Hz456v3~1- zWUi3)-HkcVy97<5><%%n4RhT(H}c)4{~Ui6mCOnnb}XM~bM?%mYSZ-ahu*VJSzlhY z<*OU(KBwWJ3Um2&)53b)? z{BDlGl@fX0qNs!@g{xUl)C13RCu#yn?pje)I|ot<9V<-@W+lB4w}PIli=$Fjd_t3l!4 zZA)%QDG45&UY41)&hb)USJ|w!&&$?rx{_b{;s~Ef_M`S6EBz%?Lp?=Td$S&pG#Bww zEzneu+0FQu;lAzdhx0j^J6v}$|7W=WP(Nj1U&6mjyk};-7B$yX*yUm_blatt_5B5% z6gPbbv&6h2^Sb04ajj1J(z~P{mRGNsvGP3M(Oo8M=cjA0^^y$UA2hGIKZ27d==hD@ zA1;3?{L$Zk`qL5Jh7%1_mx_jIUtYE|ugN@qfpmxY+nP^Dlsp6`-hXDgB-1vTO>U*X z4(G!i{ADrs_?CO$Q~f57(ahia$qMViu&{e9KG{VksO ziLvgxW^-WfZ_OXoZ|c`G6$jLBW4L3SWh&rrmJ)AUx3zliG=_hdJ|4(FX8CMCr<(j`&I5vHVSys9EbnYK^;l#S*|J0W+{r!ri?UDPwczc#*DG6SNYgZM` zeW1y-fnky^$A|c;xZB*NX79tk%`g(as=M-$`Lh_sXRJ>1o`}VtQrYrKpy`xDeeUt3 z6(x_AR6hwnexdcp_~GBlmp50wd|+MuFhTcUh)~ORBVPU$npbD9Q~r1DxW|;wsy3sW5`4*0B8IdDHqH|Nr-xeCXE01 zu+Jwqd4Jft(xUzE`;Gtk_OpnFhBiF4)|<=nB|5r+VgF4<+ih}%OT!m_Z@v?*Zl?5M z`tt5qi=yVtlaW7rgyV&(pdpJ+!~f-d)_f;fWWCQY|CuE7(xgMZNjm$-bgFxqkMS`}_I+FMV>Ob*Id~qJ0t{tbfHXRXW0;z*sY@ zFI=}+_B(~pX_8mh)>CKb0Pxc+WBW_l(gh#@9e z%*tY>!j74f-6yb3DHi?rZQawuDM97GPI1tu^4@zFS}8 zOGIburPKOX1q3G?+9dtMcxwInqwhJQPwdaT^G`qL|H4~W?WGS{Hfv55IJR`zgtM=j zrEh#n=TNWw+k58W|I;ErYGD>;8@6z;>yyX|bIDO4EMpPnrKIQ0!Zv zSR1FB`!;R0!1V|ESFvrZJ^4@nb;CdFlHkfehnJpH*Eq0h-rcpw<{Bj}kDJ)i`O)NH zy)a+T;d**MA z-bLr^-^991&6w5k{_1PDh0{Onk&O7md9mC4fj&=tsn~^j>EEmpEM4Zy9z{$yHA+ie zm}t&&!dmr^&HOuU?9<}-zsau_|6u>&z>HgcHx za;YmNCr;n9?uh>{{nY=`jq;c3vvnTWR%BXEcyFgtqwBKeL+$ZN2Gi!OnydESe(t$< zVkWEqebNus6$*Z4xH0p{Tm`Z2RbQv5K3)~EJ52fAu82=!^0xmvw5~s2azfVm-XE?9 z%D?8fJ?mfmU-E5ybcLu|BFDeO?(c-yHZXN)(rh|_feI<%BF&td)AtMI~cARKl&KGhxd?H-r9fe zVqQ=7vdKof#Y8Vn4>MZ8u{ybS+RKis9Q87pF&XNL3IEka82T7k?B3r0dMZhXt$quG zeBR^l)%tpKo=mzDT7K-RXXLd1yN`sGqzXSid0)A%G*egdlvlKig6jW8fAw_jlUB?Z z*YiG*8Nu+iY))#*(tyWvF6R9aVd!J@+Eu@N-akp31~1dU<|5mU_Gd`u3o!65{{Q(SuPZ-zKiRwT+4i0PWiRVmX1(;h^H=Ng73S>sl5r1}cz!5;JYv_> zkz-x_%}D>>K-x_Wm(P_BUdEoNTIZx^nOvSW61)Ie&lzwOaW4}R-smf=Pubq=k zrCOrs_jBL#jQwz!@4^Y-uA{pMQy9tZbc9q~JSx+kP_ zwBysRs?TnmpYZ?b-_~k z8RNW;{cB{#X1`Aov&zF;|(-tWx+ZiG1-tNAM;nOkZ zx|L!7zBR;a-9O6CTKD6FuGe`JL55$;0}_~y{Z;Ut^&?D&HS~8<=69dftRFnLtPgDM z%Q7llvv6r&A?H``-i5n%v1=H7Ne%mUEkQShQTC7f{cBGr%;4`iB6|P*3JarMySl&6 zOZq?AyYidzeUlDb0Y`Ud{e>UiYc^f(Q{DWGG2)DaR{JiMm!{#Djhh{QoMLo7dNmiF;NQx=2KI$Nku+cauAB z%de^b;hfpT^)Y@DYuMgOGoj+kXJ%Kj6sG^J-f%j@$mnuQ&w{7g8IpYW^q2m~{?PsZ zwTjV`uWvYJw2BHAZs}Pedb5>V;CIu%BZ>dNDaZByKQ!_3@t?m>Sd03-KI@$xY4zpl z$JmK=lfUn;`ui*X-_iO5Uo!-rcA7=1Zd*80isjy1mEaA3{cN40j%ViYGv?B&lJ`E! ztP}J)(s6t7f7f4@dlDLE=6rwX;!=1l#iIMonp+m~VhyvFD%ZLFe8G6~^1c5*9{2D6 zwmvQX|1O<_ohzn1Ui_c8QuN?^o0ikOy)0%a#XL*xuPev~MX!Bc?5}G3TEJ7;R{3zr z;#}1&&rO%6-E57I;k{We#i;S`(7(+REbHU4H6tGUTK)O-y)H(3-v6Qh?DxH2cfR%? zxBq-Q-8)=o<~kRa{E%O|?#<)xGIcK<_VcXT&@kVM-|^@xE?WziaCYMb7FI3N}K@zGVU;C1Yi6}}xjqn9lp zbX5Mbee6^D{qO%-?0)~+Rq==GVn6tD-W z2JNZ!I(=DZ_j^o(BYscfYhjt#CjD^wEEC25`;}^bzJBok>+kn}KiKY^_o3=f;_tWjx!*nhv?+C` z?Z??($@c}7<@bKvKfO<5|MdkGr^J6gkXWoz>t?+w-7E9@Kkbw2*1Yh{ircs*$nt2) z?2sd!!r>MlU(^+Ouln|&CG!QtewXYP2D^V1wvGXjCJu(h-oLKO@B1EFZd+gU_t)g- z=jH3SnD%&-L`^by)VkNF_DOf4fpV^H$Rq>HkDjwz|9REsEfvyz5Wu-Xn~i0o(!a7* z^Jgh9o+r;DE~2nXxuq{qX5q#Mnx8+MR5s?Y)<_LG-|??FEMDJ@UOq_Az9b|mGf-sx_0$!+o|T~ zZEDS($=rs$X+OGO321+sD;m>qym9B;MU#qJ-`ZQwoi4zb6#UOLY~B8MAGrVK-|uRZ zR%LYBWyYE^dqr2Q%GZz&%2q3G&YvfHYt_FX6N3ydL8FGJn%3X%SN*>Bnsc??(J$&z zSD0lVac4K*ELGywC=yi_f6&?LHgQ_&mvrBM^Sc=Xx*q<&zG6-Jt^eQW+gJYkVI*Pq zICA6L8!5VrY>nTnI%xc+{Fd=NGwYE0PL171K6_m%JzTy?W~N!;5uWBP(m#^9BT`>& z@D1c~41cggVDVOqvZ_KUosQy{g_`-#-=~IUUQjN*?r6T^k3N^hzRUkRqRVdifAE$) z_EfCy%e0IsSG5x^m1MCQ&Mi%JxfZvihgDgiL2d4l^-NyRGu&4uD}GDe-DvN2Ey!kr z<_B5dtwLNlpZ@#2;G+x!@k~zj6Mr`HtbS{f&6zyq zy}^vW1?L|+U(8~h9sPH|lY-Tk50TH7b8y&HtK}7H`mMSAG)N=pT&3;~hWVFo$wW5D z-QKRArh4NDr|)u$<&&FlFJh7TXHxike=?)MxuPX+KE7r;a3xXWRGGYi`ByPBJnXycM)(xSOxu&U?`C0#6 zTlCSh|I);%Q-W_kTfQRlPJ+!z%jX^SQ#LWZ+kbiU=g*&4t-2GwoheB2aoCaA?xQPh zRFCL$e_-u$)?lAz_`Y=Rw@lyVe$i|HYn{*UJjYb`XJ?(Ps$a99i1EMmU+#NteO-Lw z%9&-;6}astMzMMaRNQXeshoSG$26j^P`dVi%&C`b@`jz}AF^2rx_DO)p&qB>8V^!M<-pSoWHX|kn4?i@6P>Nu=8oLC?0@Xc?j8QQiN7~# zm&2)l5AxHTW>43T-&OA$e0`FjP3)ZAtUC|zKV|!O^pE6{hn$C_ckY;6&B>JAA+t;0 z{7F$>%Z2?7ziQK&Y|HB!uK0emyCBzp>*m6wPdn3NIuoS6`}415*wDUvBHz!zN^X&q z%>u%Y&8)r`2I(0+;4j;sDslOF18dU}?Uer;S&BS^7%f3tg`K%BCneGKRQ-ES-Y9l6usx4f@Z$|9$Bf3VWrD<;Vjk5%f}Qq|dmU;K|N zK9XCId8n(D`LDrN=ZF1Tink)dz4q9926NQ4td@OVeE9DE&#c9Vw@Eyh^t0i=cYM=^ zn2cu;Dw7}7FJ*my&!j}!?@!Rf_P@(tyt`84u9JA+{L1MaUsdGngS<8bd=AamEOKiz zRN9bw*(Ry6XDbo33kUzVOpTZ` z|E%eu?!WD2M;&^yudjRi_U+%JrFTmY{y#F4F-|9Yk;&GG_V215S7zOPQJpW6WjbZa zuC0+bCoz9n)KZafY581Mo=ZL~ZuWglTUKdaRCoI05$E+U;R%z&3zj~+x|ixg9qym z{FnaFIREJ6&CY9O12*28rk?WDny-z)kCUpZ zUVV>Y3kYaxvI|(*`pW0|(p@YyzbE{^`dv`}eB@U3Nx$X?@=KjhKEF~>YB}GzME(OT zJX0Dj?vH4WvR)#&TYQ#?(8G5#9#~~f3;RE7y2)GBGfNZa2UsoLSK_qKK+MqU+r-!< z+`F%YNnI_aXdC|4D!M@A=1CuNijW&zd072Oq3|^lsSy&i>6q zf&We{j!TbjzEiK;ZuY1C*YbKT^Txd=*#6Y*Yq%CA^*uRCA$7W2wZ(}}PB|%-SKntm zxXw0Z-edf%+(=la04B1CJbI zabn!`zvnI6595?Ql8^dZ!+c~;l|Q<)#CBFO--VuO-yFYKn@+y=Y2T`6Hv?WjWmP(q zc|G&KR-WpS`{cy|7R#n=9;gfkuh_vSfA489@e1EA?uz;k|96Tn zwy@Z|YTiH9sE0YPosP!;4f=Y2XJ=EC&7$I(!Xx`6;?uYN_xiu_xmRr2EQ5~QT6MmL z9gEfYVnmWZs9ks2>@92bl6_6xc9rE`M@8?PU3l7A{ccu%TWdqG=zK#BpL@k8b{`GO zUoQIKI4kSy-}_BIz7Mz__ow?yb9{$uM9UBD815_QlsXhh|qO*11VPI{xqZslOlodHresn}6k3 zbja4C{olLKAO9hnZt>Ax{BM5{pKlZ=qr)u4b2%z=fA-B`+~2!2cj9H&yQV2kZE0!l z#^;tUxE9`RclF1z)b1a?X+ih7Tl%yPJe0rAbnD;juk26m|6q%a>5rGWKWkdU50-Q4 z(^MnowEfUend!H*I!$Zg%8;c6J%7{17H^H*-SalpZrS16@7Br~wX#abuZnW1{U&HF ze2|56cT1a!XWC7rw{h-!cx0WlTwUHwm}RE)AjqBJ=XoZLkt zW3E5r)0VXOv+3^g`~1z1zw95? zqn-#=|2cjvit}ZCYI50yc{`Ij0+c57I4{c4`(}N>tJn9>g!&-H?BDOVME&edzr>}? zx1jQXeyHHSD=QjKG%zs`s z$e&gblYN+dd9j=A8LgO=;xp{h+wxgoWY@$7HZ2IdFiY6w|M5lt+<6@ewD){3SE~B! z@?ri?*|OR9{_Nb{l$znA?4glS*R(vgLj9r=!xfheR?%59A=%%e)~YRy(!3lLm)C7r z%xSzWIPz$kQHl_s?tg{QA|HN+{|80Rh5ec{Z_AQ`fOidU3(qml&0Q1O*P`6({73iE z@&yK-A@dJ>tX8}9U;O!n|4s5!_`h$@JfkGQSW(sVw>?wmhxm>EFBwUexk zFqd-J>qphz7gn^e)rEX3nQ&#r2Ep{{q8>hH4GwT^)SnnoxJ}a6u(9D_$_L)4yRUYH zew@4{j{e)0=hi-|Gk?j;!E6bJ@xR zXPx7eT3Do1y=9-2U8C+2MIGNGmpS5Ie#o3C6_mgh?R_URN=%E*@cnJ|KLG~Zwk+kv zQ&`jMV+H>HnPS!O=lzAE|GBpd4{{Zh@c(*ll$p@*<@}X}7L8G7PyPF#*AciWlq+*J zv#UkWNxsD=G9)QCEu@7b3A;#($X(}%vsW3`d9p7Top3& z%fhd(8?MfKzw@xE&;D6g^w}CDPD-f?{XBjv@Z==Lz**U>d;L$c{?5g^@a=%(q@}U>bw!KTZ3%SDZrzmpN9UTY#FzS&*XF;=(QW*| zomI+o4o*&FU7iGk@9fpSva5 zy{05e`$FmLoARZ?p{Kb-|7>AM{(mUOHemO<_KK!nHb=J~ssEq1{b%X>(l|BvhR2bT z9nN>_1ItT3?+6!LyJf}(J=ry#^UmJi(AFTo+2Pt6=2K_hdahwn@cp`?^N3S|?B^xQ zf2^uS-tJwLHdk(fB}1`b&Q!evPEE3#*gk!a`5u3C$t1Q9=l#8}@nk5ZN}SJpeB?@* z<0A8=7Z$s(PgK}h$>6Vh#Pv^w=v=k}EndekwM8Y|td2Y@%Stv)x~Elo`HWYlqL6!P z`wEp~>T4qYDtB$rnDAf{4}-1kl06k0J%e@~arHTu>Uyrn^u~jNmag)+-Tw{9)76cvel9a5^0wdIn@ z))#tBkG!}GQf&YD%#7!{=(4-$zp7c=qFC9=NtJ;w)C)h(;j*(ireE1QW$NT@2R<>j zO`B-PSnP7QK}|8RVS`Yj!MW#NQj@F`7*7g*xv!{oqW^@@CwI3G4O1+m!kaJIB{}Zj z8~)qeZ%td~jtv(-^%Cw#V9%FW;>{{?Ajrb=B*T#SM1@UajQ47csjfxYfi=Jf`Ea z)vx&{Yx-gy{AYPuS*Os`cPEN*zf9<}kBjFr)NFjocv`(cbM3YKMRTn;E1R+#2t5yY zAY-ieBF26#%SBNw|3lu|%S%j~jvrNk<5RZ9>uf&OXQhw;fAse8gGW~xx#QNx>Jzx8KNVf&z4GWC*N)t46++YSGOdjI_v zo6h8)_n9GCO1&pqUjDpDy%b-vZ_WEEHf6?7W#0c(-!Rw&l*yjDbLW)b+IRd13-|gR z{ZzW>yzxGd4&iQTsW$?9?$_sPyEaRQ?mDQhSRzvBva)-srBkEj5Y+V4 zfwNdwcJ}ShKXX_9zMomoR8yV&FQk(3kpC5<59(Q)3mJRd1RhOdo4fMb`YnDqBj>^UtKNPu z1ZVL|T&Y$1om*NjkbiuRN!rhZO%`GgO9W@wcCc~_>YTeGb)i(S+hf&9zbyspbgpQp zq;ogLTP|+sd;d~C5fJn+xuKU%qL@Rke3N|306hvOG3! z&xdpK%jze8k*%8Xx8T>aNl(j9Xa6*~aP(1+U&D7^LFt5=2TV5?e*SgnxK}BoU+I6v z$i8I)F*Ee9KR)L1U)!zuYO(v9;A7PrH)hVw{KH(Ad??T2o`toS>B31;wfwRBO_(GT z-Rf00ZL0hKyGLy6wY{Ot(^@w+6u7PY*MIo?S$?hJUpn8?#ktrdbzIlEoKewoe!;qO zF6%+RC2PZuacBN8W|nPWsM_*JC2YpQ0=W~cc5_%RsZ2k=PFB!Y>1TM_>(yuSAE)%h z8|%uxR%+u4IH{-jjsIHtzPGLY6|oidZm$l_xx~KKTkFZ``@0lce=}*`%szI)F4L}Z zrS^%A1D(%hFV!nro6USt(RZ?Z5AM#6CWB*89&Z zrb`T44=esF+Q1~T{|RHss|{k-%lD?OtvRfHJ|N)Ha=V1e2~Tw`0}gbh`7lOw-Kk30 z$gpNIw^75bYQA<}R(-cW9cfcNEKg>1Y*rNewdv=n)BYk~T_qHAcks+Vv8%%|@v6L1Ft&H#`R!sw$KO}otJ#uyNN8g4#0lx#NWhH)E8@t4)hs6@*-tXBX~KnI#h;xUlfw zl(>z&e*&DATU#IbX(i{Fw7fTE^+NT^86hme2S2Re!kwr5|FY6gU-d;Z76w=P-To?a zaLr8PHGLiTjVpKj4f)T(8OKxEbgD=Bxa*B#Q_)rY=Sp{7IC89e;b(yZVPb3z=i4`I zi07>F7jHb|l*?pPw(XNyeTRJFG{JvUxDC4MJtsb~x_+^*wbJ0j!wH4kFGeu`zb@W* z?)rMZFW!@7#qY^+>1UkbpI|ca1#eqJ!L`MbTU+#x&X(0>D5>H5vGsfR*RL_{CZ^dI zpI_By|66{1eXD`;pCCS^yJeT|p4`E^SH9w%K*(i={ergZq^>f!36&NvJlXVW%_r>x zw;1)j-|Dm%`-#t%dr=|FS*UHFUAX)lU-F|J{K1L>%pXE@W2PGF&AO>*EOTmm>;BiK zl?+)Dt_SoE#^3sFy;)~>+J>|ZYi$^Ryp3ge;JP?7(VMR*x985!lJmyAbwAG*3p6Zs zGhw|}+Sz!`>Y2sGNfTXyE!M>O%v@>X&?MRVU;)$p`TO`jq#ykEdguN}(JHeA4@gvQ zoa*~qqG@Z!x5-&`u?+dItXHa4S3fMRGrqyF;fG3T$Zh3m#?P5To}0x5A1d!C-Kf%K zeI_(PQrqwT)jI(_1qw6dwkACKyIEbf@591r?oSU-`KxpOjNF?m`R_uT)n*Ge+|YWU zX7$p!`J2!B->e4p|4ZIYuG9B@Ch4+bU+Wsb$JbfTAGp6O>8i^@v+DUjChb`0bYiFJ8hrY^|zk8o7R($X|-=inzo&CR_-@c|Ib~C-|GWW`@IxO*XVM%yp z!1b-24Q{IzKj*&m|8#?1+@-}AW-xHiyw)6ed;OaH%meqU{)h<8;=87}Wme3L8}Z9p zuI@KKe4oAfhU2kJA!)%47J=HQb9Ce?qp`jjp8m*-7OWrHTbUgo?RDJu=;^y7<$XnUCkU`t+?a;d_(al%b{Q zk;0m6#Mx04((<6i$lUnPg!X+aEjJ#TaIQ;j^VD;U>bp0e(P>%#_=Xi5C(nNWg>Ppy zaq$XowmR~8zZL@rZ-m6oO>;|+&i^6DV6knI$QnHXLkq_a9@9dBc5V?4GY-y<=u|r~ ztJWL3uf90UQhIV+Y2FblTdTwUc1$TD&GM%gR=xK5u<|g2lgCx(7u8eO@BVh*_9N?ZzMnOV#U?4O zS`ilBu>T7m(@MuvsdHFXus*nH`FiP^$PYcsjFJ|o7r)inyI{!@&=g*mS)%#DtlGqpjFO~b1 zefrOEe->9&@QgIxPdu`{g7f)0|0_N%f90+|f05D&!v;NuFL7(V6Mx?~@K|y->0Dmo zQ|Cj;8-j{Mth|ie_GmI*k@AUrmSU9L5}zxnJN@(;)@c)`$o}bnu6|9`Hsip;S79~D zeJq+2PX+zk?%|lZ*J&%)j-wYW-^dl84qV(J!^^a!{;SB8f2tkI!f%D`x8J%`r_1=> z+LST*-fDiPO9inrZ!hLEDQ31Zb~|&gPd(V7=gouq9kUCBHpTHO#P4MNeoFGryZ7e% z0;gU0wNz$e(UDDZol?_eBo3@{SaEdo!qSi}j2|{T#C&1-IA8zSH67L0|I#&C`SWfSOX+4=R{g?GChxEX(~IF~KYz47mKpM<0{ z(~CH^d}9iDRX%M)mf`CD<(6x2CMUNa-YK0f-k{fcB1dhO;EyLy3bK#iId;GFnjdrD z#Hvl2>~Wn{?$=)Js8QSWKlo|T{S`ZEs}8yB9B_+;??W0GPOZ`+CO*WBHc3TwV> zuj}Jhd+L2V=+#`4Yj3l4H_Q*sP~Uf3^Q=hl%sJAmTnUFVe9sHGE)Ob^SsXfT<2Kzt z0yAEHOO@0Q#x>2QGc@m@zN^o&QwBx@`5y$?fb_N)lYzJKGj0{1OSfa5T91fxy7e>WKY`@tC=KVq-z`7EdGPPePjouUI)HvoJ9k{FKU`cTw3`$=EtYxqwMXe&yAP(JL6-A2OKAuL$2}YyPLG!#KEWXf+R1+{)2X8LDV3}KiP+D6I`OZ_rSSbvS&O$6 zt}fN#X}HvOc!l2D#>>VZH#E$YlRTOi$?%`k-zR#u+!9~GUf~1V{(BxTcHq+$uj-k^ zu3MC--=MZ}&9?4053a~}%{TinU453b&Q14z9f!AvpY4n6dwii%sA&D+D~>Fie(x}x zc6j#1$(s`9#BK0XyB6GKy{p6QSbyWBQh^JyR=I964BERdJ4t9Wrp%a}s<-Lq^L@)s zC(VD-wo}RUk4I&8qRA<{s}@y1y>HYwZoYD}A)Y_;Rkd~Iy*y#2c%vurf3=iqw9oB% zb9H67;`X#6?=8Daz2y@pygyRoeOf9j^{yND3UQsj_qwOJfBk3eF;DrrK|uWB(bk9y zk1S2uXIy<0^!m+V)+n2Wzv~w|UOf7!WF70qjI5x|VeAe!nGW2k_Se7bYR~4Tp8RCn ze_7|3GoFNQIHmIZh5gh{?P>pWBOD5ILK|)|rGMuYEK5|3*~Xk@za&R-nRDWkH+s)kHvTs{*j#ZPP zkpD%=gYSt=lUf&9S$icpn7K22Rc)1HcQCldeo3iHlYLIcvvZO=-*fUSJekb5kn7bi zQGc#R7YF_3EAP+GP&u`=_*jaP?4CSlW;Yqe4E$;q%B=Y{K=WQEfCKWY2k-@MO%E#K1J2V8vZ zzqBc)op*Y-GEA~?E}xF`w6%Yhv@+JMPMvUEBsNdDUF?SJZ~Ft!EjCQrtaL+kd9u>h z2_dH$q`p>u$-QIVJ%6qelh@^`D`Qt^9n0>BXHtr*%AVgbZ{5}Gvpi~xld24}G>q&O z^Qx9S))4(a@m#t~`nR?}pP3H`oU!_QbLCgFFuD5FMZZ%w{H}_*x6-uL)5u|~@^AI_ zRgJf{2mQL_aAd#Ql==@>bk%vHk8WS~Q*4Lb>9z|F&$I75;XdouQ@xex=gODYru?aI zVUv+K{a39{yV-?%&#Sk*eRxs$x5ov|RL-=V z;Pa>c#y{;j)wcq<7JcFT*r1?y-B@gi*z03QH%#AUufua?Q=pN#Si|ASW543r7ChDZ zf8qR>%{$-OFRwG~3Y}Y>{o;`LJ^_=h^`&Ah+uN7(gbV91n6MtdvF^(P&6O8CZb)5T zIZw?{qc%Y?g1_XX$?*i;1vhWcTctc{`Ku^TyLL0iGfW@1KNkFFA=6N9l-}dc(eRGT zS=@el&2uO1J-uskWhOncmv(!0^_Y5{>?}q3V=*^4gA*jxelCviPQTr)JNw23j_8JY z5BG)f{_s9qc*4-BU+&`8U};Oiuv0fx?rgUFlu&h|cynZ>*(;`$kla+wd6%qrK7ILM zm(j!3eiJsgS-wx#__S+5X?UpA?{!-lo=x`8Nprb8q3?^+c7?W7rPiz8|E-Ux(d<_E zJN28H%7U-Y-8jCzV3lfZk^bPi_~wdd76Ip*n)mXv)fbosH3-H%`Z)dBSLL4PXRo&2 z-)X$|-}YPVs^y`RI=*(T^tSB}N?a@8Xb{4cZ5bAEIze^sxqq?K8jLni%`BMzztpE= zwQ%*z_tH=PKU~be@oT}OyUH@pXJz*@_AX(z+&KN5?v+fTw(t!}27;DMtFFjAyZPwM zCeglgwUW0jA6{qpdb%xD@5KN31!9j>&os}nMU6SvLZ^uvZcBX9S3wgip zgY@d?Zx{0%*L*muU)NGpapjy!mg#Gb$`ed;g^eQ9zdZ{|dhs#7>c=gXQAaV-e|C7Lr7cH(^cHQiC&&}GuW2(NhH}!x7`=EIb!xVC8>x%3dQkXOpG{W zTr(VR9QAPdSM%`nah1=p8=9~0%&*!vi$&geexB6^CX>JYn^X2&x-4979m>`D_4vy3 zSNM+loLJM9GGFsw++@$jKizBAv^|VF#Gk!OVP~75MEB7Ip1vuw|6Tthbo#=dO@Y1Z z6Bo0(vz$NrD*SfMT077FpU-yPl-fD#MWV{5)TH!{LE%jJV>u4-)+7pdQW;bwyG1~wMEI04OugexDW zC{KFM^DEhH#l!SYu_8X<`6Y+yUMv*e#V|L@$)b4kDq>tb1THd>T&65|^QpcG8 zzMkOJH2ambh`!_FNA(`~`eM@Sn z(7a1iy5&Emga_mqJ>F2=&8R4ywQl1jOaICZA1`iTe!ycOQfIN_P{&4=Z}T(lpDS2R z=M3Zy`4G7I>Ma46>+`NZve~n0fl-vj)9KPb#BZs`W+fZ^ni{cYPZA@4S)lBc2Uc=L zyvG;*ND_`;ZTw`)v9Eg;=xvayOxaq&uzF6Ql6+ETv(SmtH=67-mR{{?d*95}n6dBo zm9G0C%R7*;b|k+rhD>rcJ7O-ocU4yNpn{){)>4&&-S|7 zF+baTIt}(`W-od>;ZuQzoD~Hs+QPrh8ro?GUUDSZzIKwiyQ^)+^-BAs&3^rTz51s6GM_ziI{V+g z{g!pGw!HJ#xzBB_HwimEDYN@-Dr;1@BTbNP5*Y(03os8Ks4s_pmx6E^-_b6H@@}+&>rYDz$t?Qrf__2~#`NFv= z%<!PPyS_#eg)0n8Bx{bd93w}A}d##Dqlq4Q-8^bj71anK5TcMXc(L^--%gHKKid^ zf5zMywhg;vQ@K7g&H8sMsIzb99j&(O)=>pR-4dzB3nqm&a*MNQ!Sw*0^LbDfofqm#T+T&y*_?fSH||2G3~q=i()P%2HU5lUSRQ1V>=}%)p(iJ zaCgbtWyZ~(XZkM3B=DNQuwVXM|LaoeFZxrj&TwBMa^MlybM6B%6PedE@d|ESK2vx1 z(hb)RAG$4?{;*SFsz8@W+pon}`}t)waH zwl^AQ^wt!;5q1{xoHSwin~gG@$E1E8)i?W)ZJD~#A~Mh8KBwl)p!}A`;w`7wR|FZi zJbLmVJHEJ0RBOLPa7sw#+-y0ABZr;^zStQ0f7N;)&xKc=rwJ!oTsd|7Pn?2xg6#v3 z$+v_I_V_xE{b(<}dS$L;vq0I8kBxmtZ4)D2boDd2@Tl;iqdhFh4$BA#1Vw zS2jDx@7Eb`w{%BxpGok%)oSP>%#fuUEj{Pzw8bJF?T2KPWlzj{dZ}xHJ8M9bJZqkq zs$PHXk!xlD!o_DlBNyW@7h zoqkh_xz1L5&-IK=%l03){Sd<-d*DX)L3?qLx|_>`&NOhb-#j$Qc~kC&R(mz3bLakq z*eaef6774JI!!@(#`Bb(`b6f?+%u;hgoer4cLyH{xR88n^FHZU$w%(D=C5THoTj_f z{e+cLuHij9W{=fpR&dt*-7L$sNLk>`7vmW&&Wv-S>^J;0xv}(lhs0lft+V{WW%CZL zmsFL=GGc`>uXm z8ZNV5Y808w{CcBJ*wkQ+nTzkZzkiTEujTbKZLWvuQg`NETpRxL_-AJmiI87~364#Y z>N#iqw^~0-{rr4?%}Q0Xs1#+r7cr&l=enG96zaO)$#{@ob-I@Snro{UKJqTFVE^}` zRqXnvdtO#NrV`;ZUTt3>VG)t>K1A`%#@1c`?U!HDe(+{-{0!&TCqEp5_!m32$v@uK zRCT~I_M}^v&!M;JpBK#EnUVF8hwbyh-}37N9r@!gd}56HcBR}o$Yp1P@W;ow|JWIq zMA=#d-#;g1hGrdsY z7|+y#eLo@_Bw5cldam8XdQ1BCv&sHFtII^Ikh=L{&KxV>Va2`jrUVD z_h{NDwr-t%X0b=TXw4h@^xY>vzOVTg|FSUK^OEGRxYevBRXsXxXVez--k5&VzB7&6 zGKfd!d}4vg^Hs(MMr)`1T-jS6eEW&h%r9r+o!FO(IZV1Sm48pGyW+aH36qrE968#u z&Bd(bQYE$cu1BBn`nQu+Qbq4$rET7dWS@$R1)Y)dg0Jso73kd4`QOHTA-i?pwd`pw#Mb5j<(0rR%Q7YUF)8HcR7I@(=GUo$1B%`bvF@ciC)n*?cy1Rpp!$ zKLxDpR;JVva01be__+(wkv!&*4%CDwoJ46Ch2I}w$%PZ5qJG{e#`U-oAVJ{ zqkrELoySmSIAihi=WbHX=j;1&W`tDD-K^zzXeX<~eV_iF8=}+gAK!`HC~dmSV&bdv z_If#<=G7lphL$Eu2enH#v6-{jw1@yaYhmV%MWH<08w~#{Tw5sRoKqM!#eaX_ zs@TOxy#9#idaEGl$kEpKHLYjcC9CX>{|G(Sy)x%osmAkr)nS(>t$O-q zwtP*&yT7ld>+cP4n0of8{?;~$-|N5VZ8cFy4NT7i{kCZ ztKwNsHP5Huy*b~FWtv4j4i-!Q4RKVx_ME5kfVhlOr26qQ&(CVGXGm-e6k>K)J*H`P zm_78s|9LzCb;-r$dL`3lyjPIs^S<~~|G?^J{>ya_N$=I~w;1C$m4Dl6u$g`fok2{{7!`CVYrE`|-!)@US1XH9`@o_v{SYlg~Yt&z&@Ndq6?| zrO)Rsd90iEZO3Ul(=`(;>^EQ8`NsBx|JEycdCyNNZD}|b)FZy}W2IMQsY29RmHvk& zlAHBSr(CkVdW%K4{zG#YqYvAQ9SjjY3xAzG_fKnk!s02h9NQAO{gY=Vyr1#;-4hXo zTZez~nY{XA#IkTeqZhxf2;fM&G z>lX~o9!!6jwdutg(;}^@wIau_SuN^$u3KQteBM|8dcpRs%{;AoE4TeuKWuQLK&Nd} zV@Jd3g#VY%oZDx$?TJuCK)aZ8rlar7XY0id?<@H7lT%1}-%ICMRz(I$Wo@OVn+a)` z8|u@JimggJvp1aWkBBWtl*Q4_E6%Su=CFN{oYjj05s!JBy*3=Zq0L~%%W&t7N{{(5 z`PN>3zo{pVF4+I8Zj&nO;`n2|%&D(FDCg)bej>uaz3Y_O*JHCk?27YIe(6%n!r{s2ikAG-^$x=6P_5sQ>yYgcy4dCQA({>*Ifs$GfV$H znsPZrgZ;di{p`&xGMw*4&cz+KoG8Utu}Ii~<$vEzc{%&8^?d5HW?Wjc=cCCd(Srw+ zzkLmPC4JS@NmxQ|--fep#(So)1oQpbbaB;;S(g^*%zQa3y6SM!v1yT)&&u7=nR5Dc zOruuEjQMA`Hg}zjmsNb0JKv=CA4~gwjel>?%72i5A<2LH*87w#3ctK3?U==4r4>^m z*1AQey;AYnYXg=EVlj)Q-Cg5ZN{@L-&MMrl_{I6h{zodga@#Y0IeqvY+;(jad*UVe z#r5;-EA!&~_f)<+xqv~yWI3x%&kxPLKH;6Q87cw~!*A9bd&j-H;;lXF^RmRy>xa+B z|6Fo$#=F*elg_-zsL1r4J9q2T^8G>5UD+~QQWD+%PgJcBxB0#9GUty;SId6SUt%To zn(L1RgM;y>RWQO9Pfkqk@hQItV`S=`00R{sZRgqRYn}?v7K_ea z^*^J)kZ1MQ+w*2$x9{jZx-wi$%5cvE9!=YV4=2PePXCL3z2Uh2!U@_RK7V)~`LH+s zk-hEjOYf_mg>ZtUAb%}GQ z9*d5<#XZ|?@qDxJg;xA+r(W@B_S;|GXwVsUK&}5O$0k9q+a?RPo)7l_r5;tb>Bq9- zgFSyQtSL(Qym71WvH7A418Ze}bK7peaL=)LVSL@uMG`VKAqLAE_7!={ubRBxZQI)L z#bw_ln>{AAB>5WEoUzn(IC?(lg^SjlPWxvp8?HaRK4HCYxlq&cQ-yjvEFLb~tTQ)V znDI!G;kyTyX7)BoC?3D}vu%0z^n2NRE`;3M*tP$_$?P1}Cf1CM!b5h4G7kQlec$H# zj~h&;Zb7EXuAeMdKMu=G5{!?sYqH-bW#4|H`JaF0MU8#=^Qzw+Ss}MOIXV35nX;&^ ze5pluB0elQ(N)IWe(35}qqhhC?fy_5KmY&cjaiLFT-*QM5Gy#6q{qha>g3ZIa%Frk zBm$b(e>=}@w?TOSyZbO6GGw^dc~r+M z^onU6G`ZkxD8jS$>dEy5r`LX5y-(tcu&$~|g~*zk%1q^r&(icy?=%WJXLU4->BLcq z^%MTpgvmShFH1n_3s(p4| zMNQ-O`n~$Sn)Q1<&z?VAJL_!U##v`u=e9i9$|kjc*{9C7_?p|?(hHNG9XdT-EcR>I zwvf1tn#6_8Aum0AZde?8uyq!b414yx1x1JX{`Az#{0ONv&S~+I=lyhM|Hm({Rr7xw za`~yScCXeY#f>SVb2#%gH(v5#_l$bw@wRoQ`7iSvtxY9ezh=&v<$c{_x=`rWq<_U( zrfza4d%`TaxR)oYISa&e{O9_kEvG4QF7x9=zentq^^Y?jsymq+{vu6M-YWKV!>5&8M~jv_vj{bwb3V2_a!M!rlN;w_X3q)F7AZJ9*;eL5{3|Ap z<4<1ym|t3xRXZa!JJ~N_UUXK3-`PLM-o*Y)I{1T`?@V}U)5gFV)6B0vIiy$?Z+2QN zL5_o6xsuJB>38(>Fzdx@CeJ?GXptUcRB@obBpdYj=b&? zXBh$h*|~Lw9*1tdw?8T%_Q1!M{p^|oQNA0Wk7!0OX64`$vDq5su=H!wb1<98IBu6{6*E9A$$2fN!ZSkzi3F=QUu zY%G_v-}G08^8J8WcDF?$x)mP#zMDQ<@Z+?fZDuBWet!1avi$b->%P2;_1~G_N!)!n zggsUH+~eh!Zbfanr5elII(s$4KEZk^yD~{5h8c$P=PG8*Z>zDGzd7~mfzR0)7b4^r z@D;}uM^s&lcK#^Xr~cV}%j?vuTMscU-p2RW`s)0(JoyXc4f7&zPJP+9_m)`u;gG|g ziq;RF|EuWP@Hh0h-@1uE>@*MmnBKaFtDeuJP{=FQTBGw<=BdhWk}N`#x{MVLEf@h@;Vw=`2=P=8guio z|M5RzA0(Vos(XFy!I%g#wY7z%HyR|?JuWEz0#2_==QSVyZL>OL)z6t z+*7lE1s+&4xA)Q^gDI72Rx71z>uvjw9V!g8FPMI9W8Zf>)ju-Drgt8(JobNL@x}X` z{U$*Mxx6SH8q|D^v-@@kZX2#v--iRsTaz1O~cHRWZ!CLpWoQ* z^7+x(_dEOQyw*%gw-Af+RT7U#PNBY^b>~|I3OgLi~m+ z8-5%;z$fM&eKn)tMrWSI#cpQNw6^+8;UuEv~U#};v-ynZb&;EHw{I3Pm&c8Q(6=A_<9MQwmrK1%binrY-X-OAwkzbmQdmsJIATR!D5=f`5Ui(2tt(|UcMCOq5s zS$OZ)?4-}PayED~v@@-FJt;A_O7`}}vRjYNKi{-Vf1;DWXRVah+HY64&AWG=f6~^e zd^5^~?bVO9w6W%J_|LF%4QkK6>BaL*%qsYLRR_Q2g6+$KWh(o3a<}|jlpBBKR`Kyh z5#5#xs_gP{zgElcnDdEw#*=5!Z^JG;Qk%!B!JV*Rhf7I!)$6>>wTdQZ8ejb@-)kGJDTR=w0;?%7joH(q_SnCZo(7OQDpIrn3eCTQ*8-(qUis6X}JRqIkG?FiMGxAdCWmCm)9lv&Nt z{`U3xsl|Vm%+0*nDEH=4Zma#~r$-V*E(F|eeSZ7|(}Rtt8~1Ko9-m)-<=tx2jV9B= z>ioi!ggoZU-@bFN?1c>{r_Ai#o}bq5jY^%mHhhc9gpbjV96f5btlmG*@4T1Ps~7+K zk8J+;^E(<>*A+f}`_FCu$J?*BU;m%K?(?_rc3qENY`>nrzE^v`OLwK@-rXzI&ehHL zx%aK~^oyz~`*;7CzGv(9eUDNl&o9#0X}0Xcm)tn(lj7Yk?rQ9c7fGG={Oa49O*ONx zFTHAVYE$g~Lb2k)=kIRsId1=amg_s`$BZlPI7#ZKyOyMz)jc!PoNT^7Ud;D-V2Eyt zdiU?|vaC<4^XozeZDf&OaMi!<0U%xZqD8>{m^vxblvP7_fHF6KYw?A@AKBAMDJ;P!gk%6bw~cM&0N33@~%Om z7vm+kb- zU!P5@D4Qj@NHBP>uy5w5=_rS(LLG{4M zmuK~6x4TUYE@wVn8JQ9p)yg3*bfRp&X{_Gr-tXm03W{H=F$w8%|IVvAF1Y=0ylU@( z8B;$S&A+?PRO4^? zb)v~tn^iK&Pkzd7zY@`)vQl>KlhnfNf`?v&slB(@SaLYl+U{Us(;h4C`sr#l`%|_! z26s#{TJ>mAL03-P4&Spf|7>=~`7FA*)j}?NsZCVJ4erRd-;V5fI=8YUxAW%8^}-C? z-^I3t?U}AL?{1;jg3MW3r^Waxg;KpE=VojRw_lNUT(tbIly!0D=Uq(ucfXvOy#Auy z$LNFmU8Sb(o}6tOUT!uw)qL5`%jca`{3b2GK6%jxmd!KHUv5+{tV}G_pT+(7cp%fi z{g;-^)@N(Vy(6FQ`o=O-igR{q;nb&^(;SMt0xy~P{n8P44Lft%*Rh%P#$U;gZ@yiT zlvwB#DfMq{_RBm=BfV3`nlH{7AD?(pr*FM`pHL3tz0ytDmi=mzFD|e8Q@mV$ll0^g z#Si&+yJjifD%I^_dVNc9zw&qM$+wS|n61AnZT%x~+OGTeV@~xxyMFhX`_)ZR_jH?L zE12up_ZH4K*cq31Q_=dPJNNM`|303%`}b_d&4!JWBZclt)NYwP^<2o_oqyH5-}DO-}HqZTX)pm&q%S`Ij|Nba_JkNBd$Wxt3??2sG=)T6FY*m?J~%ha?^-Ce!& zbJm8Ht|EJ$Yz?a9T&sHDH)!F5=%0u0crvRqOn#Oq@?if)=bJaG^{1VF;bwQYxGctM z^6^>ik3}=4U0<|w^3$h0`VnfMQ!KOZ7=NCOR^rC5TOZ(&v(&2Qr_o@G&!Z^Tp;(c~ax^$+qkV9B=%q zy?kZk3M2Io(-vKm+J3Wj@}|?9=7{7qyBb==6)kzuVL0!6{v$PcJDu6=-D!ri&)?h0 zbo$!Xnux2`Ek{2{xmP~CynNBCr0o|r~4nOtY-@iX8um-nD(o#R<}Fv0dMP;?w7L1XM5U-`_5G{ela68>iSZSF4wIy z;y!NdQsfg?>RbKFl>0%Qs8H}k{rs~>97K%DKP0DL@xA=Jyde9j%@rl{;&n&(@@}18 zpe=6~a4EVggFi38?!~RGmizXa-EO|*c<#=}xHnH`^Du}iua421{q&6Bi6Fc0b#LXw zJ&pR)%1^JJS#h(cE?hT0yLq4SqW{((O?U2n`XNePjil{^}TxfcXwaooGTsg`er=kGclN&8g~5ZmQ|DY+Ae=JC-(gpf6LjPDhDLR zkM91oU$|yvgkkApGuH(j7iw%dd)8T8sXcw&a+`w0F0yL~QiS#|VU zDgQZHSu>|eOMll+vn-qQG+$CJ%4)Vw&8zIcua@mh{P8Zvzj?XeDNTp8Xt94EE**HR zGoAlkc&HLzmF#u?#qFiDdU%#*=pX!Noo~N-uKv`Jm;WB$IJs!Wio2ihsxSZgb;Y?= z)kz6QKN_8%Wu51*^yBhW;bYPk>tb17Mom#&Kl#ey)%$+?E&Ls!vQYW=yDRT^|4$44 z%li90$BwdHw*ogvlwNrD@ zHF1<>8SYeeb9$7+^swQPpUmD^gPXb$->xkbc>b%SLGegI=lz-bZVY#~#^n5r`d4(# z?O{O7`OUBYZRBms6?#`6Yt81Lf91W~{jU1uP46Q`%w>ARlfGUTjk)^NsI+1A(K}|T zJ2U-bcZx+m_4uW==u6>EyUXm1GyBCIoF)8> zuJp~jzc>Eu{--8a5AD2p)Ar9J#s#mWrbm|57S?Ypcov{yIGLR{=dyW>lXdq=UH1RF z;t%qIbY7d=xGU~n+Z1)T`1-ZtIfBls__t@ewD#8ZwD7Y`emptoZsU_Gw(T3w9XYgd6jdP-m_w6q(aM!+TaoD}-=thpn7YS|BNqbJa9QkXTzUHK?={vE{C-+`l8>@Ql z@|(G~$4?Y5FTVfEYx?>|nV3!KqACZzeVhKd$f)?)nI#{!Hyn;w`I@m_Ilm-7?7ihz zwRf!*f6jd>E`R^x!L0aW)vW<@Hcy&%PFsHF+9&&;7X2=M=AE7uc22QUI%MhZ2eZR> zT)Z9L+;PF|-_ndzk#*X$_L%($X61Tv*J#z86C&Xc{VXSQP2AF%_lC3B<@>j3r(dpJ zIivR6hr&}vlYV(Uchq5K+Re2;r|}4HTK-c*y~}$lt8*VJoDh3=Vcp8$Tc=;}PFljX z=1Z#N-FUkdEnnQK*07wjPT_wQeH!+DmUhck7hKU)1^-e`4TyK>>~YGM$b)P-8zWDZM-wxJwRr-?o3+iv>NO?6rRk^#nv^>+RYT}tW^8>=R-rkgJ=5>ed z&Hk#dd*9c-|7&xzeD{}%|DVJ4TXhcT8s1rU;J@2N>*>oa-AbFze{`umy|RCYg70D@ zG5=k&t@i)FR-!d&;heMSj(3tQ*E}`qG7HYzJ+8MbXUha|7GQ`R;TO_ zyz=|^`}z-Gy!*e&+uytH{wj9Y-Q1gB`sO&M7=7d2wrb79B_)?!Vy?EAPjh|p=UMir zcS8MLYJLWy6FruneETwYyV&~<7jC<5~F8lbq_3wH6+HHF#F3W!??$vSDQX;VU{L5=gXS{m(cU4XL zH0$`pn!9%{weZib+PMG!)V~iW%GO;{*`@Sg@8_!e|9k%~|Eha@o3CDrTB|^4X>p`A zyZ54=b5qw$KX)VU%H`XaZ-#_CzgsQ+{^OVXe=h$2^Xk6c<@sO!mE12sIp1hkY4%UP z`d~B3_usDd`u@6a*5Jdg1YbM&)u?~nYR*1cz!@A-Z=y#B-9_x~pDe(wIe|6cw7;(jH8zgIY)mJ16i z{A4y%JKD6r@NlHZ=JpGdcHb+w|F2%k=EvImr7pX_Ub$HkXqnWM`ypY|+y%yuOWGZB z^7`xc81MXPws6Pl>yJ-PR{#Cpw(iS|i^shr4{U#Upy;${Y~rc!?$w|wK>i9x%^b( z;p}a7zrXus#qO53uX^+EjrX13ae7@p67O21&VO1u$6{B$mSDGE=)KiqA79%g*Z+Au z{rIy3DUasNnSJh^=DT~d?{%)*y>*T?-)?2aNf(yI#YKis@A-H>O*!gF@6`A$vlqO( zw=3FCK;8R%;#A{SdD~m{@AvMN?%aJ)y6@s0r{fowWPO{JX103utcgbsMQR2A$@~8? z?~gRMz+b-~8>_3Uw|k`v-xrx%S37H;^0&grYeYR)v3}oayz_YWoSNF@H~iM>&A0pg z=<53I(VcT!cTZ8d|0woDx$N8h|L-MlSMw|}E-k9xwC3@N%wJJWAN?dvt_DfmG(3E- z#;(@B?#q)^=Jmboo2SQg%lS;-Ufg-+uHRgL+qpi=Qg=oid3u=P|K10$zpdq;9=&zd zogc1|cDL{UKXm!U+3+T%RS`{&R}WjoJ-PI%(Dvk}&WakpEAHFpT(-`CcYWh!YojOL zIj1$^?sUe7N0zz1C~EdEv}Cm2Ybhud)3#MB)o|~m<7Q`G*Jw*dyZx^J<6i%Ty^hiB z-V4XKPYdTg-EPFV>BOs=NX~yfx=R8#g_|htc-?xYeAUs=H6d?fc9$u~yWH>kyE{Kh z^JPK@`-|DjBA=XA5E8jR?bpuR+tto}ntAM_&2?4{B~Qnn%m1Ex&9mz1o-^B4EV)zv zb$<9&nind&-2~vQTF)Vk+amTk|oJYKVD zy2ADCI`7?FRb!rgTaqJpZrY5B&F;ho8g_z9dfL_ES^er_S;&q3?F2Y@6b=ceblx z_obU_IS;kupNT(_daywA+0;i*BNq8=dh@XK{mp{!@qhMhVPd;p^N+7+g7;_HL)j1G zcK&~I^7pUDQ*WKHeSQDWTl;_4&)fZeZ~yC_`1k!R^Ja@)Zs#mgw?4YQrQ^u)>J2M| zI@c}yx2C}D#Mjh!500GB@~PaLDLPF^aMoG1(-xL-l|R|< zb9Pj=WqBIL&dQqpd&8PVUwR9l{5{^U_y2GGzpLy2e+>Ws_kI1p_W%Fxzdhf2zB}#P zf}NLY*Qiwns;rzWoT;Q}Jk4)c=x*zoPl9>V_NvxZK6`uf$+VDfslWS=2if`fzo}Qy zySmuD(QBsFqtlb6RC}!78;Ac1mtOTwH~#P4`+uMO|93q8|EtaQzrLQY|FYP=PVDaF zhLGUvcAV0#@jpM+2^@~v^ZP*Vu8^i>#`zoHsh(ESQ|qX?x}Wi1yI zulu+7|L5KQbI)kLbK1!x|NY?f`8J$AC$&6gKU^Hd`SaLD9i3+b z!Q<@x-u*KF_~t*__Tq2tp7YKpw;lQNE#Gj?<7rPE1LHUTKUcTgsB^*TKR^Gz|NG+q z&o`U@zn*{RU;Q_8`(J&*Vv{SkOp%&?LFo6V`8EIV*Z!ZmkE3zH!&#gUm3fPGcWN4* zVkzI;`hULLt>4GidUmGYooQ)({NV%{&&a%Y8-zK3zu&um{@ICng*^K+*-{SwCP5=L4b^PC7`~O~E|Nr0n`Y-MGf1VTO{Ce+3hQp5s zzwLkj)c^N(-+#-7r#rUmbl?2%eY4v1_|}rhq{=7qa&nxCHm>zsD-1hA5Yp0kzcl`GCiH(z55D;oz z{QO>a?sUOcy$nNcE9R^NsXuMM$LsCezWw3!*=CVjZ5#!2Za$rKC?j;^(t{^<_6S+j za8G0TG<%iS+PF6>x7F@^?r!IF{YN&Zd7TIE@&BRM&Mk{HJHM&!``One!OP#h-dK3A zQ+7_B@Za-E{%ms|AFKS8Yu%$~&Gg`i+UCR0Kd--8e}3;9k4S@eM^^VR*rylk_N>dB zeyCy9I%!k=V~;{~&o*ps?`-5gcQlZ%ed^Vn`ww2PjBf95JGwT$@~rXC)!v!QE$SpNK(Y_-A3InR=j<-va5FDoAiJbn6Y*0LJA$SHEu9r+}S);(xs ze$d$z;8i1ad|g(IqUw%GW(=;ZA&q<8-Igr8XYrK9{pZi&z z^?x&8on~Fb?k;iYkM6U#_mrabtnbfPH+-gw~#V%+xzN8QsALqe?;%c$CV$wmzixPQIhzl`mxUI zl705pAHtU1-}6j;eXZ_`jap_l#di~zoGhGT^Y6l;`7ciXQvKojbFHcEw(Ey1^g@%> z*&elgICJg9CcY*PSJuZd*SS7ass$w7Jj5MPH$DB>;Z0Q&_BRE0@qYLk&-VLHx{24B zrGIWRP1#s=?BdJsM>kx4ujBrC&Gr29I9uBUs~i32W>49#x8GofimC5()rWpZH-2`B z-T!LK|EK;>#MxrxE*JClEJ$wljBqe zP{K97MeN4T9qUAbLrWi@|1R%$SmT}jPa~OczxSq^&Hrxow(Rvs$2BWhlOOM2yg0ns zm#whecKXqU7A0*OF$FgJpX}ekbV0~*66cPWmVOx<-d288sw zBaTX~;r`*&oRxmms@QbnUu*u_#%D)%iM!TEIX?gGcXH3qC&|~|e&5xds(*Udr!>WD4={pB}LTK>KhzxLkD*_Uzm_Mz8RVF$MVo6P#-bZbnT z;;g`l@>bIpoWB_Mmierauxj8ZjwyHZYk&Ag>wi<|@JRbwYhIGt&Jg0z{5M!~>gO4v z)7q2Heu)(A7iLmvnL6RZqlll}dvatB8HD6WpPP58z_RYsb@{HcDRpPrCRFcxaW;K( z-8VM*kVf0Ch_G_o%ALh}uXc0oW~h4Mu=fmKM)sz~no%?VfB5G4`tI&C=Qqjg3yTTH z@ri%-T&1&e71yc_O;202l{ay|V49+#vQ*3Xy87-LJg+2ddvk70P+d2zM}7kD5!R3Q zKORumH_4aZpToQ2U&H^oWy`<+dZ)JCh-JOOe;$jNCmA(AB7Q0G$y_Q8?euNqd)3mf zzV_*Y`9Bx0`TOhXvK_bDPkVGds+1PdC~&yJxI9Gm%`u~y{Rw8bo~V9KT+;S&ecJbk zsPNerJ?#0Kw$5|ozsYd_*@IL0*N0bYv?0e13P`cpH-Ln0kwR}@D#H%BBMl^mo zJ?n1ZyO>H{XMSdhy6~{#2QyE8Jo|R>Vi%5rZXMyn-}=L}_trjif8u`BZFQs2hby<% zy}zz>Ghg-0ro^^IjxHISj!k|3?oa^xO|b@bvz+-{2lQutE42-)S9Nt)l5I8PD7f~H zhwbuDqu2X(&CZ#-w`*O*^-b#fVe8C(h?##-ouPkx>d6^Tel~wO`gzL7=YHGHxJ+BS zXu~G{sqd@ZbYDC(->Fk45V6VWPW#J{Y@O|#QhkYrYu&A-SbU%EY3>hA@cqGBTE*Y3CK}StvG;9ve790&J+*^xr*!Vi-}37Wcjg3qD80S?jaBtrrn0+TylTw}FJ=_5 zT{hs>`P8fPIy|xC-nly=Kd`?qgCGt8%Sf_X^$k^4IXXE!XKY^4vEi+wUI= zlGF|iTfe^SXLe)8JVn(b((mq8-;GWCd-Hn9P))%&{oI;#JtM zU0>h+y?)u(V(v1JOUpBVJvu7b?U<)>a=po~*5fn(qz7&~VOHOEI)U}Oywkn%wb#Bc zeR1ON|BtV>-l^NzbtmT3tfX$mZo!b2AQ8dFoD&f{QzVcV(5xBlUPQtU|Ok}^mV*0a{VaC2=O4+RIr|-$xd*@i#{Y_gZ z6o>vfQ1<3P|MqR$woiUtXOgluO@XzrzHi>s>+c_MZ~Ob%UBPZm{p-{J|GqJ~D{{;J zamfGn{~z}MJO2M|{ZIbqPuUqa#D>=$z3|#JxJB+Q_m%yUZB-`=pYXI#T7Tt6Y2&|YOde0~C z&K==5KZIYeIkchK;c~vr-^@>E;!o0HC|U+3%Z{CvFaNA$}#3mNUB&ddF2 z)@i-`Z=%dsf2K|Aq+S>3?20$`?parD^MuW=H0%N2T`rzran~w`U(# zcL`9A4%V%(ylY`)^Go=rvt)_g<0o9mrEDk=y)9Sd6o%Bf%3V1$1Gis?%i^=YRBgCEy+=3nc-D_7*jR?OgHNzpaae4bItG?9PbK*k; z%I>XyzO?_e<;T(}_D>?K77ArKoZa0oZ-4KucVCY84L8obJ5LK1h6?vGc>0Ce2kn03 zRd1L@M$FgzUi1l9DKyp{Ei}Iq z(f?7fYv+!R*i~VVw^pp3qkgO?=JdKB6T(;{rX+LZIB$LO`ibo3m~A%~MHZ}H*D8O; zu_GdKx7)uN2Ol>){a58^{7vC++#&Ho-_1F1tN(OHOm0)Iyizsq59gF0s{1vKjnnt( zir&2WeSWdaS^F$|`L>0tj^9!ZJM=8Y?^EHTF3~Hs=ZkIj?_4OJymW>3Qw<}pBE7zC zVLBQ|Z*azBx_nae+vnE5{&BnGHLVNHH8~q=BHCj+w3%K_yq}QtGV1g3F1aFhR(Wss zt|?F5H?FRlRXk_Ii@9A3yMv0}pItOn&UlA(jHSE%Q}(8eB3vA$y&c}uQk7Y zw9l;neEj~?e{RM;Px)6IpE}LaVl;Z|cX|Y$Q${a6#@n&lOY~R2gX^cMS?|0NX*&NpX zF;AyG$^QDmXKQb7&&$crfB!z`pz56+mH%^Jzn*=q`v}LWe^YB-=^x!>VXqq!DScws z?6T$6-+Em->U$QQ`22t7r~glX>{=`_Pn7>@M8>X4bzFx%Jm$TX{>x>o5cj4})=>nkr$;y<)f^i70$%=HUf zm5%cB_g_-izr6e9;Sy`lZSS1^RDZu*{r!?VfBBb5m8!dn5*IK%+@yQ@MqIhor|igY z-~RPV|8HsTsGYk@?C&AdVGD78qJ>_2 z9SJz|)9P8=w_pGMO8*aDlsWNzV*NXf`k3wicc~t(`_yU?$MD=r;HSbC?`)n|Q%*gw z+xS||`pxLO=tbgVq}j4n^fUABo^T3=@f*tdzdL^Ap=`|9@ z*DE#4v!pi`em;1({rmgP5{tf8+PvG6-t748+u7q`-&TEnQ1|Oy>Fc-C`Q_#I*Zg>L z^6RH+y_&+D^;7lR&TM)&d;5jC^*bERzr_Dfx3}1r_x)$&m-};5)^Y7-o4lm0w`irt zg8d7_vLjw!&60F@di5}iL02p92i8)v)Ye^3?y8)#Qa3%|oOeKJ>IZ$v!gG~<1~F{H z`b#*j7-y|<_&@o}+uP;&_xE_j*Uc}nmOZd7((Kd+@00ts-rM)?>$AIg-TnU8-`lU5 zAiO#-rt>j3Yjpm7JBB}=|K5t(ZDK0<@V-=3{v#Jtg30l;t@Af`$um2@Jkxj0Tg-uB zb-*iWwRyoQWj&ez}FIgE^(?=86evgG#73=0`PwysMjH|1TM|GmoL(@hKM`2GL0 zOxMi`Rr!CqOJb=3)1!4eI6vkm37<(mrT;IWKlgdos>e!8kTwDwSP2`g77Wm77MBpRRLH(_l}I z`N$OI@O&q0we3lT`$GH0V%3~Bd~g1jaN*hF$zL}x{P>r&@5H+M|J!G~oiz&kJon7~ ziH&F1>S}7)EwBjVJv>$U`9_B6dpf*+oV(Kbxp>oM*)S)mIeFn19&Js#+-LshhOgYd zSKH-es#JsQeZTS?E;+iYeoFDMi^rilNv;U8dfY_vu|9xt1 zPx$|SOY++pQVRQP?@iw^@ANOvp9yRsNgmUK@6R%Hs5M?!Id8fO|NX5|{CQUrpG}z& zshoIV)uH!OH~d#)VO>x@qxovs)fE%|^UF+N(6QvvU0u}5XZ<50^{>U>O>@pzZ>}_p zIMaUDalYg2j}q()oY`)_?B84`zxwj|Uw7l`zfR7s`7^2hn$_J>i><=XFa3)AQuw)8Y@y6|OpS{_pm4QEm=BC&gyHk?MQ>@9o*MU%q_# zd3Uyj{H$l|PA5sO-_~YozVXvO?ueBuR$X9xWIFwyLHU|LNAp}vLxn#qO#SWDYryBc zHR$50zQWIS*@hB_ukX^yZ`NU&y8~bru8lqz40sO=ILE~?`{2bexHqXin*}K z&0SYcFL_z-e7nxwG$nR#K>vS>ZU1%@JJ$KL2_4D*YyWJE@X^JV{WD&jING&o>(n>u z?dm2lhH<-^^&D6{=ytCHgU=_-+ZuOlMLVOTn)Rm_cCT&s}o9zoXy5wYBrhe-s|gEu30?mUXy?0Q;z#CW_gE`5dsQ- zTv(G87sjx29$782IOtr{yQxhTPpe~UcpR+lc~1WBReDjpH}kgmPwx4z4sAKstFZHS z)6?iZzl`RdTXy;ACjZ>y$reYReOJF6x83?xY1Qev?bh>s)TTd`f5b0wyuZJ^ys~3` znc>5a^>+^b+kO0&?8ov~b01sZ_-~}K?dY{lO<`BgUY%)JXZF!x2irt#oAnzPSNqEH zn5S7^V7u)SnZJ57lS-D`Cyk3QW~O@bMz}t=?qPB@IU;DYj*lnTdiBj4`{hD+h+8tQ zk6=0UeyjLt|M|-=XI`86wQBFhge!79ZHND*7|pmSR+h=}E1=)_<5Q*+YlSRrBwoy{ zt=aedVCUTF^Ixs}U;Q<{wY2QMho8)&mVdARyUxjp6l%I5<-P3i9HvdBX7g7my<+5; zq04jNX29hn1DPN0rs}tQLrpf&^yIEqeP>$!P=9wXM;oJ?;)#tM3Y!5R@+91q0Y58flyacQ1ivv@B$ER={Wzh!$o`}|4%sV~n)zwE9xqPIvA0evCjh#XoT1(G%%O)3Se&DG)XX~*|ew)IJMWx?8vwND)9Iv_fnvp|yT6fv{ z>nGikSF+FL`&`)_zdrDp^DBGDU~S+0)3Z)CD9>z)64_Z0l%~>c_0RureC+WsM$5fd zodYH^Pb!;Mo@KZ9fqujh)1-#e6E4_&x!WbH&A4OjYpZqp8=HfQoh_v%_w)9iestt# zl0x&PIDtPtZ8sI$D>>L7P1hE`6%?Y~cX-*O-@83Oy*OK8_ioR=|4XhOw@O$qeshjQ z!N!PhyIgD^Fx6@}@~^4eH{-ni34T_Ei<13O%lq?=2i^#I`h5M*rEZ6Nb&MZX7@nSb zWS+$H>3^bjJlx%vdSuu1@1IJhq+d}?h>cd6!7X;cKlbB*1xr0 z&OWbq+UKP%hh!ycIrtJIMX$f~dHHvtaO{I6k!6l`jvuRUzPP;DefN(mr*1OLh?*b@0 ze-yMkFMbrGlaOuU=AGHWaYKabfW*wl1tnMXe==Xw3%^mjypvZvuQ!wBU%-i!9mlmk zMZCGQDENZU&8NvNf&$azFZ@6FWBP)?yrps7tSR4fepRl1)#5mJo_&XCe<+X6=S``a zC)=X=>zXGQt!+EMORjDE_VW34ice~PKX_=J@n;kN%XZrxhjMPn`nzvvn7mFWxk2?s zN%e&P;=C5Z@+^$;e?C5Xw{T9uVVx;Dp6P0_MRO0N{#_qie(t3H^Ps7nPtPnm$R$zd zKE-mA5r@T`Al@k}ro73U+MV-YYO%+mDiQX^=KNVcV%9x5VSlQEO(JX*&N?c8%boZC zME{RT(iiL_HI*6E{}yjO@Kj;NGqa*Y_wL%(eCvC*_Uqrj)feVp%wT!MeA@iH*yDQw zTP$Y#Wc;@(-faZ2Rgq$=cs2 zs6V;>rOr=v#pvFGUS-aAPTPbwRi5Tg+32uo_vYCdzoI5qYE5>2Zn3N-+=5x~#JXn| zD^3``^$HBJaoe4!yUH;A#N*-ukL;sKds7}<*DFm5OO7vGwbORSem^tD^Ras38%iGk zTVpTboV4Mtt9blk?i~MHAL{v?o*_VV`Qs7u)-fU*3$vgLBg4$vn<=pd8XL)hhGrB+C{Xs8vP5#|2W@k=6mb&w`Cb0MDyT$ym z6JmaBI~sK8p5+8Rga0{Ns}KDU)p6qA7Jul`w-T$JDs^VZITJdMX9{&N)l50iH+!Sz z#SG;>DZ9rxe8wgZHt%1yabvAUOX(w~wRRJ9r4sUVZj`^#Do%SBHHm53(%Wep($+U# zzq*HQXUnFnNhZ0guZg^VEv@p2E2c&J6JPolwy6;<7RA#7PA}s*aqW!vRvp8h_<4Vy zpM2TwSbyFVdj4}jhW|jevI&oqnp@2U4MW6N%^LGKf`C8eKyIk#{V*N zWi^*LLv`r%vpR9gDIcV5jwg1xi>CkGyWx^SCF7YVzs?78E!n5tA!jDTZ1v>VnKSz7 zYu&A@J70#}Xw-IceInAlbb>&<$>S)2ToWHZ#+){vSv&I-m)+#f3aE?KU9Z*LtZk^C zugsUEak}>l^KAQLGfx~irBLtoQ~h*~(Hy;HQ^dUuWWE0w&$#sK>%(_PioSdn;rY1r zpMmtgdY3dW|1+79Q@5J#zu59L%jIlT%K9|{o}s6;Z*^~8zgm&oJS(C>^j`5bnb&LD zG#1_bV$M`(oV)keH_;18+w&e}I#lW?h1}uodwTq~L!ILKcOP7@>b{QRIidPw!My{* zW(+MwWz#P{eYC>Om?PUp`{e2V$LEp^nXaGy7nZ2abHT3RUXsat-=&|n-_ETmwtSQF zS#r*Qlh@9Y31Yia>JG5~c$Hvq!tVZUrn$X^b7J>y3TsQwaw*I)so*$rD=U4m@h$nb zgmqC1ghh7F`=Po&Sa&^Z3Fn@kBhlimv&%0}_n$Y%&i+p1Rp}R1JEsK4-oEusGDO(- zezz0zy1S(|KPF0PxKI6_w1(+lMDm_1Spq$hzs1`Ej()8YFp-wt9{=yfH>+;OkRA8K zH(d3W{F0geqbJcUqxk>rltYUz+RW~~&C+bUhO03!-)w$qf?%Rl`(uB9p}Q&U?c9E` z%CVV`l-n)i0vOHo#1$qPX4EJ&DDPd+aAZ?b-qP8Ak!4MhHY?}c4f&R2zH?(~L3Vw< zIp?{y3x`h3K6+s*|0Uh2vRjVV|9SW@*Qvf%_KHSW>HQUd^q4;}F7!R1Q*+w#tKE7HvpbvVJzN=6{{&ZLELf*FMPDCvj%;MIk-|Y2J`O)lR(9Me7z!;+KiOk)A&J z#SN35`I9H<9*}bHnNp?_^JQ-+IQ@-3Ikj-Y8$Y!lmnTtV3O7L2vK5U)_rGMgJduV!J8wf5FvwK2Mg7 zJdZyXwA}Y-D^OVW*DmL2%AdDK5B}?wuI`Ne6tXs|Au7w~!PC~Qi97erS$N$4aQ4(! z8|qfAzmj~kT}wQiv2gjJe~gP&t}Xa0pl9~QX~~*=jjT7QR%=taF36q;87Tf3YY+=c1A`>syUY zr!G`>o11rTQump=eXT{`(_2%!uCBP=J7+}^TdUOZpA2EqsmJ|4efsI!di-uD<2%v$ zvt+ZP7AKxq?bV_fx_8H>)s0z)Rd(O|)%rI)wNOFq;N{eYL6U)df$!lyxmK-pTn~%~-JX;7XPRuXjfU6|?*zxj!!X z+U&k|`}_M_mmQ8vcbH&&w(YRp+gmcra&3x8YsYOF0SZdhi1 zefhdzhdPswdG`7C!#6YBzU-g#{l%Bm`7e@;WOV9I-JkYB;7!AQY5(b`4=$R$Rqjp^ zvnu})b)Rp1j>)xG}J+K}E?gSj5zPmr3Q7poPM#GDG#!)sogf zThlz_q?5)T-=goOZc;3cYLYgNW|F#_8)f(y)Xx0V=&*|RJ9hZ!BuB?T*)~$lY=;uk z?p}NS{=NOydk;Ok-~01#D>o}I@87;%m|@1>y|(FBH?S_$F)DeuA;`CVinLYtyxBRy z)0po(@pTPVd~eH{cK<&zSbOTrq1>F+C4cP);Sq(%S}U@cgQDv z{xg@;>_*U;ZihwQt_xVpR_rLtQ$FXu@Aw?)=!3>m0ckHxCbgH&AGnfBEg~;nQKDNfh{Z^Tctz7}LImXZ;>q*m*=V z>}x10p0#_M&E>V<-?QyKDD#>@^u>hVhff$4DuT8(UJY2u;sfnLoU>I}U+UEYP2l>K%w>gM~3rC$_miBCx zQ}L79#BHHl@0PAlnc{jhQ>r>M`t6Hzy8QC+@=Y_XvT>jne_`=|Re9LqpF9DZnkx6fh)||SeIl1cAl)3+6 z)bAZ}_lXFbtWxVa3j8>=@=ezUA!&c<55UgB}U|9QU(%^vE{|Gs`_?TQ4k zDGY8_Hg*;_+E(7WZ|^ZlU7dfPP0gfze=h#|@$2gE^Yi0u>i_*{*~`-{Czj&U%^#`m zz!=<=;4tsuggpgja^DZkPtbXwQvF#lqG-GIOrGh^%R;8zXAIAn=Ir^;>0n~{hPKLU z-^?w~I7~})K7UZ*y#~*$)qQ(rp7|Q)s@lc$GrxGrMZJRNg{r&FzippXy?*~b>zxKq z-p_iXU47=t>PM>+)V=m9{8{`YenF_%XY>dc|^a{kVJeKMiaxEo=Yn zGo5?p0Ymj$!!wF&4wY=0!RLOtEWJnAKqm43a~`gq)E*WI%h!Ad*_X%Kj+lM?P>ZL?+Tn*x9+`a64XhF+Gu7Yl z{=R&##Img@;kWwaZ`*&He~OaH-jmfTE;eJDmX7K+m7vt{DJFhx8`+xb-G6d_@Rczw zh&g0&<3o)lo948avrn+kzw0&WZS!CE@B6kyt-ojIxlZucoyCV1%=)=`%J1uoBLljt z?(p#Of0wWSd+pb^hsJYm^4!V)@$vCxm76wp_jXo(ezy2~e02Qt0`>-{%}0ywu>O>v z%%v}O`ewqN^C`UoJP&+Q_Ue6`8TfuUm3ia!U>X3bh^@MP^ByW@AIj?Q?l#--$ZK;+Gm^Or8~E`Ps_ zUp{umyRzKx>yJwB)%Txzja&6X-`BrS9(*wl+0L$SCUx+vetYx79`ETiaCD+7@=S@1A8ZV!F z(`e?;&u(oyd}gPgT0Qfz+mjD@>J1UkOm9^2olV!$=G${Zd}6NTHo1iFPnjfNy-jXw zou99E`*yYGrgFcV>&wJ%9OCwQyXM)tU)@aZf@jv3zdm{S`1yTb-6HcXST`(gRKA|M zHEw_9{AK*ni*MF2)ZKr5T0~=w%)c3ZVvAKR&~%Y&3$mPp=gV782=fy z4IFd*{5QQg*k0|q#_*`*TDLzRKhOBt5Z-^y*?Ib1E53l;O2^NwxhWI-Y=_f*gC`pT zz56U5uMqyHYU5|GyMM{-w!k$V59XYWz8V&1(zNG(i1r-T$hxTxt~!Etb>F^T-hFL% zocyNmYRR*VI80}r*%Y_@tA_1Qx4UtA2i_n5P_dx#!7k&RpOdEX_f+1JHS(}h4?4u; zbn&(U%N3?W%=4x?ir=Zc(>`ra?S{7}cmFood!TmG){0H%Re3ybFO*Sj4qaR4`(qpP z^!4F$6GA2RC4Mk-3RDGld+n0D?^o|*XKx+i^5)4*=ijOyuQDIF(qC65-;`{<-$G#d zHdTH56la5bA1kiB7yjn_>!y#}?|XF~@pV5s?y~NCdHR$7r9X@lK6*@R^Hp2Grr>?~ z<`h-tn;9FQIGuU+$9nz&m&p3Q(4?3J?X7=58a4jkb&%6>)8;FWB7Enw*6~Cg;d5{} zupm)ljb1tX*4~?!UT}uSebOpT^L0_XvZ78qx7N;vcL<{a351%eOuF^Y`A2m%TaXtokCuJ07n1{_b!8dwIJP6WHormv6q8@nJic z`LuQxKi+xrKR9mNt2(AkS~B-wgC4tN^Gk;QSQ*w!D+Qk}SE}{TPh`9@)j95L#P{&x zqHDZvrxU(jQ?@+nG`(3arZOt>^pan$y3?39&15qE>~_-o-Co8|oo~I1*RPi>Ua@N5 z>*_sQHp~5!b4;92psN19J+l2bKj-eda{te}?6;Qsc5i?6mq*pvH=6V1i!9vwjfEG~|`A2i0+2qZeH@w`w`S#_Wz%K`zQk7$`o&9zzR_33dc-WNBTkY%@{;`}` zTz|f@$0RiFz^Wv}S8KdDYwRc7H~AP^(Z1?c-{2hhf80?Oj;&y^epdJWWC+X@8Wlt`g~6Ijr#s>?~f+m zX0LuWW`UYZHmRTTr%8Uk~IIar;cXTIY6Roxkan z&8f9}7rc64SM{_gxjRHlU##xOY3+F4i zrzfrCIkwRE)}6V2#}^wu@lUvYFei3rY2SuJ4X#-QG1K_V<=Y)&ua`bJDDkKK>^7zu zH3BKVEp0M?o>$rNb?nhRaYfd6SKf~3t7(6qpRZrbn6<0#*&&XYDf6d4x@Ti!@%LK& z|2hUA^LZCabTi+zJwBgV^*=M)DD_bJNvV#XB@8p#Sr5E(7Hw-jx#RNdHC-*$8yItE zN<2{M&2jCuzWc7|6qpYcU5W&J$0cF$j|_v+56h0R#6ST~!Qjc@whrw!HCZ@(_R-0*Zt zDf8W%lL9i>xUG(7m$pex;j}lNx!J;LW=}#&^vlFYnwGOy*8AG-7La;j|Ne$$s9#BB zc*@4^lE;?95hn~5AGjR4m*Z(b?NJ^ng-ffu1n=FdKKreh)of4k?|7rNHx6aRzTvyB zY-+wqZsT8ccnag6Gc&nzPd{MaaiGWaH6@8Bkjx=pLgdItXuSLNHP8y20Ja_)bxkxc2X&(}6Tu?R_Nm1pitVzvlxyt!Tb zhF7<#?!5G)mad7p#fQsnCx`1t@)aa|>Z@#*k#^gCra~e(?MD4mseScvE_?p%GVogM zdF)#2(Jog<{grvHcWOS`*w+3t@|CyUGkw{Q&nG8;IeRzyR9k(;`_nQie0B+rz6_gL zXD?kSlNzkBf885C#*$atZ@)dc3-!Dwy-(>eUN9e|}6``}oGOw3S&B^VFrz-bhb5)3Nr%)6(o)g`1vt8S#5)tUjo7 z`Q{z=C6gTYW%E15e6$QsG)?V1yi(uh)0|5jJ4$P6D(1YAzwb9`wt2q#?Cp~lOMic- zF70Z6&!+Zzx;f942L72J8|KdOC^DWJne6bua3AB9`6n+;xVI`irE;3y4E_hEDN2Qg zGyTNv{e;(Q_NXZzh-jG=ekAdN15f4Vp7h@v^{ZV!Tw5cSBG+)0K~bP-*(>wBd%Ly@ zM?8HyKl#AvlYf_gpSSFHec8t)snVhg?sN#dG8pL3ox1GMKYM$=uWE{uWt0Wihik9d zx&LEH{K}VU1z%q1mIW>P6S}2;pZt;pi+NjAeJA8(p0c{Ql4s84HYWGfgwv9*k0#iC z=(S^Zj#!xa`rL1ABN|ODK5cmTYu~c_ z6@Q+b{LH-K$XnUUz_aJhom>3d|MKokrK0Qem@jC~(YpIoH(17??xQEKQ@(Rt=Gjx$ zjL`zeCuZMz{n||ZLCE#Drq-4JR@%3<2roPIOz6zv--6mF?w%LZVVmXqe6^9{q~^f% zP={O7H+01bHkD7mYv!FD^>W+NpZf%liskp0boX>_6gqf#=61_>fo1J2jhU69*L(je ztUJiF=C|~|_4lhjt-QLc`bDJmZ}#6OvpBc$ZQGV-xlSi{htbrPAxXwP@78?Y6QbvT zu*2Ex+ABBBZMNbjyBDlzos}+8x8qvO;|mpQJM8)8>tB6uSJ-~pG2JX*zg_Zh!sNL9 zmt!mcyVjq}3*2^Y?JYI;zk1A^&5`vC(Uy{DI~x);b`^B4ZC8&zx=a6+V=sg5oe#yU zj;fjPE;-P5-AqL*!^KNr*E(UAJC^cwfnjX-Yc9>=-9JxGPEPL4eXqP+E@p%4My5qk z4YOB2I&FNQ?^cEB;s2+;7*kgn0#nM6^qn|cge3$ z|K9$d;peosj%M?HGCw{!@gT=ClEH$Py*A>fYrErzqkFEWpR~w{m;YrTyovaT>&(_{er=X)6R3UU?5t4x zJKd_OIToDjk9qma*?7bsmP}JV#=hdLcblb}g^U85x0%4%-9mhZ@|z_3j;#@s<$1RG z=Z4caSLNunWM=I56JApxIHga+qi@|NlV0=sS5b^drWapO4r{Z>+i+~-hE4b58nCa>%BW( zW##4D%gVwR`1ASh6M5aWuBU@tHtp@!(%$AXC#OHSuk-E1hld+keZRZxeGvRlBW+R9 z>wAC0Uf=!wef|ELe=d!lKiG}*efIDNTRaU<*;K&u?{;!R!o9anuX3#BZ;$k5Z8Auc z>sV^i{O0Rj-Lm=YYf8k5_|_bnc|1#`Wy4RY2?b|1?*Dp#T`I{nMCJ7U;+S^8)_I=c1Y$L{M! z>o3YOA5Nd_S8n$3;5n7MCy!k^l)l%}+4gj3+7|XRIx{~eoeI$C(7&0> z`m?`ce|$FXIed4zDD%yfixXWJFX-B=%3zS}_W5YV!MInN&PRXTw0l1zVQa=Wt-C_3 zR(6)fEoH|iiyJ)b=e?HA`ha6jD>GBT5x$4(3-9zSHZ^{dQP-XP-Xi(iDW((M=7+96 z^Wyxvh_Oq&{hBHB1gD?xLYwc!x8F8QoxU!t<$~#IozE{AlwW;3{eDgl?;UT^cfM5? zk8(NNrs=Sxuc<%qPyE6{&AkuiOxZb~cUSC;eTCPa?oZ=k>c74C;*$GseHg?Wne$#{ z3G1!eaqMCFp3f#(SDe$&sv2;vJi4_s%B`%5LDu8YWuB)t+I>Oht3$)@?J2s)bfE2* zI8Re!dB>C5uIoPRJ<<`gw3H9e3tS+bl-RZQXW-_GcN$6qa^||{cyEcgtM{A1YO`L! zgM?if#y57SOkE?;eRKnV|Ml0t%er%Ru`oU;-emXU5L1=$>#xriKb#U8WGmOj#}T^w z_p^V^%6lfty;zpoDzwW*v1Cr`??q~JXFgxsR<%2hZ&pzH_T#G-c$Z#3TY7t4++M%E zLNAYg{{Bo%X0ar5?lGl(R*b4VNoNa0j(;uXeUKh1zi@M;dWoyv@(ojuCrdn7JEwNT zgN5(>s*PppH5}OD?#HhDUZWGRw}#c!h7dRa%E<{Nt(Xv z>wAB5ildcL*wgKuJi@b*-Lw)GiTY=u|IvM+xW+7 zbL4v4`FaWOreAt&ELp`@iW)P&+t5l8+@?;O3{Z zcYm|jSSwtaYTYfd^!ovq9A$$AoNRqdPIYmfyYj4lLAB_t)pz_isk0xBt+^7ZFR**# z&NS_f>yDp2p&|G+`+A(0Jc9$9jJZy}{=^)I=Or(*GFDr5U!SDfZ)aQihx3Q)w*CAI znDY16<<|cHw)gAP+Y<~j6oYMJZ~ixHvX#(1cKBh#TP5z3tj7BSugP8%KKGEP?e0%4 zjUVrRzFgRobm3js{mt6S*Ui2vWE9Pr=~Gs?Zr|a3ni576)Yf!P<9|4F?v23D`@h}# znyS^hRh89`+raW3%Y>DILUVZ9l;!ecrrEQ-Xx$qUQrR9Na{7?Z<72&h|3+`$woQnk z_pSTdlgFIU<}}!sc~at>8S)tGqan-)VCB_5(kreo$?{9{ux8 zm6^p;=hQhHYT9m|J5qj7^}6y8U(@{XJ6&h{Joi2nH@U2Fyh`Tz#};jFg(nKEeg~BI zG@LtmXyV)_*Y4>itiAnmvAayiCW&>+Zu+JOE&pmz`}0#}Rn_~i6I|At&p#+s)MVAk z&-nk*nt%!QU)+jfPKg9aJlfoza^O;=(bH>(+1u@A$MGKA_)es4`>D@zGlX`BI-EJu z#`fvmr2@^OYx3M_3y+(9nE2*pfyuO;&bm{q%PlC**v6tqh|dgx&0(I{AAz4vI5#hWI};+zu|mMx!jjAnJ5+hRQT zQLdex-OaC0mPs42y1hAl`OXi|Aj{A=eV2>p4QI2l#Ik;Psb{GWcBA3F!`VJPbB!sV z1GaAZAT-hZ!G0xWeRdWx*M)j_tfE=h^EF&NB(=hPZhV5_>x?^lN+<2h+go?_*R9O; zNell*E<143x&QYjm9kFR`EwWUlM595QOLi@zp)_UX(G!_tGle(R#ND%rFXGUI z%tAfMC;mqdy0I)e*!e8zKliFRTG{_r1qWVDTGJM&vHZ@j8zp-s<%$)u&v<2CUQ=|A zHT(kKzasUUT9O7uE$6;2c3B&}Fv={V@UYsJSvMGpPQ)7XhMZsR*lf5xw327R)3xmK z(WgD9yX6|qJZJU5s$0_dj>Ywy&+pG^FxJ05AyFS5)R@Duo}Jl{$z_^jp+oJ3{|6<$ z}L7Ge@R~qYinLqCpyRb+C@L!U>j=o?;qPL*C3_i{J9VQt8qsx+Iw8R zKj?#d-S#Dl5@HYsKP^$^arCysdvh9BCIb$iyN`~G?I`Kpe*0hU@%G`GCJ zdgaEd7`Z*mHw8yA#V(bcsHExnt8mU&&NtPyX@8dGbf>J-pY1R9rD*QEIg%5<<%qt| zV*bKY`K?{@?Sq6}OKzvfExF6er|@^_;bi^4lTIsIpW5|<@uP*WN14TLS8b1{j}^C^ z@AaP`&64oO<@G{6DGQCIPp+*!{PytU6n74`180mjH-{xuty$k@djCGRM>ijTf4_Ni zjl<^!o7NRf<=JUfru8JZ-&DWHvV+52rNOC~w$IQ;DiJ$LkVXSJLQ z+ZyB9n|>B^e!n{Rq(j@6KZ`GNRNqnG)i~|E+u_9B%v?SDw_D$xxJK&G&qU3i6+LU; zZ#-IYQNFiL-mlD*Q6@P=_tCFASub|QTTlMKruD4a(}}|IPgpm%F-psZ-*|s2`r$Xr z0?&inrWNx%jf{Hw;zPk}0YAa}IxU61C!hY&63F$9=brU7!ptXb!aV*xqMH+5E`HAM zfA4Fx%s0cBRuhSfC)AkS8(V!hd=S`qeXh?9>GN4Xe4csD{37iiVcBNie!zUne92%( z*CdOEze36{j*2i;oM98X(ao=J9cFu_^5iN58~u8*18RTSyHbm$)G}P-dTPR*)V$re z+r!-T@Yg#Lp=RbUIYNRvbtlX1OL^^dyYAbYo0FqC=d>(q+Zg_tkzH%r`sj^ocI_|8 zGjd8zce04PPE2ReHZX>HJO(rmK6Ts#7oTER8?mRe#Mit@&aR&z9pG zU#ho_C*UyGw66<}Oi0(L>$?`G&2GaL@<46%eoNt2 zXJ6*fifQ{_E!nl<ayXB3v+P%ztk!$(GwJulm(H?VJee5Lh$(Gj*U2Q;!~aeoTXSY>`W-RHjD zy}OLQLZX7tT;Bco@$4+~3vu=2>VKjvJU4FKsQl+#_BHs=!6#?FFh1^Guw%~O>yrz0 zPu*ACD8KRCUUnVzAHkd4gOV6+I78+K3Vw*az|i!R)gw^<_2$q?wV@VF$(cgYFBk6l z>E)+Zs-()%6eUpfD!gDDL#g18Gp1mx$ z(uxWuyjlMJn|5lj`G-&M+-m-O`8ipgJuF6O+UvY4dY$r;g-c}jFS$S2>5H-E{~{wv zKlV8+hjjeQv>rkrvKN!oKQPCb466%&2vw?1TL+zD7-9i zl%P-Y8kPQG{%yZ^oP6N+L#lgzn$DkB zya|Ge)w{Xh*v#!;#yqX>W5NNMJ~rnWT}OMantZFWrPdx6)wgq&aKNgphF=@Ck00k)A7$$?|IPH?re_u# z6FKvLe>rWE?0s$8POkR(lkZ<}zPEJ3o%+L%ccpAR?U1H94ZOJw9)DixOPWmD_*mZm zdvc|!n!Z)U(fx|00peSC>HPov)bhfP!#_(!w^`3WZRxgVh3Z+m;&3!nd)UQOig6E~(vWST%XS_AMASAIz zamIs!EARDhdYxaIwfDw%CP8CXQ3j^x=k?ZcZINo9)XlJ5{y={6V!jl;M}JnCo|&L* zqneYr$HTmI?+&TFhYiws6>>5*)(Mu%w?uyEF{>RE)JdAP&ttoS{rV6Kb^Gq~%6kGQ z)urqIUUl1WvhoLw`sh!y1LITD3+f&I*)@Ee>|T3OQh%30_632s1uS943`q?u+o!VU zr!=_`6FF}%-HWb*Cp`3x^+O{~*o zU&EA{m!5FPJZ*V$cQ4BNCDyh zTuzCRn+1OK&AGPwUG=?RQ8(9|UXtMWckM2oX)lj${M62BpW&i(+*)MTHsOjoU$)Aa zWsDM0yXL<86g6Q7gYc=@PUp@ZFldR}$faX#V`F9e_mFRTZ&>xUxeN=ormy+J%=Bd9 z`x1tD)vn|7ikBbHmE-brmE}Et_+!kup3_QJe{w>Frk`a!^MIvc0q@g;2M?YUGMIb# z=Wq7TW%36eC7Lr`vuO2t^HYm=;!~+*lF??~2P0SWo{8f-wI;PEH2mcMygZI3gZ0uy zd+xky5|?1Odoek`x%t2v-nfa&H~GFh*lcUV{OS4Dt5Wl;6KX9s-@jK~^Xo@u_wQpf zuj{0~X*$MuL}2BE2%cSYLp_|eEIlq3807g&Tx>j5?yfxHvE`o_X)cD@{x2ODwkzLM z=5o#CHhiFyJJU#x*M9kJgInfzuU42ye*S!|Hh1dw;+B)%i)T*PC}`Nv|2=2M>$8(q zPQMy|QJe4ECuTqCYZcX6e`c{3$LpNB)317sfjQ~8=m(YCFaORC-F`u2&Xl+==Sv6f z_XizlTd;UCzr0;d&Cz4!4`dy_d~9)Dqm!1Pz#(P8%GD;C61gL$iE)DO_Pqz3bgBhb zvwvY`*MG7_;aj88xs$9Jm8Ar735V)>zmd{%d69v_?WRDK>D;q|7MSg4FdPD~sy-PB(VU znJl0_N0>>Rt2Hn=r~atjeB+etNCBDs8GGyR|1z5WNv_0h2fK|*T&wskAO3zJ zb>p97+~LXvM|Kyq7>8ATam(p{z{S&gMc}~Piz`lh?I>%1e9^*X=YLCE%gRl>;j%35 zX_9xA?|gOYTf(POnIz@LAKNE2?|ymui%IQIg}uJ(!?RELdF(K^bbO%`ToNWAXj-Vn zGoe;S+#xA?8S6~X2}#zKaO|B9DHU~ChbfQ_VnBg zJp8Hfl)i<+mxF8P-gS9?<=2B1F=_lu?wtH#VCggIY;^VZ$#2iD{rg1k!>R4x*XF-x zh)$eabFZD{{DyPgO)K^1Z0Dbz=u~CO#MklC$l34MMoZ_g^eZj%T)K}W{`yqLF_-^= zf!2n#|8`bY-n15AdH1jGlSZzuCcCc``@gc~msykL)|AaTE0*&)RbkHM1!=XCM;ZLp z)Ml0KJ}el#=fd=VMV2!^eRyEN6Y=@VYpahi%Hl8YD>|XqVk#A#O`)yBwwym?~Uzf2~Z~B~?r1(DfTT`^VyZX!NIYv|G#uk0~ zyv2O#%XzAg??`(5<>+BseKGs|@4Np>%wA8{GG?=Tn-;_HZ%V`_nVd7Te!AwLnAh$) zeM<)GysEYA`>n4w?((gC%UJpEUb4WH>udYxe~5p5ykB14O~~0_eDlQzk5A5vO=J!^ zvooMAZsEMc=dI;tXPEjne(x|3QSGYOJa19=o{yhfoDFyEvc7FFwJ~1fx_9BbN$deF zL8fQ#EyBV@CpKA%;yMSwN=bEg^vHp+!`tJ!$V=~!pE3=O0NQRyK zw_gc$PKQ`uG$icEIrMYqn>DpZr~N8l`{kGzuhj1Yq4y$lJzLhdY@b&n!+Tprw&>Io zp>>OlpV+))wRn8oefPFG%Owxqo!z#FW%l&i9iiq&em&i4utZRFn@q(iC9UUc4xdji zx@zEBB(g@MbmxrSx8z<~UA3^Vy5+yWNAkVYCgHAsxhE{xn!i5gT)w|-*ZS!B_S@ZZ zCeJp$e)WCd)0zUYEsPJ(Pv20Q^M5X%xQyu4<%eH<6~Fxc{`}?lXBgM9`K((Vr6lz9 z+_kh#Q|}zBXK!!cK3RRfhpAPvl+*)W$-1|`w;roT_uJW7mpm#xSE)NK=Yo0M^L=U6 zQr`7X0`uB(mbGLq{xNISvsv5Lyj=IwwL-+Sr?0>7(SlFYocxGQ`uF*F z`{(*iYYyapUTvw8B>yeNnOnHFq2=v${&#cl{J$j0fAgA2%!WUceHkOx-b|RJ`^)(i z_nUhKH(vL)Gl$unt-5@2(bqpm%i|b}=5Q=uvDRoRd;9F&o>kTVU;br}n7Lg3X~9p; zYR>1j3`^G7zd0YiHTdT9bk9BKKI&|I`QliX*9EB;|K3NtF~xFQSe$;g=SI^ai+ztB zd7BviT)5Ko;n}l~3*{}uo}Onmj^}DPQXr9?WWV=+v+rHzYcCUw-5m_>`Y5ZZ=4+61f6=z-j=jeM2KSBJ%RA)1 zf8jRI-^j6kl{KHA=dWBgHVcUZcl1*~KI?kEW%J85ci)#sm0y;&emR}<_bj$p39DU4 zPR?1oo_X4DA)CUe!!!K&Ww_E>l9gt>`hP8JugB%~1+Ds z94(~VuG zwzadaxb*1t>vgA@*FF2{7SMiaMxji;yquh@@hPDevETjr%Nw?E9bcioT;B5d#^c-C zB)`a8WK>Ms@%Yc`u-9MmChf^-6e+V~IJ}kN-?Pbv%USis3|e{qdjFI(O3U4#!?Hl; z@Amveru}uk+gUH}(mnpBreW;?Bmbv!-Y%3e{r~Uh=Jc1F)xXOxf0`pfPF~)-9Chp6(`LrUE>vIGaQI^U*ITFVvCevZY?cZ8BEg3Ej}vmK*#qZ}KGn%?l-yJM`@@uSW!*gOyZ-t2 z_vPwNKP;)9%zJC@%_X{mjZ@^$Ouz2&J-w&bDSB7r>;LKR?@oJcu_@=^iE5?~1>ZXa zJUbVym{KvdV)nMmmqxSguG*eAHrqcz$Tdhr^^^Fn*WQzqG&>);rhR7J@LAPCsnDNc zzd`ldy|$m2HiSH%Av=5eDXl<}nJ0Rl?yJ53{nK=JftTjr*_-3^zde~y-?y*%@nZLHet8=iyImJ^ z>Wst>i$^lby?=A(mg@JF(Wk>!uj#G-9SNwQ)cjB8r&)ylHV!kbGXmq(Ze*Qh#JGClm z&wjr6DX+gnus~y3vc;73@&EPu4xSF*zwb|~$)p0Yvzz3k?>^#5e!iIRlg*AF#cOr5 z_!H;8IKGuH{UH1G^YJGNjmwme%Sv*8{#f`mImSt0*^|qEzWL{0xVY1>>htgHOHp|b zw@vQ7YwwotW<8^?##Dysf4sTjP2NKcCOZ|qceIP$FqB zJn`DCQgCH!$&M2ge1 zClgvdeoAzD)$gn4cC|UfKkx9n+RC@LwrVHI|5kc4zm9ADiv5@Vuh{$S++5`=($9Al zE`4tq+Ba`i>)-gFYwq{&6*ZipxBv6y*%#&W-4DyR`QO|B+xgE%as9XskrUtcTiXbI zE&CAlz+dW3xk$io;cexKv%mER{+Yah@#vz%iyyyycv51^gpdW%)i+c8uk7mh;e7Ei ze>`W+!ToEecgrYVRZ08z;%$M&BnHnnN9Bwz&Yrw?^5n_2ZnsakzR$@&bokZ{>HK~5 zMgsZYjqBsS#IBaI`TOkP;rDE-7e(E462j00X?=JIqv*)R~V7=h>S^fP#pWXa0`~AARJF4Fw zdt1GI^XmD(*2MPjFrO{6<;0@mSf5KVQG3dQOq@Q~?EnAL^~3wRXJPyImHu8G%Fc#F;%7A@0&Qm(6Kd{BmK7uzL~1vZ$Jy6F_-eUgftpYO?^hX&2RriDJ_eW71* za<&Y2%ONJoTYW!RH?{r_?mBqvnH(F#Hcy_Vn|S7Pd^z;HMC|GD?XLd<9a66KlzndS znYDX&#`0w4pFgI@$M5~0{N-Cld2zIjQ`~dyReSDUJ+_1U@0$A0-P*nXmu(j=vp?^k ze(I0I&Ql*4>>j7yS-&yh|9%cf$4{((tThyyqt)geH$DB=KcDx0@DslNK80>}nZLJh z+?9XdSDrfAfW_mM@PYFo20K*P*^f)VKXSW$71fH`)>tH*7iIC^+lJ$#;DD zx2z5%yjA<*6rgeZKVRj~IX^B4|6qIE8-Jni$Gf}tjy-$w^s+Ut(ebUKb;+em|8FeT zO=(`w82{ep&yhTJvx`@H6OY*it0g^4IV<+bUR%g~Zuwc$_xk42vAaSZnfxwr{BtJz z{67mfPKGVdrEfjirCF`CN>0XsqvUCPb$d1Yi#E1;C%1|B?JX?j_Wow}%8}O+5I;Rb z-Se#DAN4a6JdZFuHC(t(z&@jkv(U`*-Q>xMO3R-;co1M$_38BH^uyneOaG3Rw%=dz z>+JN%471sGyWa?YU3X&L*6UH_(*JKKT!=gwcIf%uGvx;1nTaGxD8S-&{l(hMgo3B6F_P+Cc<7NL2c5pO`-Y=;CEb!rJBLBB< z{G~EQ+04BY+tu0kcfYckDJSoL!P5Q8Vb2{*jz4?$`J()c({+YY|Nm_M!SLN_@zlaA%xeOlN9T6F+0wM7YUBTn zI(^?CiE{k$k%^D-7E_uPt^eis-g`CYYxZ4wU)|1C(par^?t4|<)9lXBygNIpzTSHL zK9%v<>>uqR9lLMOd41=|u~(X|6Q3|#UhtcJfgfY&gg+*bmk ze7^c2&%5%<5rHjLXUmMTgw8%%G}CQj{WZIAfrQzdpKRWzYKt2fh>3rQfAKZ^ZB7YyIR}X2r#tIT-v*Rg7`C@y*dov{wMGYUrCBPu!>uHH|sfxT3MMl zdAV;37Co5I9O|*7&-}pZO^jtt)i2toym)@OY|nx}b~oxbcr221YqCG{+vEk~nrA<| zj@T`4JNiTDJ-ZF_r@*^AraixTc6Pk2G~fKX&ue$sd)(f0`1-pATNCsBYfMdk%rp42 zRk?QW$LY*Mi#l^9_Eu;{{kr+#<9GYL?)fh!$~4*@3%J}n_v4d-?*emOW~=W$QP6W! za{ES8Te~|_-fMa+Gc8rKv$G`>ZJhi+>isF(*_`o~S5e?EA1 zw|~5S{r}hc_W6ag_~$09NLa8mReY*Kh+U!cISDn!$Gp6O_kXuXN8h}5?Zs1W%f;vC zbuQW0&R?#wNO8H$)YQOq;fuT)?ek^kzj@=hjOAvD&(ax*5e#peFDo0mRXx4b@-=8% z+$xs?>9gMD_uZ^6=8^rdzE^+Um){x;*5RRs}2GS;knmLL|Bdz^1s$7cVq?5>7Z zrX44^i@bGRde6312$%1hsC>+8-k?p{ z>wG1;-XVjp;+7*z+jf6L$^E-GR#q4=wr*K-|Kv88Zy78%X89fGC^Fy3DfA3qRg}#ce$02lt*GsUK#1i;Inp zjE&uS<6Zg-z0*n_$NlzB@GAY8^;;%SyyNV8x&L1-`zud~%YSp}(cBHIvy0i)Wmy#~ z?5k(1UrF1pYIo2cW$nAVCVA5lr@-~FSGAw_T%`(|6xa89QS@9ahla_ zJM$v#9lNw81P`mEUbEFdzUp$`_URv$|I5m%ZTJ*+b+6r@R+HGvoMk=EJ+o{4b|?wk zaqrm_`=$PU>g{%+-okIX!rKKjlOztV{FHQB(n@H5K#%AO#e)iZ{}m1A>?m0wzF@^Z zb6dH56{*}DOECtPCp$tCo~Qh7*f(v@+~@L(RSPUTRdxyLrfyXA5^6(Gbb$<>yS7Z?6+R{4Qg*&`Vp(N?WPiA`P+Z z3I)9<_s)IPtI9C1ylFD`1h1t;FpJ$H8~*a`6Y6g{HEU|UyDj`h;r+{h%{58J(smLJ z9Fa9;7ots1RAmK-WM zc1&;n?++f<}exP10SmTfbCF}QXgPG}DNlJY<0`}XJO zZ_4V-?%&OJA#$hj&ATpwp*Ha)VZo^hi-fN8cip;wXwu~PkZnnuZ12tU;K}>(Q1g$C z%)O}38@bQ&St&Z+d1of(bZ4rb+VgWyJPvic9?mIveCokz?eKLx`y~3z`X)Yb;J)(h zom@VHaH7ov)_}(wC&fGe{NT4Iw@6j#$lY7FWZ!olZA(&8J;LdEKZVgu^;o;A_07B0 zcDJT5RHlFb%F$5vy*$&;%>2r^k6lZXODP?}~P5FUxQGsCckn zbI)4gj*}Tbf}b6dYHK_1Y0+@$-lGZj$ChkrJKHhOy4CL28{_%$^&ei}zP^9&v<;7@ zUwrY^W8YlW+qt`bb9f)Tz1dy0Wtqh?hbNvDqH@tcpHytHkMWV&bs+Jqf}{`U`;DbF z&Av-!%ScuKJG}Y2O2py6mog?EcwhFt;-yg4itpQ{d+P8;^TzbV29-1y zQ=!W6gY#3jJGRdMexyFrybbMps-YY0ndh24(-S<)$e?9sCyJ$>`| zQ1yfRX_-tbWh!33`YQA4>-$ggJJ^c7d+v)#{dy|D#Q4dP6Z}5M-Fe!+e>XI+nCrJd zOwGFFw>ke&<(iL&|6bI4x!7aj3Rf|g8P)~c+=DkRn{4=3-wk4rA8Wj5rR zo7;Kx+xLo_;!=;keYsX$_D*4G>%6pYC651oEYq}VKCW)PiQ(4ux-E|D^YgnVeEaYt zAW7y1W5;>5TXFmM{(l`|_u+@Yote8o%oX4~U9{h!iT#{k@@tmZCDq3RcK+V&p0WJ4 z^X0eCTw)gg{a7OHdARq@TYrBxzC6F{x1L64Z!|Uj==s1fu~1F>(^H%1y`R5`?m5}4 zJLUIwf4+jvrynv38=j~+^w;Sd|H{=b56Y=Eelz@4w8?c*zzWyW=99cW@3hsJdpKj> zFuh7zz%$jjTcN7{OG?H6pB3@Jj_q%BZ@10K&)*}lx6XRjyHmwIN1Yz^bnF!s4?c5t zUJKWPsk8Iu%Dn0K+_>G;vg&(EMR$#4#>>ApZD-c*GqEKz zlhc|E3X}UI1D1I4eP5n@(NbgEK3TiHTd(C!zGR-{SC)I$vRvxLq3kfrQ=9)Rwy5}3 zQ=M=0_wCu+LyR-lDzQ}aV%G<=h*X*H*yv|mZTz3zy z2W2ifKVA0Je(5@K{;kIhW=mTurxW!q+cS!4K7IP_&R_p4`Bd~Z2c0$dg#PSaT)XS; zjE#4ij2ypCUY^zOsPOKE)s%#iE-{%CS7xi*-FR(my$WZa-T6`&30w&GlswT09?RJI&NsFRlAjlUS~DOq5+> zj{GB)y!i@iQs+zjaPoU0E;Cd#NsV^k|Bx@Y&s8`-Pd_kaTd|3)U1DEFcW-b8 zr=aMr>Kdi~q6Nm1mrtt6rACXq`f+!1^mIM**-MpImd>kRCVphD>fiLa^*d_M7GIzL zZ`Ve1DLyvmMgQx5NHzbHNOIy|{N}abU0IGpoqdOM4qLi;bw~A9=6iM*5=M7Ck37IHu7HXblEvO zc!%hj75PfWTNaydIDGmD=iNIMzaP)t>h|pVwI}~Om_DC>mTwWcq3UDL4e>1}?jD=F zn%`})`}K8vZ7*!9zW<(W-f@0nk=wo8{OW8Y(f1|aJN6mOD`YQY`0EfYBRnJLu%y_Z zMH9DuH;^!Nt>owY&-wgWpKdv;ePiF}iZ9Q$+n(w1fAH>5{IMxA(>Tj{7XD&%dm20C zWZ&@}Q4bj0%7srB@PwQ?mb`Uy@5kHe@sHvj#JtQq!kkwtl=jB|^N;A$vG%`~S9Uyq zAG7~giNzkP3IieGEygpOE>tITrFb0dJdoR6HCf=?BjLbS310T2^Q)SLK6amSt}WiA zfAQS6Zz0Xbf#Mx(>XOWfg^P|p%09Ef^4DKpzrQZ;eQpW26n*Pg4Ehrq!(RD(p3d$W zr`HO1%JK7?uy1MCTW#3hJCkKkz5k=_dGGYoa@J;^HU9JebpT^zkhqR!L)plH?pMC%KinGGeD&yo^7qNwL1+5G#}i@W^&_0Iod*6g~mWwLEal=_3H zwkL@@J{0p8@eYV|P)a$1rb3<0*1?n=Sm*jnKiR;*g`0wZ`4$ANkl*{Ey84XRb@)JTt)`li&edkZeNnunes{G;5l(2u&)-Z{`53csE z_-gU+`KMyKb-2GWGwL1k@dMV%t3Gb?VM-PJh4P z({Y|H<|ca&hur@6@8ZXA&kR-Pt_)-Q|7mM9yO(#(md(W#EnFL2QfJy6JMDh>q5gim zU7g*Fov#_Z+WtAG#^c9y>A1A@#T&)1i``FH+Rj61RBdiTYpL9EPZXM2$XPlF57qMh#g z8(ePteD$deiI{h1S3 zp0By<$+z-zJB+OF+;)uo8)5CZK-2Z@`>f9spUJ1PmYW+o@7%xjU;JLX-q^piY}-5ae{~#n27l^W?1JYsD3{!OqagFgyh7T& zBiZ1oVb$lXYIbvHpG}LCFFIOpvj5$_<04b&o4IT6GIySysD0+xuHzYZlYdE^wcTM_ z*&HmOVo#Re3=e^~YE zSSO!kQmLQYclPl7nEiF?=YMNAuRl@n)APix?w|AgH{ZLtbN|#N)!%>KefWK!ufMEv z-?#D$mptb4ZISKxAJOx-)}*Q5D6v&~^O@@C-wVD7H*aixdgG?$4I2xesn!vDnCG%z zvsd`cz3KSv+qc)h)1f_Ek~E`J4UjUr&y2 zU)6BoVC%bF9~0;8id#1q7Io}M|01(QHfO@MNzdi1Mas+7KAni(ZGHLh^~D!g&!6A# zcJqa0xKQi@^-U^5Ou0SZJ?1o@um4(5;A(T0_e=HSP0ZQ+_x?85`Yt&Yz3HV$`Nh*4 zXL-D_ziG1L!Gs&R7g&?yXU$pnoIgKif8o+<*im$E9Ak3as2<=z%tp{sV>qjvs;(}Lj-O{D%8+05)wzxnMTiw%E7^Ww*v ziyjGE@m`)Af6u1E;!N9pzINqPj6R1CK2)okTVOw_rG3%g?QymeDXX{dt3Mk(Mdgs~ z6R*TOZh!oWx^muUu0N_~RR2a#-dVMiM@HfI?(;1&*Aj|Nsv0EAdzj+0IzI0I_~B#u zclMq9-kJ@^X723galH6c$K%dtznZOv!3GPmZr!$W@ZrDI_VVFGqniIqKZbLjHs5Bk z?`(H{|3ae!zgYdBa)>|PQ&aKSZCdTmr{>BZ?l1auvQ2V|aG!;*;`;gR&F^j<{dcx~ z{ek{{8`UQi3iX)>$T*s8*tvZtdox2UQ_#%0izhQz?OGrAm+!mK(+_)d9qp_B|9QFj z;MO(AciwPIPE9R%+_OjaR82ZZ=}_;dCmy#R^YCdi{O~K#etfAVUyk4X zli>b;U6PM-e>Ok7eDFbB`<4BniyJL}M)%jVuRM@YpnbRYZ~FQ&?Xvgx{=S?W@$Rm2 zi1M}z^=(s*8gAMCqoGN*_MCg~{x@$Iwtp`0p3`tvIfkvu=9n!1Y>!u6J^8u&e|@`k zb?ert2b;s+Yy5jrIkRVbUEQb0{q}qx_dgW)zGZH9#l_I@`Flj|e|q%&;LP*1oF|vJ z=>li|=YZ_hA;#|Rzjy!sy}rF!d;5Mi!~d6;FOILTwyUy}x%2zcyr2W-Qu3y^XRhCL zkblv#r|a9|ch~dm&;DkYcW3waFSePx1kNu?e9X||ZjyB2{|1H?kKcY)YMy&?qJ%}( zs#vop7h_H{c`W(<`NOHJ+u~#QetU4zTcrB?GKG^rYJaeN-*QrkXTEK9MJ&(7)cesV zcbUumGfKTK9CC(bzwL!PmNPDG_e+pcFDW}}|Lf;%{r!82Uf!Jd5Y_| zPBN{Y`5^wUM04x{{ZnlH^7eI~9-H5>Z;JNazmxp(rb;%-?urK|BD5PW32jp^-!GVV_cH)SVhe~S6={NCENvAcggQ2iCH z5_bDW)#oSI-ddOE^XGZa`1&+lLI2dJ{zA!zTaUj#)}C@i=&M<3g|+P=7J*wH7sa{6 z9DN#OPo>p=d^){(_V<0iUai~1)-0X$;#cpQH+LCI4b!R%x?kL#9e-E4ruO%%wQFv_ zopbMhfmFSh0FT_hX7$bOF7GE^(={`!E3sg0J^t|Fv-9`sejjh+vy^`nCj4`CEwAXr z`G=O=IeBdT{d?Kn-`}3&HnU`26cF%V`fovY!)u?5Nf9TC=6|2QxBP=Yd-MDG{V(16 z4tDq^H~%y0lXKl)}Bfr-?Xa4r@3e%cN3_5ozf4nx!j@iBAfA(X6KU*a3vBn-h`S9cU z`!$9V|BmJSKUiXAdDEr;`aCxSAw#+Tqfvcwyasn3roJ`a{_E;w@t6kj@9SeSO`PJF zC`GT{bmQ~`&nY(Nj!Yw{5!ha$V(p$45m=_ZK~MIuo|*?lOr_duEnbSC(b|>$|*P z{>P)MI^hQPcRp`o@YwzK@cU+Iu46(x8@iH>?*90BTRXHe`^Rgse=c(#>lSjFeLtAq zs&>@*ipTc4N{a(qb9rN4T{veKz4z;bySt|^wr|_9YOltxz1-P%XT+a)VfFhpzaO0JpYi`k*^j%A-|ydVbl}K^xd&sv6vw~%UX^`r zp{*|Wzr|Pi+V<&}RBe>M__p?uEA|PA=zvt}4FXzIgsT z+v+aw{>qmw>+2uZimE|T$j`0k>=dNK-k`datZP5<9K%|Cv6@2|V@ zulQ6rg!We_|4(`UBPCz_`>eNe3p^ix{qXK?&C>FZ-@djlZr-~#w$Guz^6uSh@4hv% zY?$4ifAsYSSpk6uZM(Lf*?Dkr{854XyNgY;KAOgyIHbO4b#2+oyRW{d+RoDZw(0Z6 zsr5}(M;^S^&$}xZv$wpq;O(miuekD#MMbjO8Xw#}&0|l+j=ld*EuZu1sOzE!tMj+& zcQRjz3Z2J)#wgC_?xVjCryJ^i-SzQv&WFqL@9!rDeD05T-^28x|Kj`o|IL1V{k`6$ z`2N1i=dW)!x3B*mSa$2ym9is-ArJTc*s$oa?6Jw#(~U1^C(ii$?Zfor+w<@5YnJ?f z{HrqBU!+ zxxYj5Z^`C0-r_D-PYUzD+h6hb$Li?vcMr1M8uk69^^Vo;kNl?h>-?v>`p|#>3zwHK zy!gKHl{A}md~D=j5#dDz&s18n%Us!**kog_MP6L3Z54Z_=7fL!C9UYUVSG|NKOg@) zF5XywHul`-qdD%}*PbVdO%d6B`|Y{S3(gxemhP+hQ)2Na@yFT4@88*O^q+`ghSe@Vx!MirZ@+uq|H`Yob@P>)Xqy zZL{vyefq3_`1SU@yD!b8=BcprR-WMQUFPzvaql&G?-N@6!gl9=Wv@Par}kBNc$i+( z*Y&*9`u%dY8*ZN*eLXCFsb<@f?!NE+2S47urZtLE-@lsrL z_Bu1|jMd)za$Ac_n7^+rQ&Znkz3}_XtZi(czCKI8zCLzm<>O<$*+L&`7}rhZw!OKE zyYk=6jHa#MUZtPa&x@6gk$#Y@w=?Z~%#hDhrJ>-#aejsbI3&sRM<{^Orl^qVTxGT$8C6VI%7 z9NaEh%U^!++wP(((tDiv*S5XwPuvhw@K)>h71O!Q*0-}n7GHhYkp5r!?zM`AzgEb0 z^(f2K@W=m+GfUrXck1WG(EpG99VV!I>lIWu`*QG}DR21idGD#=SFSgoW8Vt#ZLxo~ zO+{zY-b1{V+M(PjUi&WFo;J)`5V-4h?9V4gD+6WpC%*W$=lthqt!v&!FYMhpqip^C zmtSt>X7K)>IbFdyW|F^QOV6q3?vvYPs_*Q$@<_o--?Vr2biH+PduF7I-!}aiA}wAy z`AvvSH-AdHbgJ<-uAd7`YYK$lo{Wvl{Zl!wcypn1heVBhSorUm@4pHaZs6c~wr}@~ zns%MU9o4GYjegqe=G&Ocp2Oyw6sLQphdwxUtoZ8Dsf!rTr}{2=|GBKXbgSQ)HMMeI3hnRA zY%cySC>uNP?WWGh`#Q|F`DOf?AE6ep$!$ z5;%L*-p2{QjMToRkjCWbU!R*h_4kfz(@Ky2HRZh%a>eC+#jcY}Grm1h-gMreUh(w~ zwFAj48?WkUiZjLPfB!x|Bhhx#x0k=AKODN;QV_Lz>$BH#f-3z=7vyzX|J>Xz{>S8F zg3IpHc3)y{8>*c=I)~NO?tO)Opz-sfi)(%y-nw;1Onuzp)@T2d{V!x5H*RHh`>-bb zdCBI__VNE~{(k;?UOfK)_y7Ou|JpBK$NcB{>-qXI2bA<#LO!kEypGrEx9Y#3$Z1DE z@pAvS-y?JUVN77C_rnb~_w7GCR@7}c)UF&MR{yWLa$cBn?)_ujUivE-JZMOe8Xuo0hLWY^k^7eB(e*fzKQM`41O=wv9j*^N^kLo4=8Cgud z`pc2)rx7FLpKkuRDIet{8Wilgf23;ucslvhhyDlOKb`XPl#v&(m+t=H8bjx4*`#<=?@H47|M{y#YXOXvOLt=?6RoXg+$*D>xtz^}L5^xEbb-ATfKKKlF-VBKTDvsC-R zhkw-w7KF}xaN_3UZ!^A}ex6d+>My*vXX4jIdve$N?fz$R zXgh1d#-}-{HpWVynm>JvVF-8}usT^Y=0M)zy$8O%mefA_Ir2b%i9%jR=8b>1xz2oW z&U*Io_pcx4pOi}0Pn+4nZ1-{bUDbbk(rQ|a@j z;JB2y1;Tb6)!zTK<}Y5g@JX=lyZUOrdaHl3&HDa|*^zoO4L;xNx5auFQ`qYX<~ybKADI5OJYAoGe^!~-2WgwF3r^J^@r^QB zJN1zNFGFp=htCxj-MwvW{ZE#uE2hzPvyagHr_&!jFLrw&WpSfIWd8Jh2g02>HdXzv zj+MXtcIJ!n8B_AMGSwNTN0|8;1pb?TCPU2Sv(Uad{|`M7H~tgRu;2r?&NG>Ri&_e2 zY_6aAcK^fm{q^N-`vazyUi03!?SaMghwcv;14S-uuq%>SQFPSC`A^y}{|~=i|6FnY zb?G@vT~_~6W`P}_H?no4u3PZcQC(2PzF+3zWtT&*y*_MYnEG~qUBc;a`!D_V*IvM+ z>)7OfzE)xv$pv>UyZuf*6EZ6P)h0AMwK4|=)qZ$!o9oAd zAELtH3$||f|I+){-%H=>`RX_Ce8an3{;({EZK?hbJDZBlGnef4`XKnVyp(m(>Q?#J zQ>PpMk>hsIWSg{Nw%Px+Nn#)GKhk%!ET>pN50S1vS0@Xgw%( zzxuEI?bLmTwj>+uKl|^?`^W2_SnhrJeC5iItHrrmUogsPKX~>bz2NclkM7pTJA58o z(QQ|hO5>>eX}zZ5^Xu1J1;40XEN1i)W#e*qa=&fO6GOp2YfWnJf4aMl{a1}-y`XB? z{M}otPkv%7-9P<<@;{?gLE*YCi!H?~+t$A-{Jr}w>z|uUbwBR3oPR6qsr7i~kIDsC zHZuGxjczbn{qeNFrJ(1;{d=~Ucd>*?>1~ZV+m@SnQTP14ddq{4lFxjr=d)kjUQW_LrgxGXoqVTv%dE_@{haAHh9cxc>3sAIZlb z|6$i!e9K0s`@hXUgZB8ixyB#FP3z{o-B}#EKjCI-`eB`2C(j?~-_Jesm-M=jdggA% zt6?h{I+ht9&wplcBBKS>cj}U>-w>!!-Q|=g-}!4--q86aA)&vC5b=L;u10XCL+VrTMvRK2gGW z?#TRTuKhN1XV0sa{O9xCUd;H9&Hb(1k}>Nhi3GbTM%B6X9BBWz-9*4Rf0stu`ROY- ztCq)EE@FLPZu?E~PnzGBV++z0Y}wBxE!nK+_uNGYQu*{pOxyWg|ywHQ0Rcp0E%qDy&sqd;6t3Ag0 zN96yLwYz^xxtt2reRzHO_35`9qZt;tr*iK9yl5t?{pZPnm(PD%@~pF5amU@8+AX&P zPC8Eh-uYHn!ne}CoZ&^~it_g_7KAsRV>)xuzR%v0k^9s9m3r|j9A7?O5`Oiht#Xr1t8V-re zDhp;P?mzPC@Q>5eYW~_c*&mw2e$23K&t0z6YQFu;)Y9w~&*g@$uFtBgoU$VFh?ln2 zL9vEkF}^B?4gLi^7MH*Fq1md?G*X#L6k6U6&IJWR?+l!=?7wlq?4 z&7w69z5B0o@6~y@zN$4>UM^3t{?;-E(T-DItj|5x^xlkcS#ag?iz%_k_@~ZTvVPXV z_adD3f0xUx3-`Hs|A9z-H1ihAKb3rcHc!~ARd7!GS=Wbzg1W2wx13|p-u!Yolil{S zE%z@L`ktR~^77WSQw-nF?sEOpqH+I_e_EUS=Nlic8;71){y{uTcn5>!_x+PU{Fbb{ zTR;E9>g{|FcCI^c=%4tf^b=AYQ7LWF#$RVyX?5A06La{`r6O{2Iggm)k-W7GuB9Tg z<~g{3Q2JLTmMd3(CB->)o68f25Qg*YVGFWuFm~)}UZgqc(doT?9bYE-UHQBHY5H=V z>FQsu?tRfNx9#3mKiU6w!D>zW*Rq)F0`I#==i;gDL%@Nanq!x_bl>No3}{p z=zLcx;q-I)-IdJ!KmYP?7Hi}BIMJ>ml+iBiLGuq)fp6SD=C1j<=gVo&rFIXWCG&Pf zl!VlC*6nxwves%V@1GT0EI-Rn9H?AeLogG`&j;<=hz%9>_EAtm17LU`4B}hh4@4BKVH9+C9HVniG6gu|Hk7=b<4iWet#V@nd^GH829u2 z9zQJaHMP$w-X_6$_ND!v>w5JwCU>TtKWmXFT=&XO@c*t&iC=>vZQZS%`A->g9H=ig z%wX8a(Ea0W>+_k%&)dh$zg@pCAhu}US*;#TKYa$F0Gm0RN}{rJuW2T|sW(6K(EN6^ z>YsvYmzg>b=D*+fZ5zw7zo`=^|6lFa|44X`8sipcCoz|lh7ZiEK8D8CGVGV}==9rF zYPZBK-^%x>uL;+tqExoyybsxD8H)VjL)#IDM)y9WcFX|CvQ zJ(i((g?oXQW3@us59K7MpG{x+AGRyau$6BupEfi5V*jFK&3t`rF)6J>?#rtF{VcHP zp2=+zA2{={|K^<>`ybDo_vz%n+KLw{r?0L~P4fS+JIFi1Q$5Vbc!NOZhtoW+p_Vc) z9sW!H%i*hE_#@p@M#6qpZI11cth(x3b|<*zwA$-D=;uD`QL$3{^`1(Gv#L*xri)&i z!6vI!l$J1Y4a*9)4Tnb^ zdS4}UhRj^Nrai!U+8)*Tmed#Df1f=5UiZOt)`&y%Gc_-#ZmD1Xt$v+^-;YPvGhF5; z3)VDz4qukHBZPf{@*5xDhr+i!7oNX9ZIZ!{NV`?X)^je~G)MJtZQ=*PgvA2seVeZ7 zU9ntxeb>D*y@&4w_j}A(D&v~t|JJ@-*gGQQesEEVqs`mq#x(qYw6uFQ>~Hf zY;)!xagO<&Re^Dhwv$U|na*D-vpMz8*VV`L8KvybXKz~CvibP@CA`-Sq|^#(Wf!^s z(L8m^+v?@4>+_EDKi_$(f}tpE`|R|G>lc4GP!Z*<+Nl$AtaNgtJbze3`{u5$8ns!* zJo_%6K1709BE5Ey+x5Ru1e=uDWjwg zw@?&Uot$Gu_a~0iKVD0iXs@_Ycqj6F(2qFZi8>6j4LSP`?p~$C+|}H)K=A$I&W82} z868|{mgU^|V`dfER{;)Z_nA5(bp~7z3js)%pF^5c+$}27_ep=i+Z_DJlKTPlZ z5~%yKN#SM30{w^nA5`-i-=zj$%wgT)?KMyJdEmtR4;Zhc2-SuDRsQi+)OnL#)ZCc( z1N{3pEO?t?9lC$toQLk4+~y^6)*o&Y60JM*bK&3RNzVNd?*i{`XZ?^fYumC_=Y+O; zEonI{|1A2b>;^CEyN{CM{`|CEcrl}1pnmf4`yae#JlOp7^ZYsUo$j(c>Tin|Td?9n zy4>^c^4bmW9d<5DJh?2Db%N7{jJ1L>9+51MQv(>czs)b-Vager_v7uF1Bu$rOWPtf zR(Ab-e=vOO%cD&X9*ESnuFrj~Vei~8`A72Ks!L8y&t^~ZkIxjHCSaSLZ^3xszwz{K0;esjfuPjHmvOLfvZ7MYSfYT(9k9 zJkI97zH#O=y{G>_G@m-M`K-xPp8c0sGzN*>m^=6E)H!Lvo1QY&-I}GdHEN~T#Lr!; z=REtc`Qnkt&vIpL>y&i*{+TDctV(8{FT7uCj@hG``?vphW!^m}yJ5ZA`QqiawZ}JI z-T0^Uc9QY$$Qe5=|M*>QHJo*}>t`Q7KczdpIJ#H<>Cp+Lt62X;&JsFd}H=T zrqv-YPB!OH5;y)M6hGtG#-?-aZ55|}i3V*9`B==DU>CjYZ)d#p0@43Ew;ze_FI~AZ zxo6%N9`932zbE7*zwdtNzK_vHG{bbUXR@p0?DHwvuk5eLc}PX8%uku!)Fyl~q3Uyx zciGaXrF%VcmOfKW+882d*LuIkudK6T_MD_Mhkc%}X}Z2CDcj?AZyL* z!R^Mq3aPJ){Z0`{;a!{pEkZC$uaJl09L>HsyZ(wfKzQO}T3iM$6Al z51+c3wIeFu@Q>=p)m1EY)1J(Irgmv%hZ(o&{{OY!zulL;w7c@}aJ$awEVX|P@>k>! zC#280{a;9XLx;WhkF9&nrWRhcV0AI}p4R@OJCczv_vcipYYTX(4ZB8)TGSw}2EvJ~)#6ONdalq++^sn1jxf^Z?n>w823szauxaOQg=c?rUi_Y%N za&ohun*PgEe<-fLHU7GRYuBe0 zd<}XHp&ZPo(pci6UNV~%aPHSXrBvyl=b!4^`&nm)@7?>Ze}l{e6%BlutsRaww|mak z-(R=kqwZgW#}UT2SleXIN)$XuJhx!c6wdWqk}fhFon!gOq?>KNrr@LRS%u;Xx6&R4Zr`UiQRv5?>8|H{=R7{I_qA7Kmd#Sx;|Jv9&*btxBgs$MH;e$+7f6)>(YUxd%=?w0gx<@PBQoQ?Bu%HD$I!Wm*4s zzIu~)d5K>3J)6A+K0Nke2a+BNoJx+bovv#FUOXK3Xf9_cPh3l98Y+d$S)b4!Pq4nAZ z$Ct=dev+Dd?$GjQnRb?s!$hvIOi|UakT3c;*E?%=We`s^LsivEq4c`>>t_cPNq^Q$ z<96WZhzy&?+i-u4N7`Cp<3DftA3slAZ4sjr=+NgEb~OI%==tZf&?fn@gom^dwKU@KyCC z-T&K=nNp?Gh`OJ;xD+cp-~>pyH{YO2}x?rVG6O`iH`A0EFv zz?x{i{Brsnb$0*R%|Dyowf#6V^+!VG!kt1v(w9@p)Hl@#?qHaj78ARSSIZ-I$&!^j zycX^841Ey#JN@gw*A*d!&zKB6#buUt2241t|3>f3qPnSNc1|BQ1^>9K`D3T&)-J7f zuLgUk_RW#*N)}ajV(zxGAAA@5ZR16`Iu-7V6TJmjD6;N*>@e@^gB#w#ewIq>=KPra zH~Q9pV_gSEx!p=<|5bW|Yi zPt1#BnENL5Jgc+1pY@+af6dga?pIqL<^)!IzSi4+ZL>+}Qtks`TL0gRivIs~Q?)|) z`y54u-}y~aLHrBT89M%KNxnUiHDcDbjfFp6eBP4#gJ12v#m2~$;+?mSv_IJGf^uTA^~wIxjTpKWQrdZ^hdE~3Kn_J1k+Ip5~|(nyv2 z@sj)Z{I1uhf7q7SR$gK%oHK_(Lw7shpXIg-e6l^_&eyH{>#lG-Abh?WqwI{GS*dAf zB;*YA<5Z+q_O(3b5&qP~H_yFqN#2nwA0!PISg9*1FUxmax%ej=cWljBQ-kZf+N_^n zRzI_oVQDT?laO4~*A`t4xfOrDcKz^QzSv}E^vz{cXW2A8?~q}6uzA%Zliv%katbo6 zJ!YI5y+Zh8#=1?jGA_-rj5PkV*)2iiqsOhEGkHR%{o^|I`Qb^2h7W54{&73)nn z8QELUrq`Vz^k}}>&)LQwtaGnzd{dSXuW%>BfA9Jq-A3111(qKTV2)Ohb}Cm`Hp!sa z{oEck!#(K_%zYO%_8rncsj=*$#oC@U8QsoTelIWHJEQEoao4}_HSBAjU3>lCRK2M7 zXW}I$2C>(Q8TN^{6{{A1%np%m67JJ8-6g?u@#W4%!hxnqOSuo2C*-j@1s2Tv$@8c6 z=_{_gnK|}63v{exrbdLQ9$v8PeY@(q%kz^zEL`+4>}JMU_N(>kzw^B|cHWh2xkNAtE3=SQhCjH_`M@q#x7vnM?OHQsf-E)Wfrd-hXaeMG^6~mPDN7q>$8eYBD z6wzVGI(5ZvY3aWYFIUX8^Z4SP>V0j&p-YLGi~)5Ey=Q!wZ#MhfBLDD};{JY^#b>4;i z5xXvaw7rwB(axQ<;r`SIuh(r5y?9*z>ZCRG686>)o4RK?JlHZN?J}2akei)D_gX0l zwbjoJ;-aT=t+>J%CS_q{ez4LimgVw4jWiMO#qTb$I>;GZubHqg?9;?Qhd*rfXuf;g zb8hsT7Wv9+X~ue5$0h#-{a$UX{mvp?a*7bM(zSUUmT4D`H|_0v^<*=v#^Qy?Jzf5U z2F^Tk^JYX8b5=~%uNi_N(OiF~JdlZBWY1REVANRmM`6CAuD|H?^X;|8$I^ei|9_XU zzVMd#LF0<)QkR@gH5g6iIFnYOPJRY$<)8(wiuH8K*7P?KnL-w*e|)8z)cPd8>eCEM*EyU6>qO70XaDzg);|}UgU5bZtyrUB z*>iA4pl%cCdEpov@8Cls?-oJ#|raZs-(^Ws>ag2g? zWZbDt-kA)E-fi2ZdQ8pSo^%T2&Sj1NcHc1iY~l~&U%6Z*KmWhYe|@}r+T8CW!NaQj-XO4cq zI^iAvR}Guo{(TxOVwHhQY$7YYS~H@T6uW9gnu?uV{x$yp^IyMw{_Xs4chNYq#?iu) z>C>H?Ob=ddSNLafbGnjo0uP(4+R>j!ZtYHOpT2zEr#VZPSiiT4O1Y{W-@)Xm=JqFS zi{FQzqLvcudrc2K|2Dxxy|%%Jg<((F2ILqCByo=#g_q}2cvs(EexVfoD8(t9tR zlIlG8qJ4tqh55m$Vce4+^`Ej^Ey?L%l2+!S^`dj~;R9-pskupPQ~Hv5?T_krU%l?2 zCSGROc=Pn)ZjQ{1vyQv9EK6p&e)__vbGqys(*oydQxeZCoUmxdkEtOa^Uv-#E$z;p zsd?rZTj}{{w~no5iRZqz&xl*%bI6ZHdzP}USmS=lXxdcMt5$3k5^)TLb8epg)yX}t z^!Sk`9j03^XEc^*PLv9EQtIDXCEa?+KAW*3r|8mjgEsdQ&0Qe|OT&JgnZ0PWyu!id z&jQP@9=X5rva7NKqgve+*Bmu&cZPYpf1O9nzPSPBpn{J((f3 zOsm=K&eMBU0;TVa!&fER2)^jJnR3cNs;J0K?8GIZD~TtLuKaO%;jzgtHe6ja{kW^< z)t4sETYj%xH%o2F2Bro7uJjqP9pSWBSM$6Q7r8acMAn^4w|ilyZyV>InF~%fSpMl# zeiy;K{I9sc{|752Z-zQlc}%tGZsGPlIOiNwNBB5+6H6{hzDru#F-9N$c-L zavg3O>)v8Ym@dfm=>c2MtEoF`8n`A(2DKSD3f~T?4n39oYVnze>6eXv z%gRWv3wmmJLA*<+(^$jj!_3Fm5)v{QnQqRVQIuZh)gPYuVXNq&={cP1>f7!wGYc0# zkfzlW-kTFC)T?l!)#`Gm^|_f-6)$dRQ0IMe@<-r^lHPgTQj+ew|shZ zuItdV2SJR1OjDx+mX$BqvY<&eWmd4R?)kcDOe+HBrWiH;)RO0rU&v8=dBvkW4o4TC zo*RA4vrof#n%_?ct$6kMT0&Dgmn*T)b&M8stu?Ne9;~`F-Oim`p3>EJ1=g0;dFe$iSsLFKUtsn{@KUu zG@VWPw>KNE-lQ>6FZqmjDwBBd3XZ0nKeTEZAys! zt!wjdsZ@SabG>C9k@+`vuB~YWN0F9TM(n%~ubDLJ7}C!fWEju7=5u<_vorjs`@Gl9 zlUr+Vx&6ZCz5DVmE|t)qf9mzDe-8B}r_SpyJLn*p=5lj|an?K8)hC(UuGp|m7CU9= zv&GAb=XxEd{b$!2u9}ID^w(~4-Flo=<9Yn262I9KLSwZXn$nWm?5$hv-7iY_-m9`O z;+=OTx9M?Xr+~>8XPt-bUEH2~*Ufx&OH@U7cVB==SNvpN9zV__?#8tXmzAb>TYldk zb;w^z#HD)P({~Gc^|l>2$l_po@4%Z$FXBGFy=fNv+qdohACLB!14ebbN)K-231a#C zrS$N5pJh@ax#yY`tiCqQSvoyo(8R;cg&Ul_*>`ivFj<-ocp(# zW&C6~nW<9iYW}?Q)YRSwmL+0K;+s0VzMXciuKIK*N?K?0nYf49he|9f()Y_2xAsi_ z@_6%tUgisxH7b`5X8K;L*z}nt{g7_rAOO!mfl?PYsTk`Ry-krOP5{_I`hFj&fG!KK_haNRO_?!om$GZ z%PtzbteR?aJ$WT}_9EvH*Y55YJbeZ0E_X$3aV;&1{klH+x8Rx{?@v-Zi(j!U-@UcR zKK)pS$^C0T`=X?+w+q!-B`kXmjrDQ?QYeY20}uR3P(%;_DI z;ijdLE4nWFtf<}a!8W(;?5&%hTv*aW47T`J+4>~fG`cQ2rSrhZDDA-Zu$*h1GP0LN z%<6>VR%_MI`f{j*dD8S1O035$Evqk?ZuqX#`}*vMslN{G48E1O?XBZ;?-uRs_m@0W z`}5P-wKKZ!+tfWf@!^O!9r50GqOMnB)_LJuFA zv$3e2a#$4*wA)bnwO01Aj*CXc0g;ZAyGqI?@jVof{kqIA?L~p!Uj336N}VgM)*gD0 zwa`|3%ZC{;+dMAGFrPIu5YRhp^slE*arRnSUqzwrXC~8@lwN)4^wd@7%F4FXDWT@y zT7y`8+}P(yY(dq}smKsvJ_~V3eLLaq&U6a^AzD zz~8G)bP}rP1*^_j?0xk36(;dBv0;CvS+pu{o3=(t95!8FIf=y+SjkS*C}+%yZX4Ob-f;z=Xm00@NM{}lO^7yzxQU| zY5j~;xgM`F&KYMbS8bd5Ii~B<%iW)^EI4K@yJP!W$$uG(!ouYR_f2h`*K_pl@eNk* zLoPbD8eM-jOKRWuWA*1Q_FNK|QjV55_h!zobz3)WoxjQ>s_8P*YR2cRrqP?9ZelP? z&FkdaC||XkFO=ChJuq1!w(@P!!CvJxjn_UrEfKr1R`pNjhm39iKWqv$*Lh$r*7%}l zC!=-J^p#Uhg&tkMv*vo1*V11`{bj<3{xBKLcePXToyvaROlrApjoFEmGeT{fLN31( zT0X^WpS$+qS4;*UMIMM>luw**)omCzb4&V<$Tv$g=QE#bu9d1^_W4xb^~xn1=icdH zm~!jB_TPHZGmMkA7QGQTJJaIK)%EkakL-P1GVkh|DT?f!oN<}cFGpN@s_(t}y5Ys< zrzKX$yG2V)>n`7CWnXMEN5j;<%em=X(uFHJ0=d}%(ax%-T+=jnRjev%XQ`THa?ngc z@y(iS_fvovbymau8Z)>-p? zO}MOf z)jaHvvdlj;-90)zaDUW7bY$6G-TV|tQLJ;so_}a#J%$_N*d1h?)mfLnv-rtoBeBX&iaTW^3VBOIoWoz zzxeTVR(Hzb3Qon%j1^f{yZp06IO5&cmz=q5G~vv_^plHKXGerCImpz1$>F5Kgg!q1 zg1BW1IJ$Gsp1zhQd{H$ba`yZ>r$n1OZ-n(s3XG+yW-OAdtLzE>ou6yH{7wAQvxj!L zi&t@!S>IBBRoj1(V*%4bH3#=IxnU-1SI@6@GT}Td(6?vf3RWwzpAQ$Dj(5*@WL^;X z`8r>U5%;Z?jX4cjc6#c^1(Ob~zqWD9w~}c-E}7Rq#h;Tnk)7vqC-m@_@)JVMY~Ssp zwgrkYsNWIdQ>eQ>)5)0e*w!W74*%O9OLW=KVqjsL%k!e?+w6_9H;l~|2VLM`^E|R= z)e=#_QbuS0^iyY|24>7!s!KvX-&%atM*I03%_G;0gtmAy2=!jkp4-?Y{BKjnEBQrh zyEY%#Xu_zmmRBiuk6XPv_oR70nortK3Z2>7ytUoooB6?b2}8%Q&p}teEPkW#yx=QS z-ILzP|Gi(fFwdSY!{yQXEVpKb@T7b17M|YP=GxI_-}<>|Nv+cHbhg&hLe6 zkMA{c?PlHZ(q4Yg%`#m{i_)D}dBjhBYK#sx{X5x4#bet$`x%*=B=sZBFDg%;b-m<6 z;%Cc0XV$alZtFjI$-Kn;fpO?dHkF@tJxP~LpFPbmvHK7lo9N4Q#6NtELO%Nz%j}6? z^w#W~7PqnN-DVYrrDbx96Bnw~On=s&!xmJWGxeUsfjc(FYvxRIi!ffi@ARkO=l3rq zy8bFV?0@i)&(iJM3Sa%)%aUfC(wTbEtyu8DlIe>@-*9bgOkb}0{nYyDucu_q5`0#e zm1M}xXnNl_R&jmq`VpDuX(gYS?)ZoG?zM=Sg>idsdw$H8%A6=2=D+OX zt*bw#9+&-SCElRYFwOoEgP@F@Z*ukL_t&oGd!0SXz_#m=gWMUOa4nfzE)CzA zduEd8yg1|ckGp5yGn@Z`eKU*el`^{^p_e&wr|x%L-(t&iDNFjv^bg;E@6>e=75-VW zL2FU;oW0z~K5~0|&GO{RPwffObh*m<@#OK7r%J!xoTL=OoVxCl)ngIuybP=6!!mu- zPXEc76!eJY;l+oXuiRLK)=kd|ezeBGKD2j2>2$VZk0n=Y$5qcgRO8kB!T65cX}dWV zx9iu+>}uV#)XHd2?A{VL1CdwH6z8S6|49k|`0DwTsj9oTx^G#uSKH+O$!m<)4!CZ9 zCUcMT7Q=%yp#{Dof4Wwz;S@`0xYHx7^20)ATS~(P1z{aM6La5}t{z5PdgQ}bM47}D z=NtP*?<^3jn|5vPu31_|#(%z?*y}HnX;QGXH|~N@rsoN-8;;3QSEYB}yS`@k{3t=m zbzv{d5?fNs?rT)fUSw7_wM^*qt$#`%eS23%NljXK<+g_KkJO*$<0i7_rOdfym$olRa+5dk{;_x2AqA#6`!9(4sMhdg8oMq&S^g`=N4Kjcwep}~ zBUk)0)1q(J^k44{J0HC7aMj(d6Vka4Sk|kAI!#>0RKl!0!+w=y-M=i|wcI~u?v8j- z|D-MHiL-Pb*W!hILWPc>X9aE7n4wZQi(_rjm1S-|YbUFnJo!?hKQ$h% z{SEUyd$slk9TszY8=@L;>gtbaCo3;q>UPUD<)|&Jki2q2;-{$jf_c^q|GxUHUKXk} z%`Dxa+b3;N(^<_Ge->$a#&!pU_!wIGPR-sCpyXAs{7pRDzthv!HtdW491=NE_uSnU zfuOMED~xMjv1iVb{We25RCBXr?V8soU#@x}Wj{|N+)e3PZG>qMzpVFiX5CpYd))Y& zSFv`_xprOV%`VonJxe0%AAMI0ygK9j+R*z8-l>(P&-=eQRY#%k%9*8Sbw#|3-NnL1 zHcx-#zNtMYMe*jPDn_2Vr7z>X<)&7xl-~8UP+9EN;~sVHScdhs#aUuc|E$*MeIB&sFZ|b>cO`P*Ee=>uJ_5%~A@5`=FS9^b|<^I)h zyQuE`ytn5vUra836gM~0`{)F7$fpRoIvQrDbTzwIsib9EGEO}(J07WZLq$NqH@tEOF^ z(`vWbiYHa+gT|!)(`r&;Rq`#1qGvT-PhVuSTKwpfTL(|g%b6u*dvPN7gY4yACm+A~ zp*qccuj0fhlcGeowFh%eI3n2Y;w-7tBlO@Z&wecjpLv_&mfm}G=|<$lAc2tlsiDRP zXRcJ4a4&nE>b1{mFO=dA$nOB!~=^DF4OUT>~eCN z*aDLX)%RBZPq=(+1K3{l%!*98&0H0==wsnU$MTiwk+)AgssHl+#kGwt?=8F!{M}Tw z&~!%TKevyo=WW|1z_NPFDd!cF{yeH;xc1w-I8w897PEIl)F~b7e!;*^Rw6e)b*K9u zwc-?Y*?Hyk-I?bW>`R`K`Fv8|`gzhRyP?blD7ZMd;f@8((G@Tz|rOW*MPDbu;Ud}Bd# zRni4(JtMaTc2|C{*Gw*9e8IS8Pao^zybQUJS*I_*P83vSjb(6KFzaX7pHSPWrV3WI|PIlst2Si-hH{!rg{E~DO;XzVOY=e zN+j|^^~Usgv=R72p@aA~8ZPuJ{s)StR|?}{z1L8(*h zW?jrl`D}e=op-=u!@eL!jodSATm_u=n+%J8%q?6V;=OVGKAlK$!HF*Gi?<$lay9qT zHiOh90i8=Zx!dAR+oc4~&7CoGTjZ9evi`S^bb?=tPP!=SCYFCt_VJ7vT{2OMp0aHY z@r9D5yRKSmpM15pWKMn5k^Dy1>mlL?9{sy~X7bFB_Zz?U#P$jLPX3ZNC3nxdG}Y&G zO7-U+;Pkt#Sg6_Kz1=nAgv&ZTe0qv$E~~85 z=QWQNd{fV4^-onc;cM$z zjVU=BS+AyU(3vAw>FYne^3kQHQ(rkkOuS#bkbG6KSEyvg;T2zPQ!Xqjs(t45!#&e~ zt&Pv!<yxsDih; z^=%pZJ#yni?>5gCJMj3xBTn1S1c_-HKUt4x72NcHT;5Y)`?0-*Tln|VV9U6<`@fdn ztv?Yjcxi(@f8S%K6=`k(5~VA;YbGT{WZXCKer)KyAjgdh8kY^ zq3Q9$Y^zkG80(2hljeLzxyNc>Occ(gWvi|Yys+emCZ|Dg^z2F@qu% zvfNqBY`;{<{EXXrVh&rymoaRR4>(bv$E5z$LgKw?v!G3s#GRL`9j^R*#w4O?dOR<4 z4y)L^iQl8$#e37zy=L#fp7}Omd+X9m8S^^ocM5-al$mxRD(9{2i%5=Dt6tc(Hu);G z&Hp`{PrYfvk{zF7WZQendoua!B413ERh+nXNupAOoLiuuq+wTApN9=|ecY;Q*^; z#pBhkvqN9ZZS#8)`ovdEjcMgUQ(4DKjt#31PBq;uA^2L!E_FUn_VR^MMZ7})g5H-e z|EB+O%EcHRWtqg&Tz8B89!^+r?grPJ<2qBqdEZrjx|-Ou*`0~eFk+z>yHxn;SKoFU zv0h`y<;u=;={I!yG^_aSWgkALuGmT!*INzq`DQ(8&uZQ-cqV7jNyT5mCJjA1o-5b5 zEsJqEa%9Ogr~3?=Znf+D3{TDr<%_XRi#XP@Zy#s(M1}4Q5ymZy6&r4Kwm6?CJ#tq4 z+>WNy>p%ahpVVuJ4(dzfw+Xdim0Xt0?d^YIrqk{M*DQ`Vb)MY0+zaxS*>C-?`At#h zUTpeKJJYmTPcEiCaM^f@wc+N46HIG&mdZ`OZ*%y3LzHlB$hleDyWP}}SXtFB=!$)o zvSh(~gKE2{wq}2(N%cGSv(!XI^q#1$=3Xlp`b6>3jy*O4k$;&c?R2SQtJ}+XYFGRx zle3F@So=5=&Q7dWe&s*2D(33Zn-SCJ$f}*=+SWF0XRK%F&KY@KZ6Dp*6SMAVOfvl} zWjayUbM-p4>6>m#o>p`XecawX^D3{-MCBOAos}D|w_cN3koRC!h4;G8KPr1Ar}x*- zTi)Wdm%&Z>*bUZTodx+<_c-TGeR9C2Q0T|b`F@r&RT!@IzqQy97O}lIcKR{a5BoeC z`A;VE?*As8Fk`ouro)VgzJ2KiyUR-UUgO&-_=D+->Y}*Wnw1;xEfY++XgG!8@>Uz> z*&oE8o@rS*GyUcK>vPgyz5cMM(@Mf*lS=&W-6nNc|9tSAn0fa=X83--cEdwknCg{u zKSTvjs}ND;ES$MTR(#6-DaSjm=u}_c+|ZM^lGUYZzK++X*Dc?=|BF~Qv+O-5@-b@5 z?V9dNuAh>1xiM$9{xqCoRn}M`Fn6})!_EKZuC71ZSo+JMf@RaX7aOK5U6Nob8MI-7 z`m1wSRQ0nqP2ql?QK;FLdP0J8<9m`U%6$2|{tJ>QnUj<^}Bvo_IW4Bowh6Z)%6vGR2`jvyOrHw)rvVuI=0gV9QaG@E?-qS z*U-mnIax1IGP|l3W`s*Dxt#HS^&IZXc^>ly1JtS)W&a{^pO)Nso(fzM22zo|5aq z!UYW)Yc90ezGdDvPwdOQ=_}h7I!|9Ju_MK|BR-t@*rCM?f-k>EENsuc5xVkahFG3f zczSHnUX2wc#}d0M4vRIU<;c~&a=P}cuBK<1)6dMRnM=Jw--RAr?qGT2E(6E5(6Wj< zkwQVISUmg_Ojm~(H;IxC9p;xuv#VC_R6B6;L)w$+n)3oapErx##IfnB`86kj zNzqG04P#_;KPNq65LN8GreHoZ>((v?H~z#H;Z~tfmx`joVvB=Y(~2|h25!2#P9$H_ zc!y&Y*Tbn-+2)*H5XT{HS~_{dA?{!CS0@K~CU`!4J4Nv<^U5#RRc6FRehK+$l-*gs z#n9)r_*`9v-RYg8`9VMS%<8S<{HlCfWolg3r0BCVHrKr}sZdpN-s-tkg+0{s-x8KU zDX+(zhCZ9(Jx=rU!)t?6>-|1 zcjVdSxAWVftjhCS98Nmia(%o|bIbChMOmx%P2C$&?{zagR8nRAr1Puwl6-3GUmbYG zlv1U*d6IqGo=x6UdK6E;*67}TEqAT=XO%M#pC^`9Mf+y?s2x{{W&FeP`Q?t;>cL7P zhKE*$+rH%V+m&o%t-t0%-;t^7uU#+wyY~Bi zOlDbG*1qVT&xUoJj>!d%CwTw2#vXmu&ffjTQ)#An_m`R|Iv2i(SG1Wq_ z>k13|NrSwFUu$=-y?RU1v?Xz8q<=$XxDA74V?aBL{r*M9t3H+7-KD9h*YIttQnp9B zQ>E?&--vTH<))fTf=Y5`nDRb1ZRS7w!gNjJ`gyC9PjsD{^QU_9=g7A!6JC2QG`aoe z++{BH=P`>nz0<1Ocxh_dqMID4SB+SB?XDkka4~r-q$za#&uX2pmqp7Z|9R;)Toyb1 zizVxO*b`Njj^rB?tPY&bu;u zeySBOh*-GD+M!YXu=cAA9_t$mQn(DCMCq|?UVPb3D>vO|PJr8oGamzv#%I}_Q%vL) z4@x_@%PVo^>uO$$z423DH9eWx%bu7p>!;ju^;HHxN;j#qKKI~`SeazV@Wo4UL49gY zPL74qk24xUNA@hsxXHb=Pe|Kv-=RkdLdIEpR$rONHlO{xUU^6tX^7aza_YKqu4c zBcBe>p006Iib181zpA|Izd-$S?bU_P_S_PDC%JA%%Cipb36pia|7fKfuX*#*s69UT z))E^_0(+E*t&e2_a+{4-C% zs$)F+kIfNX&+Ap6x5wBuQFjB!qs?B-GNvh6E426i*S=EDz#iK5U%onj`opLXVY zB>aEPaU=d}>|NW(^IpArS5&cV`O^|#!LAR&44k{J zYTu}1+{-kZM4?C2MX0 z&l-m3eREbgsLs~7rY+mTDP6ct?rDl}X@jv{qMkvWQLoT3`QoK|a?eiaPX63yxT-n+ z)Blt?ON(3PZ&1?nbm0oyCB5O$!mn&*NjHqpuux>VGDDSQNq$ zlX~=O)V-34)`tym9(!a_G^IC9NRCT1?O3_OGWYJHQ#XHhs(x2^^!Y=CZ}35ljk%AE z>K+N4NzZz|_F3$jIX#zzPHOB^sJh;HBJbIrj%^MuTeM_8AH3pOwp!(3)K`)Esrkkd7`2?VI{E47WSdtf>imze&P@$V{ZZL2{Wh5EQP7{m zvVWBC$#1(gnbkQiHh<^h4Y%@gm8aEi;LJWYL*|LXlhBg$2bVu8U|d_UBT{qa#S#X+ zG6pFoiJQ5*Ew4S1YT2VXxyV7LZc_Y(A3MAMaM#J{Z~GRTp0adF?A;{2{Suc-ZXbI; zu}LE(`efva5Z2Y25C8M*dm+rVv{6y&!>3#g_AQ%cp7vgB(=2>$N#epeym}AjtFxYZ z;9m64qWjtk-R!-B^UofB>1=Xq%YV+PT3?hx3)L3R(PUngAiXi`Y3b?-Z)MUNia2$; zPICS}F{5pZrr(Ej@BcR3vnNh@y!@>1iz&N~?$Fr$`C@$PmnrVfg-+)lsQmB<+1ipW z;lJ@YfnptmkctmET$lEm0kn-;|i2A-Mp)o`NrmZwe4Qx;06os3);=FDh6 zJ^fgw=Sr)hX-!W~2Y&DT^0+D2$ohiu{oe}tTWL# zts=GgQR~s4?=2V0@68DRr8ULI=TvdF`=)fwXKU9M_rKcd8p5oql=;HUVPm0J>)V2N z)sZP&Tc@`;EYa`0ZIK}}d7{?DLMufXWPD_ zj}P^@{@K#vz_~Z2Z~G0C<$Jbt9NiG2={l{vRXSN`vg@|* z`l&mZdNyjG)=4jNU3)`z&dID92X<6n>{>d<_3T7ryV;EvtBxMOnqFF-9LLCi_hWU8 zu*8GQV)req<2H26&(ZFBX1274kyF(uO2GbBan7y{8fp1jeLo#89|`5i+}+%{x!J1X zqt$|&&rM@pv)^oYV*gO0Tq(7Ar$-p8w!G9ov0ODT3oW(n&o1-bd{MNyY4ynm-~8;P z`#)a3zUF@NP3s#v@{NK)H%nU1U(!^PZsL<&c;{@yxA^Tl7u2|{T&g(TXL)1ZF5QOQ zo4cMEeW}>l#P9c6gXR6UQnxLyx$JUJTd}GOe7w@X@m}?0|L+dpjxW*YF}n0kP%E@| z_+Hk~Z*136IKV!ajyZ)Jxdi%*$i#J~8!kbT> z(d}xw;O7}8x?_PO_uM^&DvOrrPT`t&d|Tfa&h>ShEDC-s)e*?j(vr|{oU|>6Ve#R8 zKYaGPyy`s>^6aDg;$^zk6JkG3Gn@V_qwwhFouA`2w@4n;-=gs~C zsUi_;Hi(LO&kRog>=K!3v$KoYMx@H+bc&zjj2VmA6(2wE*|bd9e#yk{ACGlPji2n% zGXHaqAtSIi`P-o<8cjU*-+i8l*;W2@6bdPvclnUl8!?NWf7ClOruhmfrKb9}U)vG9 zqjDz4<@z0WvUHY9e!P~LlV~iyPx1I_1DzX_Dvt$z3E+y{(c>3*`{+k?>6zENRap(D z?cFw$-$l>SWoL@cXQqv#VN1gEc1`g>Q2QdG3u%Ax^qp@ z&Zy-G`&lu;Z-&#KWVp_}wy=v~immu0maHI`wzrXia~|!!%s5BR)rRZG&Z^MUOH)4^ zCe1u4X}UBdbTa=@k>tn^>058zxzQdpWxf-akn6&$%{zR#`!l#d8d<0oc2tU=I_KWG zZbIm>neuDOmA5ZXXM^y!%kX8dY4n{a#)%h}vj%FVoAGd>HH^R5eXnQ1cRfmXiS zk^r_=DJH8$?d8u>WgXOyZxFt;>~g;A>s?m6f|yl~&-VyTFM4l~AnoPIYPVp4=IqTy zf8r$TZ(9~jX%sJ78*1}Z&1zm-K}ViTWNSH*7Ow@Y%j zM*o~tI{WnVi#7)ZR=g;T`~5shF6GH(COP?gXWuHR_)ZL}@DAC{V=op{QkHJLTIQ5m z!<^|7)_-ol{$Ii*uevckFexZfr$Zx2@$`)^QzHs=<^}w(%$uAtqcvjXS(9Jq+D=$4 zIJrFH$jyy&V{9jvbyshhrz-2JsQvBO&w!_5(T*z1j(BBP-TY9!W%m4F5mx*3?nw<@ zU9tg243w zezoPimVa`16w-Qns&ij13-CJham`{Ub6vYnb7tv&crN1kbPoIT8G(YPUZJADjUK36 z>zLND?W1|+UD?|9ZLb?zdP-%=?p*c$E)uRfZL!eKNo?01KQDZ4rNX#$;$^cx7KKYq zb}$RQW4P0GuAL#^i~6!=)kw|VJM|CNY+;kA;}(yMGMT%n*oejcluV!5kvYo`6qyJ- zd2(_=_OX4EoV{~D>WBVM2t61iEFK*lq;yf%>X`0P+ljuGHFg3MMK-@!ve-joXKU`m z14mURqvgh(NbeozloY^ z{WF;c%bW|j65Dci1%153n!8S8s>i}_V#^gS{fZ7N?YrGpn9wCE_91wNNsgzbs+E!g zQ)A@ml_%SinSwvwzx^R_^Um6R6FX%6w=A1uq4xSk-u!mq$G&>6)Mo|?zGdi{dwXg@ z*pluCi<%jJIBQ1suRbuN)7Nf4i`SARZVJmQk59={Q(x=4$#)8`N}gG1!|{{4Yt--f zt<_j_)u}!HT70x`zI|Pe)=uuAIyP4RtMiUtoWfDN`wF83PyS^=gOs)tYOaxu{i*XV zI6lfadO@&#ofpqk$Me@1V@-2@g}zZ*y2Cf`-0z3Nw+_2W^E^H=lRd-dQfpFErOfn< z!iPy-rQDw%KCcjQwRzB=`)ATz?Zu~r4?q@>FIN9^5snBdv6`%(>}^> zuj-NUOT<+sX|+)Ixx$;u=-v+GPd{Fu{zOWD0?SIll6k$BFQWUaSm?S?;( zI#~GqB}DG6@F6X4!3-%m9l-ZvNhvPk8_EOjvQF#{aT}h zA>V4@-N&5s8wF3jtF`hGKD;!f@P_NerI!~)Ogm5@FJirK%AM0+O*}V#He7yFF)`=u zrpgH?4fk98x3rg=x4Hjs;g^?dcAKR>VLK!6w&$u+XZnt-ktGp^O0J#X-n2}}7T8v~ z^YX*=&n)YgbV%iUKEENI8GX*A;|Ygxr&@c-9)jO?`9G-t=RtUSvr@uRPmj5|)o&2D#gvru+{spe8A7Zw0OIkPII&18T{WfCa0cI zpPe9Oczs@{Ma-jV2AeZPmIZQfyKJeR8mu;R2ajuat*>2AtIe?)J+CJ83k&2=&wJHX zv#^CD;%abG_L13NR6J+wzMtuQL_YsvzS6&2aev;-J-S1EdbrNXZxa-Rr?V<;7G$@5 z_;}47L6bM_okxB2V$Y<%H2i0lYVhP$^TWya9<0bZR2diOllo@1%!dvON!K~roCkJn zW%#8&?W`8-{jfEmmN_Oj%>ViQo0`VJe)Yx#hr8{Tk~U>M^J~R+Hf`3-@Gm`cyCUk* zOfU8gQkkDEJq(XOIGL;bVWv;wpFRBRTp9B$8CuHt7JGa>BviL<>a8iF>0QrVV(c|1 zepG+0_i&Gfe&+kb@-Ed!kLQ>Fbpql1^DNdLSq+YjrX^+3fq$HE@$&&-`(s7Pp17m{xHUC>c<7rAB}Cc zEg1(+V*XTRTl(`4aI^;Od5f44v3IWTQXQoiRwRiDa9Z|(%#`M6En(<5ur zx#Jm^7CsJgHs=z$>FLV;pQHG~n%*BQ+3PM|c*dkS$Lu`w{YOESAvT>k@5OQ_rxkBk z&ABP!JhhZFbcct=a{Iiqdw0HWxN)CbUgxFQd6y`cMaEYO%X!~UU*`NkXuH{iE8K5C zKDu+bXRh+S9=F*!9UD(ZCOlVPct<&3PEA**@ZyujX(!XNJ~qzQJ;}rOG+;qlnqSxC zj?%D=9jy7KDasqKPV&0BNKy0u>?BrQ&#dQJ`W$lo&Nq913rv)nmSEUtux{d_CyP_l z3{#_p_6YqrJAwJA+|A?|f$o?%pMEmz*X`fgds9Tn|=H&r(FWZ!x8{Bq?&p^(LTOH8G1Hb@)`Vio!C{H$Kc z-nCw$Ub^|{rdX{xpEs&(ye&WBL!wGV^Ga3k_X}@tcV^!=>7dH*ubI!Kw%?i>eq?F= z^caWTMn7Nlq$#xbnOPQ`wshJue_EH~cH#c+tbl2gLfRIr$mE{oZ#Dv zKRHL<7bXOJ^7qvJ_%T=amdl$foW3i>mOVRt@Zm=9%}2PVzX=Q!F-Sb?w(?O$2WQyw ze0IG#2Z~m@N=aKc%uxxFKlIPh*Yvjk1OFY{_|>0ZxW_GZ*X;NU%ZSs`Dh5if+5CyY zn^vk`Hhb90Z>PNG=BZVjTQ*#p&C2`y8I=si}y|JP(=MWLHj2TvP4+U^!~yDdoAQT9o@ zX=BTSkQKNPrM|WEyUV8Ow@PM5Ifc7gKbmwyMEH@Z>nj~g53X7U zzZaRThVOMAy<5~!6s%(^9{b2gw8{VWqFL_(t^_=@+h=g&*u0O&S6&rcta9d;VP;TF zPk8IaS8hA)mbWj8yd&a!HLtLUv$fUJiKS0BWjEh@g~H#7Pb3~{D3t8^tvliH>X#lr zCj`sf*89a7$tSiy z=u+ME#9woQ<89xtbCVQ*Y}B51T>H$W%(XS_vbigIQ!grUZ2IevbFA>pmZM)c-PH7X zQsX~yP0<#O`E07CSEGX5WOI*;g+9)D{77c5*@JDJPkv0i*_D1ERN}uMKZly;vkpBe zv!$M{e^;D{5_{cs_hYf3cwpjgg9V=#vDS4L|4Y4ZAt|zsIpya>UzSaNKmI&v=$poA zFz3M6_7tNO>o>QJZr-kWSFKTPdgI8$r-ffmCcdyN@i^4x-=_C?eMN5t|G#M~RO6(N zJ-z8+Cb(ctuF>>M+cyZ~THx?>XVer?)j(B#|Jsia_q)xu zT5!nr0Qii@ec!@W17C^c+_AA9uy{IhVTZ z**{ZVBKQ5WM=vKHarDdy%5>73>al#<^T1Ck*5{)a6@0loEew3)Uy5? zo((P9b1t#Xm@)a4W_;+Rvk?yp8#z)~_0-O>w|tV=euwb@r@rLzb!lGR-G{dQbg9_p zbytl~>JQuF^k?gBI^~NcS3KCPt>JeycgORkhcZ-zrn=Afmw8qiIp>^i-?7PM;y-+k zGjQ&Hwd3Sg)!&w$>k1rZFh5(U{j~F!acAm%(a1?fDTdSEWt>h)pSDyuOyer^_VX@9 zJr?V43D?;l*0-H7pLKid{gXUV)g>o;WTH#Hsvh?Eq<&Ya<~D0i=FXW9*{3+4-KL;k zIYCFjdb;nyGKJ%+mn#>|(GyI&`Y2<;&VMUayj3fk3TE>L-ufh~9<$MRn?S>1g;d|0 zQ^cR;3;gSP%{XgS$exu63@TsvTOBLPt7o5;klGUwru=e7;Sv9jFSm7zPq=e3OPf7L zRdYeq1mAUSce!?Mk(@7n;n@ejLkr#58_VXH#Im#O*e)*jyj8`oiO24(6W7vx{j2|V z*2;KqTrlBd^8TGK`+wBl+}~yYu=uyvkDvD)yiU14DM=QuxXGy=v()F@le|v#TY0+| zSO1vvZG~*dzq8qnNwy4H6?0FB%~L!1a*5_|L00DFMdsWeGVgkP6WpBJxk`Ns%kCN5 zgDmGQ{4@1}<3g!3j?R2_Uml-GWhxRay!S3dqyFHJm-}+9T7{ddRAx3Dx49Q_>XY>( zsr-c^8qaGZih9J=@)qCp>UrolL9O1$&*eeXG@p#0$Mc^03f-Aq@@CnC<)yiiJ*qzz zRveyGcCV;<#jP)^Cw#6Ge*Toj^Vq+*15QkP~Z*!KN@(6zOs*SNu^bMM2lb!zjsc`3_O z2i;dc$;GhaXqwL_v6Hhl+~B{f@6{SO$s+pT#8p|kI=|aif4#rG~f;-D|w9;j0)R&l=L$X9`SwVtkE z<8%F2`=WKjy_>UA3)VFqpEck8WGGwV59XV`T6}!(Bkte)Gw*SKMq-mV@11LjGZ&V) z$hE$7vSW%ci8#$D(BEwvnCCZ{e>1=8?x}auO8!3WoGA0=%*)2zx=vZ!ixZXpIk>E@ z$a&onfAEZh@aC3ynROmr&&^e>m2Yn6JFsYSz4*2}A6L#hEMLGU@b>xCwQW4}KMTb0 z8i|QDa=6%>=sC18Q02qYqQ(-2`R`9HoihK>`){`rUzY1Pzt5ejKV|FVJsNp=Z5JQP z)OgHs-?q(r%Dr9A3-5pG6Pq4PMO^Mvq>n5&m<+{kK zv_EHm94^?d^nbESYtXibm-Awby1nE#iOwot7rew@r=@oK48}<=UEUSCeg*k$K^J@P z%scdTOUau@EiC(M?5&OK;~dWxO6e|9yU-)_#xgb=4<=z0aSQ3##~K9sKcU%kQf1pV#i+UN<+dw)zCa zvYV=zb(yoQZv2-2rZ**Tzwh_@xF6N8ufN=v|2;lVjcMMqJ(K@Gn-DMGdFk!;%w69< z|CO0pm4BfBiqHDZ-ke#HC*Hk}!4_ka`(tMSumwym?{<}>~8`*ZHzB#~XygkD7Z-o9+GZ^seinH zb0b4*@-E-i{_661dGxaD^N!2Rzw~MGB_*a`zkgZ%Ha`32@bX#H^6naa?fSgv%j!oz zPT$`0a&F2W*EgochBFv_PKWQz+j;M~p4t4v@eN_G4o|C0CTWEzG?y zJ@SsqxH#|F(&!(vS^u!M9=jfs-ZSmle*eA8KkQ$eJ>}VfOJ_Lz_g>15%1HPbd$7g- z^bgnm3d=)pIrXNSd&f?kw*PKb^p7_YQ=S!kV)Wx)?`tkww6-EvZqA|JJ$p9)cxrWh z{Zai{t=SX8Q+|mY%~-g2-QE1Iep{iXtz{m!yDkf>AC}Xu^>@Bh`{U<2-~89y59;%u z?`-{-KTS@-e$T!B|GmYF6OMlReA&s_#aEQ)+FSFbVatAo|75+nMyoDxQ$hKM<=3k} zwul>2YfD1-N8@c!AEY`G1o__lBUAcPAska*c>%ZQA zsQ0q$%PH?_rbiavKDcCVTH5{{diEzq%v!`!UwS&9{|r zpY=Okzua1U!h`!&L7GnjIA%=Ef3U39bM~GIT<3Lu*M4E$yY#qtOHS2|$CuW!f0+H+ z>3-_{ocLYOzuj4-`+QDl=&vINvM!k)W&cl1>)CMokk6&M|Am<^k7`%U_FI!8>vjFj zuK?FY?B?Yq31Vioxi>6!%YIGyS7u+A^{ce(tnigHY^zK7^UqJa_xjDdFZG*_eE;@# z9Z%ZY>E>@Q2)q4+@ z{!%$EDbRqjW|6uch;2K*Y7aydb@B>&!tD+vu4{L)pxyM zR;-+4^2*5&wCh|8j|c@VfYG^X5J?-Mk}p;@X>M zgtL#FmNBV2bGfPhKC?|?#*&&Jmx8uW`?-H+o~4USljr*N@v9%t&x^aLUe3GVn29RK zkwz|&|C#@0J6+!Yo#D^%m!FFiRu)VSGI?S(UHs{bN9#Oe=B!=6Xv>dDd9^dlH<;KR z(m&fguaD=O%O4%xxX_9>r9aR6Ot*O&zwgo~&AXZXrI*g=dKdQG{hfA_yYk;ljVIk{ zTc%qU?QVSVx895W&8%~`v%Z;5=`DPf`&Iq_M%@@MrZ*FoZ$8mv=(=;_?tG!sIbyNj zw|rQ9iFpa@ZhkNR%!8lL?mj10*Jb-oVEOHNRon75>Z?3E5&6;N!O<1>w{FBGdz)n!k9Zr%Re@m&4A+=H((=0{Dhj(@))YS(AA{|mmv&f2^9T}GU>dim?=XLEK< zone@L^IP+$K3gA6lVYnEzuuhuGC?P4V(r5n=68Rd+;(-E?FNH0)(8JM{R=Oy-f~m! zPUQrfN0vV-@2r{-zx}_Pf8Z<5C0kUs1PficUcI^g(xZIa?J=_~Evj!%%-ehVU)koz zRrcq;SpLZT_OV;w%u2rwp~w&?UtB?YktP+z?FBlM;6SSb#!;0`TNXM zY_?0w_65bqoIaJ}nYq+D{}aF0eaop6eQlnH*mduhY4l$2UAzB#`fm@mxhd|urrxdG zV6sE3`TH&Hc9(fsj!|(Rr`%ui?vgswvsUZHYi@TQSa$E);%`6HtX2BU#6pYbZ>#;s zr?m6(-3d41ME*3dS-Wz&?}d{4ORas+TJHT(fBts!{HZ5CZ>sN(c5PeoQ~kDi?V`lU zD2KX_m-*6XWxsxZxB9i=yq-|4KlAUl^BybuZ|dE+>F@V5^WMLkcbofmyshUuL6x3$ z+-H7Y;XfHvoAva?%WYzEGmQQ(Uw3l-*I#8HKJVW0<7D~f>)lSuXW#wox!HOusrv4h z-&4*n&u;%&t^50*?RTF`Ca=TKy*W|4*>?Z^Jm*&*?5B2rP&<`3V_&9Y_IY0JB&E`O zH%vR5(~~9hA~*ebyq)dN{Dp7YtdBjLnAh=Ld*!lAuGMw>f5)EFcke&CW7>{4v(qC# ztD2v=w=_EGeRa&VcfTjuTiN|uGx6-(H@nU6O}O8wJ5y}m?t8m3&cFX&Gc!%?=f+I; zsJE5BPUp?oU(A+1tA2Xjcg5c|tJ8kjJ>cfQ`~BP3?WcVA$=LsDW_oOCQhlb|R_Wmh zP>bVLv}lOuwlzUpp3JX4Ht+quydyotnU}fG$S!I>GyBBTx~P4R+!vm?<)`^dFL3>rt=k{V2YqYk zDS0*Nu5Ewq3g^;eD`mc?z??_6G__CrwfZq-zuJK@<(oWF7-cdg%h`*-lJzo!Z>OkZR1 zeqqp^%h`EPCH{I$$=mzxbWiPLU(Ldgy4$P$PfdGZbolMliA(Oz7K^(ny`wI5*O~L4 zng32Po{WPwcAlRJwfLYvu8O zd6Su5M|b~@Pmr=WF)1rBuDDwB&#Q~GN|#*@sCvcr=S<1E-9MME{3YDA|Ki5{ACu2E z`X?Qo`*Lqa$t$)wGu)Qv9q7!2FxUUO>c5P2-m=Yg7IW&HK0k-G361Bz^hy79Tm72X}wAXMWq{TYj%5?bhA*)8)eMKPV2^^_lJa{+jag zXUi9sJU@H=(f^X?zTe)p`-a%7EnRAUwB);dZuPz20kig=T;(NV_v??8L1{jh=!)4l z%U^zbI=?UId)MsPAN@A&f3+W+H`}}H=a2gBXU?cE%DL|UD&@iTOARZvd*)Z&ocH(3 z)~l!LoV+sC-HZ?W&tH1|=q29yvx0s--_>*fb6*JS3XjFf_ug1s(V1f7!M*7~?R>e< zi69Y;DbL<>sS7-rs@=ES_2tgo+~turUZ>x$+q;K*&*SMgrDQ*+xi8%Eg|GbCF8_7g z^?yv6GVOlh(kG9^SAJiqsXJA5=^>Y&^N(H^zWieDyVgL{Qh?MaX7Rlg* z0O=SYO`Q2Hb0aNz7Yxaiw%YlGNN?jOkVrKqh3qT>X0sD4~GU45-%uN=#Ol zXZrcVMIkBa$d{|Khm7aGY+tnJQ)Kb)!_IYfRm;v>gwKjWPY3VuI8Jl#?)S_B6fbvhq;FqI?UewQY&HaBY`a!4W)~(%$9X|xlYdGd;Cw9 z-oES8gdd*2zwEZWtb_f}dsDAyi?I6db;{f_e>R`&G!uQMnUh@S)bSmzFL_Y9^Huo| zd)7aPRXxl8NItHAESX?GSI46}|DbZ+YF3M?+vn})Tsn07S?T9rYd6<_**3r4V(F(@ z^E;;4mA-T|sk*%0ex8wfNALYBzoYCP^qrh6x98VKOAXyW-tYVB_%8H&zk4w`E%VRb z^-cDr>yHZhf36RHUmP4&G5KB1kEb8&e?>$@RZQN0Ug^>NBZ3vPE*+Y!AHr_6*rfXN z(uDLW@AmwRno?&w%^o=!Fn-~`TfgU%);#grTrU5+4Z@e@{yY?uty(@k_FvzZl-J+4 zykq#oeyHl#p$ih9`(!tNeUN@@@A69b!~f5;zVEL8eek?VjsNey{`%=h?+N~&r)GEg zQ}c)S?fbWXZS9}`_OsBx>0b|*|H}Qo@%+|5)j#Gp{7Yfq;lKa;38jB`#cZx0wx0gJ zEbr&W^QJZTllhMCuXg_aPu2c5^Ov1`H@aWFRDbt3>9uA4@&8v`tRIB`p0y!9Uevzo z<>YTRKaT#GU;Bdb1F!Ml%l5bG*2Mh3w6Vgnmfe1TWihuM+y8UUd`s0o?k>-lYnVGt zwx$06k_WH9+db)(6%gC4@c&Wi_d8j)-U)v2+FV}tP>F>NEoj>e0uO9r~w}vr#O6}KaYI`1hd>Hub*EQStvY#tI%D)fv?_Bpj zW`Fnp3gu6G+vT^fj%TZ1zy3$!mfrtgC#Aezw?6B*=11|lTbNka?|IEV?_ZDkmwzD# z`up!5dSCgzbAQA4kPrL&?^oaT<*)x?EZD-o;Q7b)^@sl#ovdAS@&3X6zHuK`aemm9 zCbO0~E&_hxPaWmM?|AH~Rl4&-<%9A+jd-PwKBnKNhd=wclLtcXz^^O$UE)tbFrf z|L5d5C%$imu}$gn-!A^xo4%N9>Bsu}b{&2V_6}AWYlK|i-(kI|`Jr8(XZ4sw~zcg*QRsB%^&i9Dz-}sLGXR1>FbMfQH$4Bf=^?H4Icevi=U;W*xgP*sE|G6#y zMeoP`{6E|0f8KTA&$(QG<^S<+zd!7cJ@@CzkN(o@#{c>c>0A57eN&$IG+u1Kj{ScA zf8RIM&s)gzpIh$fwE6d0>n?8i;qb?D8gs?Nsi)7gU+VmjF2Cou@qTCZx&QU2wH{xb zG22dJzkB_@Bdj)BZx8%W_}f3%;eY+_wQ*B_?h^kWX!T&h>-1wEO6<%6Ol%{)^ckdG#j$Zu>j^|2cFmOuiJ={Lz1s+`d17 zQTAS?|3$@($77!yKkz@v`CM%Lq4#@B|LlLSZNvIM_s3pw_uB7UK6Cuo@BhBpzGh?p zHu3-2Q4ePQKXqR=`_KKB{TJG%+gaxS&#teS^RfOV|EV7@CvQJk@s+>7sebmp>?v;_ zd~e$R@nd%V_r(wR<2(Oft-JmE;rF<%`5F~V6{^3A?fibIJ|N`z%8&mKXdK!7ke`18 zoA)<=&i|b?4atwrcV}Om|9cAaV}7oO9~6E);Hz-|r@y|4!`jR(y?b|Qt{d;_;T-<(kyS33n|GPihqqjEnUG95-(fzT0Y;!p4S%r9k zUuS-lOW1Ry1SRMP$Q=*+d+_m=CzZc6{`}@)@^48}_!Wy#KlNME_JzTYPVR z9mAi6kN*ch;P>ypFC6VT@BhIc6a8A}>nr_PA>(KC&qe>(|GNRl_5RuN39kS5B<)l1 zkNC-kUz|>Tl)u7ypSQ%0vFy9Do0{7L{-*yNJ=<5mnRoDgr{o6ZzRmZ=jM@4ec6)Aq z-&g-!c>RI@jDOYh8orzS+pfO*6mR*vVx2$B&N|M&{$RRA!*<^N2LFD`tO&or_b=w( z-a@}G5y!&$NQf@OJZ95Q~b@0GxF}o z59eFF*cpEF?aYWK$x3?**+0sU%2WAlDuOdb_kZv@q}ty%QT&A3g_A}P`#S6wzkRX& z`JUT3bN23$j@w-IO=fRE$A12Q`M0cPEZ2#>oQOW=F`+SAm|IC|4|6kvg`)Kp8{N~wOfvF$%^J~jA{EsawmUme%^Z)sc z(s+Hb5AW;U1piB~TC;yfobBKFS5&H1Po*DzZ!4=_E&EUDFUyblh0BfST>RF~{y4ry z=3jZh3CVve{@gtH!=Aae^v}b~fBw5#EpSo&6TgA^+>iYx|Ld>+`+Mh0?eG7^mnHvS zzx>}->+%0Y>j!t|e3+m7r$6B38_r*z&;IYedf=z$hy6A6FBg89{GdMG>aqP}`^WX7 z|0cH{@Au4?{Qq3#^UGJ!dwcGg{5!u!U~b;W7X?+T|8dWgeJo%9XaBB$_K)pF|H(U> z&G|T=<3E3r<(zZ>{~MMZ_80tL=?*c>{_+2=AB&mhew_bt{>OSbJg`huU|*YW=5{IFm9@0%a@@4T2VUBB|?dLv#t zuK(3nCTVuQ4bKxf^-+Fn=EE?R?p? zW&0-dB}o0f^65QCZ{6{a_4QUxi|-fy`_Cf+3a0;4KL5A)cID*T|K+#uRx8XE`M+^- z<@yD}{r}?@e^uW7A&T}uM592#rx)8 z{=YmdE`PcCBm1gqyIFN{zu#MYiTwEZq*Z&&_s);Ouj`0uD=*>VLtt$)eav#L9}AEsvBZ~yzk_JjOgg_=h8kIE11tJdzDz9T@t zW}AcEryuh#C|6|OcbAmq|Ia>uMvzV6YtcRBHGkxNmI@z_oBsPl<%j(<_#XV1zjLr& z_}|-~``^!!m-#=tjC@eO$kg`NRIlm-&~Judb_k@MHh=!~DzmCH~3p z`giwt?}77;|7&0N{MUZ`|I{D(zbc>JTWnEvU2G()-2dVDGNXSlRzK8Ve>wl~f36?g zVNdw}@E@(0>R)8>PyOiszHfgv_v`-q81(0O&ZkbT`+4?XRe$tLU$Ncm-ulJpkGg-* z9shieZTmX@`^z#{Hr+GQneX_2Z(`KDQ~Q;-y&_Wz0xza*dB=g#y#4vxJ$-_Cn$-unDJ{LudXb3e}i zu$TWQp5iLd(x?;u}-#1^(?3Wc~c+WcU2NXTLw3 z@@9YkvHjaSFUD1UV$@6C!@dAr(+5B=?S^v~N{XFp4P+k*%C`|j`6um1IXvGKq4zU*gTocH;E z;qUSNAGPjy?)AUkSmQ~c*HBz!{s~6R54Uk=1 zu2=KC@1_&i`V0S-uK&UkH&ydd_=o$~)_;FsF7_@UG%GbHIj`rFnQ;93KLyXzSM4(K zdb@MOqDK~CtNz9P$nGeUDeN6>de(%~Z<>!|5?!#@vPw!=Z2p+38I?t$_yy9s2 z$Mqq(t2p*vI_4z*<*LJN+qL>erLNa~z9;Q$lb;$PdvE;}d6kogR`l4%b9|WjT0696 z-qsT@4!o*JJ$mh#fq?Cg{cYb~U)|MEZ#?Ja@{gZ&f>xQo@Krl??eEP~CRY}{W|sc? z{bBi?zWuA#ubRtUp>cK>Q(gVStMdPT@td#iu|Hj26?Y-b#&}&$eB6)K%!}99uD$l* z*6gqeyAw~?Ty1naQ)u?9BN|^4mQI5-Q?vPvkw;Khw``eO=+#o00{2;-|DG)a{e{@W;GD zyL7eN)t-s@tv73TOj#Jr?+~2lD0-tU>g$!{4;mr@byx2mi)U12zMsS{YIU7)%j&3B zHNB!L<|`K^=355NZTyxwrCnihK;qZz58INo4}8t)xg553%_@wQ0?*tdor zeV!SO5A`-zr`}rZ{XqWd&S#+sZ`7{5Ru(vZf#2<_n61FZRS%uzc_z58-L-4a&OLi} zHHp8NGpk82GlKPd6^ERhyquhTuK!61#;a3j9n7D1czt+5{)EKli@B^O9ka^U8qR+C zcGE)lRl8X>a#`gWUai=DEaz^hsWFQuch7?v@*ax9vH!a3f9n5JHR)}i_pkrQ`+Vsm z?z>(+@4w1+@c+;Ff2kAv`5gA#W2j4ZFEH)dy?sI9whPU1wH$|&+1wPrXuo275`1-~ zbi;=UUmebWnJ9Rrl_?;K`8C7o8A0#!d;d?V_CBb?xQ$KjQd-{GTTbV18+QB%Wwxqp zE8-71?6i1a_5qPEId*@U-Ts8v{|&FNZLMeRZ~eGGnAbG^@!Zdq5id2LOxpir^ZuGI z#d&*`Hm%wn@b%+SR)>f+SCTB4TMT*(rgUrB{J*~c-&x+T4gwC*qP}%IiRo>V1uzi{3hrB9JT+m6+#gUI8`}4?nSH~~4XgF_7#i&jOud=eY8Sq8lUu^Y z#rbun(!MncCywn&vfbSD?a+EF;p7CB5OJ#;@r!h%vZo0ByR-cQuhsm2(|djhwf%qg zNp1c=jeGA_RW-|68nG60SV`;u{CxkvokmSXDf5T?16=Kvjf>9*1vCbHh_t#|ZLp*M zM|&Ypf8$H`+U1TaIyJlpR~V zjCPvJhQ2=N6TF%$LzrJ>ZY$?S)x#W97SGGtBr&@j~XWb#|_K3eu_V^EpidP5j z+_``E{++vb?iBN1_*|RAcEU$qRfD%q{zoR~u8kJ|65Q9U`MBGSzksXB>3V|B<2M_R zm02}Nw7f20Tg1__du8_P^Cnrgn|4=OEd2B`e&R>>bu52we&K(&ppw6g$yo3MTS4Nx zjZd=peDdvg zo$FPrSvRxRwu!D@y&%YE?#%h^eFBG@b#1KX|LZU3zhEQpYE{7fyDea9y~3n)I~gCdUl2O6SyM@syoqDCxCdcW(NRy}4^1 zN^Sci!K}D!-Ts4uGrnbUwg3CaSjAAsXw`Os{r88(=hz<@{at_USo|!_1#H48$+`S( zp8oD${(^QdRNu6ncAryp@CZ{$aryiE_aA&&F1RC+FJN1>_hhkJlWcbbj?IaE@@&<- zQG8Fid-k#OG#q&4{bbV8j|b;QoPB0IgXux2^6Oqt7ENmxM>gAA%yln+X%tN8)wa1? z`D=0Qqr-C!Ej<3Ro_*Ssx39e|uVx>Av%W#l{J}zXqtYq$r{4QEzW+P#`q5>Y1)5*p zGR^CM^;hr*U-f}@ziS3R6j&n|c0Ioz6FI{;!Sc|Nm5o`)e`aMJ{phapWXa(eW(Spr zS$ChFIR5UI!{p^*p{2fG)unvA6ZjVIniqBUSk%O~oXyulb&4kbmEXXg5_fMxCliZv zzb(TmVV+RAx+S^U61zD6m6!9|@7puW&#`3n?`jEO0|(x{jCQ-~WhN;FESB;K50JaU zoK^Ce<$-dQZj{>tF5M#ABMaw8Whd-fb#{|=+|wTiCz)%{ZxRt-ESFVv*W4uV!n?TU z%I!G^I5Z@3ol;B_eP z&-f=b8&dnjB>vu&{llc=$$f0yqT2_8#lE!Vd2f_me1dU@%V9~Y5Xb-b7^>bJtd^MY zllLBz&*RnFZ>0r7R+PRG`O08%T=}E>&Hv8p8RvYNx+`LR&&+Q<%Wc=knJWoC@cbrr z>{b)!%IOD$?QSm0IDJOy6;pIzphnTflLs?J4n%0aVJy~vk=U_;eVtks+n?!Y|D3v- zdh%gnASXw`kAuH1Unp_9^Y*1Aul?O?kCp_O?6Kpq-Ps@Z@k6snMa6+*cRzeM+m z`iz$~T$>+1O3GQw#>yH~p*$~=;q`M?F+i`wHeq!8@Fzda*YgnL zGr#$2haWKgGmy&&vVPHXJUDcxf$)YNvx@RV=NC!0Tx0%zVCw9D3pkkUXIy#kPT`5@ z&fJ}sM9!XMQEGUm=OI?Vc8T)SI)46}_gU_$iwoRUVa~f~yKC-;wOTR#cle^1)!(r! zV6I@TRrnauKA)Lq6(95ZYK@r2?}C>DLKo^Ec)fRR=Ig7gZY3{FcpLQdGGD}UyRu2I z8p4|nS01)qu%fl#p>nakltzXETUEqT%WJA%ejGKcd%%#PRBP_O_m%Pl_m_=7m6@wk zt~vdmKPQ1F)WP~sb&0jS!2T~1B`p`XnkKAxlzfospq_&Bk|Y1w-X#6wO5_6Jgx_?gF z|1SQja9RGCylX;2{=wsn-><4aTmEeKj*Mqo_FUO9>;9~idcl-*ss84Do4t-lR(ltH zwD!8cdjGHNKXIb#zF!Qvka6bQ#E&OMoOvUU@EiXTo4L42>_oFv!ya}|U%SZ{4St-C zzVQEo#N%GK+7dwnpPp5P%@@lO3~Xh7=KWd7?hs*X^Y7{Vy7hDZ?cU|SvHNbT4eJ@T z%kulCNNlP);}P-r6npd4sP-Qd?>$+gpeOeA0ISfAl^kPh>cK^&urc4#Fgrkoiy7L`4!2RJwK=oJA8#!4A z!sHbviT}AhbNh!$wft+B_J4lOyY@+m>6zV}Hy)P1X}`01@S`3VTIlA;tcB_3|T(wOrn@Hln$mWvXH*H@Wn4SvwTAj#>4(C(#`J*CZ-4} z&3eZ2c>9y=MiI%ZvMXEHD(3el+>v?I?&NNB$NIBa+@|+aBlaGB&di%TH;nn;yZV2} z|F>2@XzU4X|LmX#Ij>f2`Y2*IajwaaxceLDzPsO7bs_2n<1zkAWmj4=x36nn6ZlW&M-tmU zwSq$hPXz2msvD+#T*|)b{nRfW539Nu!%SzMuK&;f|DC;821kra`+ldqMgJWHxg@lj zH|BB&%PskLD9=nHcs}nkh0i>lECH^5OT6@;x{f!1nHIYALMcpn&WXA?7 zp6IBu;ER0vAo=4zE@sAZbMZ4d&8EkEY`@z7yQe3zs@?>+wf-Kq?|JNG!fyZ+Fnd@En5`jq$i z`hRC@@3TK^B=z^I?v~3u2eKQNEuL=nj3LwP-xDX6ex(Cb-mS=!{ku=@q}JnVu4j#o zoIywRzp^y~O2@rB{R{*Ui9y;^nmsW4WQ zzFd7!qNOeFao5~+YfOJ#&oX-a+wpS5fs;=p7Qa9KSw`iyuEsKh65AH}=F-Eq3*OE6 z>zL>1Ve#SRQ3ZaBzu}It)x{_KOcEHLzVm-`;FjX2U9R!l7rwd{+!n^aYHwBi;+1!< z#x|d1Q`nUs>hO-2?VkLEi9Qx)Qj5!9R5FykX_S7!_#(FG@_PfX?*;t!J9oWdcVu6> z(on(wuhprQav!G#U6JF`39w1LyZea&)9$RpzZ*-~np;sEgE1qVuqESbRdAW1&uQY>?g-=-@7u;aoXS%ra zt&V9?$NR4rmoAla_|GCKa=@juf01N);tsxrf#r5S3=?|oOhxW7Ez;)Wjybd?{}ct^h&!j&wZ#aEwsirYW40=!D9{1 z$!UreQ)Nwhc~yl&D!-k5kUifnq9^?8uQ`vHqB`yWJCsD8+iGlnC>%qA6Grob&~tK_s}DSHrA$uSh#lH)q@r95+6v^-&$Y3 zcGkCpjAjc~y(vmjU$R?eNn=05AEy()9prW%y}*3GVb(koozKtzZv568*>r@lG4Z;a z@3Na#6TUPq;$)kAT%hhnKk_F|93r;=Gl|NSY48)?!r7X4&OPz8Mt}&&Q+TC zTfcZ7vDtA{K_X?_r75o&zb=0z&Bwn{{f83o2KBF(7A-fHIH!LgF#grgIXqsb8anL1 zN_mRdB&?1a9J-qNOvEqoPvos+ew!xWfIqj}#Tf*&;zaiG9yqo8bG{z;kCP4xw%3n_ zOkX8D>%o^+iLdfA;?A#Hx=q1D@64IYzqT>&ap<&D&PZqd9~E=WmcOdu#{Y|JS?}LB zWM}wb{et-gW9i~Ov#Sda{rUZS)?3GXzXK=C49;6!y(rSluz#c6;`q6b=Le{9`it){ z&2kZcxMKG1-8>%;dxWogmw(h|;h)}h?0J!Y1oci&mz|=s`jz5|}pQT2Pc z96ucXu_oYk^UBB4F$~88->)iM&-d23v7xYkm+Y|)`Q!gDeyn$R+^?13InJ3If!udl?^UM95oO}J>>%J_0u_<{a=SCbRuReK65Xa4+tV4=;GE6mvei%Wk- z7u)=CyPkKr;Di{%3;Txo?Q-ls{HtNQ7>=u-{)b6-*>z_shcL8^Ln_WB zc=>2fi ztXn%L8tm8=e^^h#ub@%P=j5|J8=bECUNA8Dx#h0L{$%6#JGvjTtmd_l-_;lB;kRq`1m;zRf8?3I zGVnWXE$n|`*vB3_VfOCtb~7@zx9b7_ie<&7H6%)=ace5_D=J!LhABmQKUtAr+ zSn#-ems z986_a{JYR|W)IumME0yp2OjXJNiQmzr5(Ngyn3|!fX!Q9Lzv~{<(#Cq#@j0TbK&d9R9xwymd^TmQrLA5gqd-f#$k$4naA!gwH!09|=;EPA1 z<@~EIuAL>=H|gUVmNNgEZ{Az6 zrM~<7K3bH>+}wZuPx%y`DqiC<-pQ#w`@UYf5LCt5@|J7a#-kpVCHLz8>3jU2*%Z4a ztFrx}Ss(kI*w~%VlT$*zzv0=sYW)GfE8#u!_k8Y}dwrvhEXRh63j(8?>qU1}9ChYR zzOSHc>T|tKCGNnQhZQWR$6*X$_<^98GmtGWICN@cKH8Fe98SLhAE~yty5&g1$Ulw+LV#8 z=+wqEo;;?ROO5_5Fn46JwWv?x`@jBrKylNr#SOY;GbNj=n6&Sz##ywBz2E=lCS&gm zf9C1xu?+vJuk9;1-|=kkO4VKF-H$n+MKNiW)bBR=lhGJj;?XAh^Y)Ag=IM=z9CFrM z4o+gbel0$aXDPSPKl{H=AI*>X^XcuYO--+)dldqjh4>lLCOp4yduP?g`zuP1t=f0s zX*qxKc8BkmqZsb2IWFk`B}Go`m|oZyXNGnuz7`pYAaU`8U9pzg&$w={*8jLkvt!e5 z9s38*mUYa3S5R)waaQMI=gbv$XBq<6Nb7u^;*@(JPa{HsH`)F5o&DRQj0L{DUn!X& za(iQ3VvNVfdp-As{{3&>G|NDn-B~I83GeQQ%a^pbYr0O?UdFYHefs=^Ifv#4FJRt& z%_iVTw~(&Y*NJb#ZvHUQDA70`sB6C9ufFQM#=-y*hKl+POV_mQBKNh>7fq(#g(02) zUrz7-&+&t~CpRG@;BTz+&I*Ptr8gVq?F;ZWv7C5!6?dF6quNfD%Z%+op*6w$2PYo< zBKxP#;KihESMBuQ#$EW-vrAk^@snx$r0^!vr3HPhcJYxLP~ydbi?-pF6dlSztU@@eH7KlbYt z7e1-Im-xrL`o!zmE4V(f?D3A_FL20fa}H?>z0=KNFMID=%G&4tbElO|;daa7*%%*$r*SOuDlHR!cjCX{j$6wP&GR&{uiA3qF_%Q%f$S}N?#6$+ zDq20Cv7^C{N8-`D0#@Ve*C%%g-aohh&_jg-KZ4$8ow>4ESZdAc1BP~o-2c2d_TaC< z_sX!tjWLl%D@=O!Fiz~QtT@3jd)~4b;nus6uBRp3Vtfl!x!dLLhHda|{JKS|s@B>d z^mb~zaI1*^E9u(og_Dm}e+)Nxz1f)eYlymoTRBgfSkouDg=XuUf_I#{<7XfknzDGM z)R%_V%uLQ*k#|ELbT(TVBpvQ^_)$D>;UD(;@zC(w$3{x6L=* zq=hU?;Okb zEXdfuI&sC0wAD79hE;|i0=c9@cfL8e|HzN}@ZdY_jP52EHZc4@_JVQ4r=+!3ZJTt` zM5@D^^H_f@xOn);)l&8pc`or1O`UZq2U{PkSu~O9n8gjA#YbaqH-;|Ox%a_ATCt{J zlBr+c@(#8t?s@vO|Sha{L}ABss`Rvfi;@&t!L;iMeNrR>E)FL+oMKDqOXn++(=@ z`R$zruP#ei9Cndif2^3#de7=jPq#g2EIzm}v^V`&{MV|#w+b$*SJ!b}a+>Lvb9Tw1 zXU=Ds!W^INXWw#Wy~g`VVe6Zqi@_`h~t^wxW8tZJi~wHecObyKxw{hP}4PpjAd zKdaD+e#u@1{Vi*wtz*6i{-01FxiX6Pt^QK$)BkqGugu`tdtgqE!}l_kbm^_SdF3H> z_tSo|Dj)sG6!+CAyC=x5vEJZa!a3=Jzf1C-AKvJ9toBakHiwhmLU#;*i{|I=n3MX? z=EO$rODoF5=dt#-89dbgRS)sS_N*GiTc^Q+pURSEo3ce?i^M zoOyEpJJ+weC{V@lq~3^`FTgX$Cs$e1ud7%xW7p+1p^wfpn_V}w_!B$FP9ZDf{=-EJ zcV+M;1#dX`A|d49sw3O?pZ)l`ZuY{BCQro_9#vh{`f=xPmbh!jtDj{XHfSe1Xy*j1 z<2iUp;`-`aI-T8mSGMOLH2<_y%bO=AvZt|8D4?~X@s?5bwvWl%I6MBZT+KIHk+4OpXjHLCT5iE{{sTMmZmc`F;fc(3vjgE0 zUmeT7Tuk10?C_t^AM%dNU;f{~y{BXUqH5W@ox42urtR95EPm@-nibPkUZG`42@&kC z0#!Jz4%!qPoO=DowSQ_w7nUDT=PTz=Ui{#gM)S^J*NSWS%7U5r*xqR$k!{{%%KuSX zj&Z|pgKvBiua$djtM;%9+pRtvaozE)pY{jms8-{W?pLdvcn<8oV~}PNZrU7lyL|P} z=?bh`%6ofuQd6fX7M{Z~SjG?@vsa5^DbH zOX($McOG|{GaCc+dDn4F%to{{?+m&39+h?i`&0wubm+PBNLo zZX3-mY!|hadv$V-^U^B~_FVOU-wXZ^IGDq%Ykpu!*T%Q{(`J2opK z?ux#%DP8Y`$+p9-udZ8~rnBvzu%#mM+y4FaA5!ZN$^Btizv!(+NTCq}BirM}Uw24L zZCdl--GaW&UyDN(_P;xyVfxGHe+~zKc+Q6Ao2w3a+HP9ysP4DQs_|PmV*_I}oAEi@ z3p(4*Kfb^F?cH0VxnFj@{cUo-U6_j_YHQ3oGpV)FGU=Bi`brr8OKmqjATzuCl~nnQ zK$c})ntU?<7Uq=q=>OPcpE&;ybK2amrOdauolRc+Jh@=8Rn;ns2ff^XZmpd!{vdgm z&2cb2(+=xVpUwSu*WY2Be8hbGMm(2INc>F@gr zmhX?he-&uSS-bz$tRp>Z*1b&K!j!h>!{LHJPSY8W57^9bZg||E?e(RoxcyoOH_zb* zU)g85-7nElj0<(2Yh}URy-)l&=dUlJvuEs#)L%2#r+wbM(o);m|5x*Q$TSPe#*{8y zpt?@KnbGE5*43}Qa+0yqk|qEDNIqaUTz@UhXwQkyYYzNq7Lh%B;Za)T(@%fjo38)= ze&v5h?wjJZPrqk@i<>afo0HKPWdP2^QZHEN0!3IknPhC81R{0Wjn)cl4f}1>-*ns`LFU08?xSb%~i_x zY|{E3d)NMm#fu!8Z+!_jaGN2~GQY|AxpY;xs@#d%j|Z8*)fCJ;@xA0DmtW@o{hw=N zet+G5TF2sVePQFiyz8q@te(}C`Qm3lsQ#f7E~i^%TUJS#8T?TD`T6FrU1yk=9Ao|1 zxb^GHIo2%VK_NC~i*J1M4O*$YcHJYr+&2t!&Sj|H*ya6SZC0QAj1a4Wg$i@3ckD8A zN{e`;*QR%8i}}*o(VxO<-Y^UNI=t@Ig(4m)U$>nVuG_Ay$@p4*Tja!t#UB}hJii}U z(z7Uo*GshL^@eSn+EsE@%my*es=t}vRc@73uFv>t_|Izdfg?K=Z|L*hUcK1ssE6vZ zNorR)&lHJ#vnY}?yY?`h@4^M=(kYdf+3uCzcpr6Hx;Nc8U?!Wm^zI#(PvoDuR^ZG0 z?&1NvXPO<}Y7ZK(_DJf#eio!;wr3lUt-<84|7(Bfz6ks9=^@*~&bKv^Nk1~LD66Lg zMX#H(f0g8mChL>)&tJQJu*)?q?N4*Q`2CK8*c;9=(if^b>^Gh)F!oH^@l?WGy7FpP z?xsKW(@#JB|95rF6ye$an%e~)SA>= z{G3_){%zVYcinxnWf}JC+g`LK74$j>x9(y-`tkVh)06u3H!Tsb}qi+G>0|i+vkew|8K7U_a=P*uiUx8P9K@89PWJBz^tY5&#KJEe8HdB zXS1g2ur6`xYxZHP$Sb$m`8KP2s+il3pL<_5SIGP8PW!pjfp7EXXot1a6d2k?1f2HE zvRc-dFuJ{*eUqi7Y3JL;!ilRD)U@}mG+o*hz-Rxg_}7jzjR)5zri;w#{djDyOHeT-^>oy5+1b&Oj3N$ ztR5`qT~WE0Iq>kVwCo-CnZkX=6CNxst#1@#R#RAgtg5+svYvy-xdSdMuM|9<8P)ga zqr*?xw=3h4-QwD%atoBTW7wy~h+p1OdVT$xn)`3A*?-h(yOw2px&8PojlT39Z!%w- zKItswm02M5Lg)S`FX^>mmoGH4P3i38Zd&zkxp@7(Uti@9)aI;Tl*zdG-AaQ+5B-Hq zdlra0HZ?n~X8ynat;C&{q~r;A_h!l3>^-^V-hu^o$I1==`ehsVUWoZrpnTjlzhU3` zDdt%Vf6VOX;qb6N@WD_kpjWuuPWsA;vWP&g{g19T-Tmk;&waZ2%e6G-U+IPyw}#%h ztkA43yXWGCAdN}e&hajuz`Ee{Od+O^QUAlwmQDE+ToPsQY3{>*)_NA<1JMtFt? zk6v4KPoJyzzEa(cov;7#EUR0~ZoJD{?R4<{U#9Zk6(&}+^?m4F$$w$Zt6N?BSa+IU z*&!Qz-jRD2BikwUDN#Q$=Yx(i)D?;hRW?Z#%`SsL;C+uQ%m znvE-+5;^i`iGREQFPX7^DO2738w=(q>#kkZ%(`Ra-zfGpwHbkOZpvHB6AN8$Y1G@A z*xup1e=u?XQO_Hur6Qfj&b+?%{?VS8$k#t>buun6cwf5T*?95CYrP+9?rL`UuTf2H z-)>O2YTw?s4Yi_=E<8RZaz`iTwja;q4EC9Qhc~o!?6&`T`2L@Z^8Y!H{ZF%C;%eK) z^`rMezthtHUl-N=^nbYWYu462?K!uPe$vVgxhKKA?ZnQxS9xMR*KeD(^5CNUUCW+V z?_jJoYVCW$U#-C)D65fwXLH)yW0&5gHA_D~(B6=lGOc;lz8MYAR~Sm<{)zn~wx!qq zcTC1)X~$;Ihv5e|MbG%hWaZj^_qOB)w>8-Y6HZZwDiL-*T*Z!|byuu^dsdV4q zk8$=UzJPANhYIA=1@gB^eU?;^4u6-Y-$n^2`kk(u*~saxd)OpZh|z?9ZgN z`ab58NdnRn%73?AGSQZBj4MA|Q%AG4{TklrMXb*_#H;cI&~?Nk{k)s3(J#OFKlGXvt|qX zvpXtu>;A1#x350X%Cb4mrE(%pw5M@>mWk2@zgrcl4=+yR-mU4{|5pEM+Ku;zJ#x9%0HBK6xVT$LsCR7yMQ%un9f=G~SeP{&^iI>*!VS zQW|ov-yF{E-OqlnaQ<)p1^xL8_g`uHq!hq%jV&TH`{i2g!}m-+^|T-S%J|A^O4Wn) z=ku;VP;FE=;CfNKgU zwufq6NVdPxQ{=|Pe^aMgA=hl$<>0p>-GLD=PD)0+N?5i^@JDs+7x8KZ6RVVJ-Bk_y z+`h>z6JGs~^$cf}dfU92y#?%(&wY;Hd+NleJ+i;HaO8O!CpE4v$WN*vZl`}kEpRq~R@!XH8@vC~|D^%LrlFr_}w}$M> zy1ASPoRy@s_*kk_ap2LZ$9U`oB5u!k$7w6L`l42((`?2r15IJ@d^^VVIxu-UI^ zw&OzY1=hzrcQU`y;akmnzhcgp>xV6PJULnaXZ|SaxZVDL2j3ydv&|p2pMIOvvFe)R z#?a(wp~Wi{^g<5Lzc%Il!qwfJ>c%`_{Lc&zvG271qTMFbG;`%@%MTU%H^%k-`uZ@5 zm+cRS_xuZ+b{(zqWs}kHb2b)rvX!~g69?@jly-kKRbqpB9&NIHjv7nUCM2M^4T5g)D21!L?b9 z!q?R;ly98QY`DMc)i>Q|=lnu1nk@M0e<7sde?G_m_a#4~n_F#S=9$NJ*(9Hw_D7rR z&0=QOS*NdvytQvVxc+vuw5C>2;PDOfmwr`?3eR|8waPX7+LgWBZ`iFHJDG!)^ZoNZ zI%)5opyF8VEA^if|M3^JDK4+>we=xZf^6 zr{|@v#Cki0wUeaha(+(T>$F?uzvT)02mj)~zWV>QUOucocCk?Zo{!xUY;1uWbvtvq z4zt&Fu1lKp{g6r4>&BhAEfU?UTkQ-@DpyW^%2vKG`|vqF*Cx}uLRHCM-bTOP|0lnD zVwB%P|J{4*HvXIMK5_C!*&gfegNI&61Ze6#s^F@LRlMLrzBjQ9>4zJ zHLq_E<)bpvGu+#*S!mzXa=*uWH*0nK;fId$HNU^T&c9!`@}qd$8Ox&=<7ZhYEU)2O z9(CpY1CFpSRgDh=Q{Jt+l=#2wa`hkUc(g6R}B#dFQ})jY%?`JEE`zcbH8+z z>!1DEjV%s#jp>Ou6S}pIioVqjcyC@G@jvYF%NJMm|KF~U{rhzO;RU7DymxZbH+C4r zh9(~@Eo^-1dT_n$%9m1WEO>)umf2_Q+v+q~>|botOKW%YiDsFBg{%b|rP+S*S)DNu z<|{Nj*QENqdb8mV##h@K=4<6FyxnLnxx(-6w=Y>{K4u98%u}|$>aSvxIhm>J`AfMq zCc*G*?z2=L2W5ZTi4s#6{B85`Ftsy2_it&?%YWu~v$o#a$FaZm_tfQePyatE{jI^j zR`P+;@3oG*uQ~HONXA{B9W&#mz*oLoI>wv7OcYF8p?KjeW9l2h`)fp3oHUh~BQ+;^ z&Z)VqT06PF$Oe4&ox=85;<;!25l>0hKMCh9-Lp3R>YTk=dN-pYTh1JY{>RN~7Th|X zyYsH!JLjPF!0yEDhugRm{s?mgoUb-0JpAs(f5l(+j;BMjM7J1(d_AvSALDEA<+J^@ zdRK|WiY(i=CwVr`%UiLvR7kkFzUtyZTlG3w?c&g^xvVo>6{a{!H|>y_ZMS0I*2xMF z?9cud<`KWJ&9x_UqCrGx^^}tv7@H5T@>zb;XW^;Ui$ou% z$}vZL+p+55;)#n2tWOuNGE|8k%jVz<8ifqWj-Wf!tFe^ecG{ zx=9^8Qp>$(<)7=D9<{~lmAhRwZ9};OcI@IP2`#txnm;AKtwZQ}AKque=p2-lora{&dmYI9s2) zUqenv2n9dVzIK^KyJl&|&V*ADyNff^tqPo+wlgr9nVxk?@zo2ryY8+#<6iyZneuO@ zF8=n(sAOHqhsg;q=FYzH=jP$tvzD~2wXjx{nt6GHpnd)RI?>*vhZ1&n9o%(0^SZbX zW5fTQ6)SHz*Y7*?QcB@UdF-A*yCt6$r`~*4aCiMw*1I96e_RSZzqZ^U^K;Ph*=d#` z)@_o^zhBP2zcul}=Eu(te)rn2VusKBxL@Z?x)=G27vJ6(vgg+Sjdk;lYUg=QE&jXd zh+V`311nZ*m+F;1a<`kznV7FdJyBg~|FHYU)8k*4Pqg*?uz1SuHSPCplZEuYF5F*` z%NP{bD|cwOo}7Qk!>tw?<&SdjPAkcKHq+qQd)4Sa>^-X(eS*&F%g9bnXkks+I?>nU zk&C^-X(h2!GYlmcT{XAZ*zKG4bw-xU!o))s-)al$qyOuz)Og##Ju_z0+SIVPX8|%- z;%4mFo4IkS(1Wz%w1EVagYx&X{s8Ik4a6 z@+0}uk7@fi{ zzhcW%x8&zf-afYu`o4ni8eiEK&KuX?^#8W6S{b>C)%*RTfLh7tZqlD_$)7uBQ1z`$ zn}?aFzTWz%h2y(xX}$FZOgkPP6IyeBZ?(LkN;<p{wa)+;I(r9>U~|Fiw(EY@{?vIVP;M8xpS-6{Bi_qRcqV}^DzyV9<6 z+b$(Bw|MOE%^ReH3SN^s6-Hn}TjAHIrtPkwmsFt<%c4L#xwEYKPyhz$B{an>iHCZ$CAsrzS+Js-g?IKTDq44D}(WDiZ_t*Tqed*$_>QAyx+TUc~)t;4Lxc>HBg+%W<`;9NnMHJQ)2y=^D zsb^X~nK++k&$HlZ&CGpU3^?y?oUrw>m-xJxNk<>u?m79o@WL0F0-hs^t9tmh9N4^` zIXn7wMcGpIx^$bYGa-*Ywx9j_!|GaR5L+Cx*c_u6yZK8#`OaiWxqj)3pO60h*9@8e zCqI0(Xg^hAc$Y=#o+>g=Kbc3ggO_FEAnZIWrY&zZN z|BwGTlP|OWzk6X5P6&jtaC;U^Ro2?PVB;IpjSYowSiawwwj#0NMNiePJ$bit9a$eb z%?vZHlDMMU{_DHl?oGFhT`vo**y$z~wkG^h+)AFD<#JoK6n9I^Ez|jNUFdB9qkUNm zU-x(YoriKxFPyRM%Z%dsOsW1!!rQFpd|MP|BKYTiBY#+!zr&lv0;T8Gri=PrCa#`{<81R>)QHy6=fmWy|Em5yHcC%_UKgm&S`H@m%GF--cguR@oU1- zW&O$?Hea5wHA=giEp^;-_kkF@{3X+~W)kzy={j?Ncy+jv(dtB;dZ}Rl_V$3#EujYD zDU#PFFiyQ4d|YUc+8iIPze>}E-s#TX;&@)maj|PiZQ-MJkL91f-n%f&{G+h&qrHVo z*4CSJrS0u`_mJ<*pS!;}WuwHFi8M1b9M`i*w=cv zi{DdS5g_4w%;7|+-y>ePg$xsy&Ak{aevmD(Fw*;je~?=I8y!Zrif=1bN^;+?EZ%MD zYRTHF`0aya(ZP=vlG5EOKll7w>Max#vPOAxMg3LBL)9z7^40kT1ZFlLd8zZzW3}+} z{OcFr-O_sF_ebRRhTIP~uAL3znXIzBTy;zJ%ZNA6HqK~pWtqV0Hd(<~`tAZu{GgwQ9{`R`wCUNY~IMwx$#P_W;qoV zSvPoYep|Bck6p&KthO6pUak11r&ws7TYl9vj{8;Yv*!x4sxDnlI$xBaTb|pi!dPOk z!BvN;V2e>`i++wo$mxzBo!XU*GKm|0@2T@}mo7Rc+Y{V5J6yQq>y51MO zo1xCZd_`n!lkb_v!{1r%$ciOK^BcaioXzYYBzlCK$N@z1w@SMlvvZNBJY z$8I+1rT2Y2`IYZp3X_-WVR=#E$ii;-=}|-Bwc9Z>i-a6Hy(fk3)C=hCR!Z7bw1H#B z-38uzlQv6pHtMY7nU&bZ8s)s<;1rYZKmTR3PDo;wf9^LaX^Ns&X^WDs>TD-l z@%ihr4z*6W;Wj~U_v5HLh3yZIpgazoA*ce>-U=y7R>(k z<3m!Fn6bxWQ?}ItWzThlu;euc~)FezuQ8~Ix9ajZe-j$wTgLB`dqnfN0?_Bhn{0|eiJ?K;OQ5M z(N}*ty6ew*@I3jL=$UGs#%+!}rXHQ}RcfdI_xZ6RlYNwyJgGJGO8sQOvMKt?rRX~W z)sI6Gg(dGOTYO^gt1fNdbjTvYeutTb;hO()p7R>l>icdkU7gYO?S|s9O1_tiXMEJr z>(~<5^1vd;SJwVVCIj<@Ej=?O*?QyFw=Qf5W&XTFEQjmE8iVsj=D&rGpJwGc8+7C6 z4CmH;A348iztK&6l>gq5XMb1U<|Q+@UtYC)_&@4**zLyDG^e?i&wTz0{fkVy{D$%5 zfw}v?r+pCqQgHO5_aAS?AeGFf&(hq_c2%>SIIe!@YOG_2^zcqt#eB6BW`eK-Hd#dmpl)*lk~%QH)LTvMQ1aQ@e34Xf(nYe7|S_jKwdTx4DiG->KfwyygFe_upRy?MZDq+C>ND@|GnPpVop88q?OQgz=PM2eXvIk=F`M7GW~O)4&!sRjF16Bn?(Szo zZL_?lf46-&_uEFJ`qO2~vb#2&@O{}PRUCEnc)RS@JKl>WEgCFT(@q?>S;w_@w{TgY z>Fg(LvumDsX&sPVkjMD!(8hh4Ovbq}MZYEcj@4|hJEWxcYg1au@d7`+GuhX^ZG3+$ z-1W+|$JgfHc00dWE3)jtik}rP;sU#T-A;QfUV1W8wamK5&1H>pSwEZ1FWwo`xfCAn zb?zu$drP@weZ=bE{JOjc@2e#r+&%Pbt;O5YWj<_@yh_aCd;QO8T;RSur|&7hmrvLJ zX?yOAeG~a0Jpb_jRevLH&VRG8&E`9$Lm2KC$++Xw^^Gd(m&3Ywv_f3lftCurL z)LdC^A;BJO!p1*+<8p>o`TM4x;hsO^@7vSy|C_l!osDJSd9nP8OM}>@z{Ck!v#%>H zfB$y6u};ua)-VxLBLNb$8ka|69L8R$I=_Il%rc?Jy(n znOq%dnU^u8^3jI%*S=~i{*eF7lx4hevgvP|Gt+*_XQg~T{w%ubW6?Cb296t7x4dKu zgvW>L4ROZK4}0e5hjW>{t#Qj*q{k6TemNn*DWu4fGl0E4P2>zjNHH5=)+dQka@Dg?8m~^F)xYe zym?>8F6POMqib@wZ?0fmdR2PY2Ihx14wpF=?2yeqwoLucgCuUBWk1)PyD&%m`N=bD zJoqDjWE@WoKgIu>Q{fz6se#b%nV`ISZ4Jqkfn55Kp3ws-=Ax~tyV__v6{f?ZaBUF{_A#OLE||!UOUSJba`Y>Eh$W3XP1w-CR)O>1t|+T?Y)1ZP zrZcl`=g;Q(dVPs$-SgM{KaaDQp7|EpsTDPMSyIp9{SjvR{i%3-|QNB-_nR1@3W82k_|0B5&gD6>AU3HJ-@|X@o2q|`2Jsc zW5Ex(bpOeAFE{KKVQ6g(xNq#{m#+C`;oNWy_vML;l)vc+9}W~Z<@vE>`Oh+jirq8Y z_id?c>78d%WAQV~uAuhEESKAVPbMEaqV?~eU&o%Jh6i_2ghQErvP=yVnEmbW0TDi4 z8*#rwnbUR~%fC*~Rkcglr&G8i?#inL0T;Jzz5A%(_%ERy^_NctWD2b@Yz%CH+pY?)?JF75Okdr99bM2SyH`=~FTc~Y^|xl6UhVk*IX~+S`OTiwTO1AA z!tJiDe>h{KM&#W`5B9r>&i4N?^~@Ky5AJ_5PqCc3_VqVc$z!SC`ZuTR$4ks-kKbN75G`gTjM&)bw=ka2JPQ{j-3C5|bo4^_RN zaUH+AMCNX)-A#M34wl%!4^!sY>P+^kTdel^a*M5|b42#+RnPsilr7dz_4T{We=uda zfcsiSarx+Jp1z`G57hSyu?PLk^h|dCJ~L3LZdtM@Yt7DQX=|62nHhwCeh++DgE5RE|H)ijO&9fJL zHA!b})W^$OQ7VynZfr8v>yvops-icP=*+uzWX-j!+{e9lS+9@Sp$|NrIp;|t2CHvWF=D-v_@ z?W9DrwJ!J9-e)YHlhzw9r<`ZRa)>D;;=s+dGr2WZZz|qc=8(|sbX>|=eAyoTWk-Mg zx>?Djc$)KIPRa6VDQYt8_ncK`Ip4{8srcz#{JnD*T38-=<+ZJrU^eqg+0-%V%uyl1 zi?5@P^=cgomCyS0(E3ZrpDS$5vzQ!oDxT!$mHc^syf|98PkW_i`L zAA9QVmi%}zsVDWPjeS_%w!V|~31@WmR}|VLKUnj3amyz==Yp*)i;jJL8Oihf@6oPG z`Iz<_ZSS5hJ$5;3LtdrV^T~^uS806Qsq?Z=kNE^+d)E#rH=RiWenEQ-;~7@&cp4|V zCe+YDM0?K9tC7<-B`iwq+$82zS@!?Wm&?^$dyW1TUX#{6`tthz{hY@S3%KbYR{!y| z_z!>i>zDjjHBKD-AgeO#c&2`~*MkeOyM7lbPOm$lzD{f74!NSR3lh)yY|S5?R5Wx` zGml>+CwOwN@a{9_-(=L3i!{%!n!ezj zWTxqk_kEd9mrNGC_h9K70~0yfytf~C*aF^%yH_L%&#PohSsK2s@>1V}n{o4JT)6k= zyWQzKv$ikY!DN1&@zc)>2W}pp=d%3%=en7SMPhzgxu$U(>%~rS^z9FG{P81Yrg-*I z9qu1KhDPok%-b%Ub6nGA==1Bsy#L&5FU^@UX>(s>@ExglE6rWiMGpuZX>7muK=W*6 z24mX$<9uDg71AGEExT1J)9r7xMir;O=j=YeMP%Op`}M#7K0NT_m#Fow!iFvP(<5e2 zuMz*Rnwes|rs^=)ODpE?vulhz9lCwb-Oiu-e)6w(3-_L_jdfvg@XS3c)R47NZo#s( zO5$e^WaQ1aZCBYKv1qBb!R&i{44)_NU9jSDy%?{U!+Zb0OQA{A1b59}`ISX{%jdLN zmg}D|J&CS8^YQlaIjxeflQ$`H>V-<|*XKj8En%Wt!E3b|H(5^+0pX6N*k=bcrz9Cm#x`sUQ*4@)kH$Uc$0 zB+aP%`yS(0uL;%_&2N@AM3f{2-?yC`RL#*NAiv45?wu-^O8?4(XM+#w+Vy}4}X-5q=Gfg_I@$Itb+#k8~4&2`##8AS1Y*y%$ zycC_kpFUasTmRH;N2gHgIzNg2FD0v!)+ci$RQ?KQoOS$->7j~A^z=Fz;@#bVCN2`((^JZnte z+dO}%5U@vo$&c)?X-2LEC)aE4i%j0NDVy24;j77k4EKe)3vX_(WZJ*)<*vG4f0rNF zv+JbF;_s5G!JFP+>t8R_+s$TP;Ldwe`e7^2vhF!2KiOPsKOuWs?!o*E&6m{{6sk0| za=mz|HuF~94wsyTjWZv=->p5H*+J>Y#Qs$gRTZzd9o@F&a?Edovm&2%n0S?X*iJmV zf$6FIZs{wIB^6rpPfoHtm*&Un)+X9eGv%Cafy%a7TTWOpOi6W;N%;2Wz-%UVYle=g z0jFLXd}`Srzdy(KfL3mtyx7^ce;@KXV)S_~7#1ggILTl+;l$c^$Ii+s=g5V`6wUAE z>^shHlq?|2{`!#qJfjIJ54g3DKiGF8U|R6|zb|8Kt)uUGFa9aLeoNhsdz&Bke9TBW zU;T_<{d&*wxs2By@Nal`|I>esHs#*4ZmmLEYfn8mr18;h?>l@9X}*wJkF+)_1dW zzOy*-%Srd|&$oZ&e-+KR_ebHSdsBI4z1(NKP+RHMyf?M$mz;4`ayP8-t-2cH%T;mt z@W#|rmu^|PNvzVnezB<3MLAH4b^NY>bxVP{3s+syL zm$R&jbNPnJc4iMdSO1$*@yYP_o759}`p()`v0e7QTd#fp`2Qix{+06ewZ}vr*ss6N zF`sMxh7&()|IS`lpTZb6En~7_PJ#J`gpIMwzr3xC{bRo6c!-F5&_SlDhJM0&>pf2F zuK%LR_?}Ju!Gsk_b8eVj+x=pfgu$#AA(7I{rsl5D(OYrs*zHRvB`)>vG`Tb}msxn? zd$t#vSKB6N&c69%=SzX;on?LVZz#XmllG;nH}Y-g-b((%Ki+=)Z+bm--@c#!JpB)O zF8kNHvL^ojj}!an?N2;%aLL8U$-DgD2ArL6VD+c3oR=T8P2KWCPKojV+L}#^86Ve_ z{5?NK$Gq(NnT(3N*{h%Trl)*A^Cq~@IYMXgtZVHCkJkF?eXq$sT;-WNGlR!_u}5Ln zvAD~(e;7XLI5XoyZ}7DW28sW#wx&&)TU~L`aMt!y|KD={PnB5`Iomu`T=Iag346%8 zw9|DF|0l;7M-{(%xgxw|_pP+a?@k;O-#y{X$*8@)9uJR;C-PoYNaNL0P+ZEheP7mw zKOwhMUVLEI3gXGr)hy<9Vb0oMCzR%U!#&{UJB8V87b`beSt%%ewU54$_V!IzrS_v^ z=2iPS*PNZqe<(7HslP|{QLtF-hCTVScE`(`)iFqlb=E!p{rtC#GON%3e-;1YW{cDu znZXxxJ#u!|4VUKq^JmsDU->NOWNx6$e)ALaHLi`V)gt$|y??-B`b(bo?T0K2c~fx# zSzEhX+HU+hrn6OhZyz!%db7mTbSda}bFrz^uIK7C7w*_Li|*O9BFE-mM7hJ3f-k2eQvb6*KmTHOiFCG~E%&*yD(9b2rXR|--!wD- zdrIoSN0GH>Q&itah&}7eW->3Id!hMDRt#(Ylvw?4MML-a(7T`b+JC9rmz131Uz;G< zw(3-pmKEQT3O4N->V7|Z-~WHV&+wq}lH2n3YwV3x{yx=Id2`P5W|511V8M;Q-pxfl z9qq0+8JBo7h=y%U*L?SJR!9V6Og0yT9nWUFc@o798*cndd(l48UgAu$vEY;LpcSo; z?>J2NGk?Ef`Fftqp558gR$t_qF|RFA;M3X$>1jvLtw~7n-(#pPXE4LR>Qw$L>!nW{ z_uQ8&Fsy#|f8zQHxs@gh4K|+Ue_gJ4R8Qr~-nf8Gs~UDHzH#o&DBskh`1;VsQ%AB? z4rDfM-|E1)rr|~CldVE?R*GcLc32=c-R|Li_rtsmw~fyn`R-$x z5qBGYyD*7OD%@&N`NSlsN&fRc*T;Uwu3PqR*taurviX(A)n$Lzhs@aj;9vG6=gwOt z>^@KRy8Ise`SAGH$uPdRdzQL;nJ!`OPi&~#d~Z)_ZAkf?jLzQ~=d+DVHx)Qsm~lzj z$a@##^KF6`bsM-pWS$Mu&?||~pCO=OqsH1RWA^Q<(@XO#YfGSseuzXU>U#h=`wtA>u^!rPzq|NqhdpX8t4e%9m2mP-euop%|$msXAU*s|vD;}w!htYXUw z#lB9okk)##vFLsKgqf+Yj_8~f%6h;3_UR4V+r0LAi?vnzgiM|&zTrba?8X{*#&7%n zTQ?`snqiS)346qnD3Nf)VZYf4A5FHZR|O*=W|B+XdI_st&N(6z*QhSKlPbIk`zc$J9hg z;qQbD7M|yZPWoC323wOq-Pw>7#m>f{wC_2m)HfH#8NVb~Fn%juDdEkv{+K8CWyQ$% z?GJ?CpE>+rrfu`fdG9s_I)9y$B*G9=-ppC7xo5(WrJv$GGT9C1OC03l+APQF8@T%D zMGLt}tujlx4#u`U++O;aYImdh`5&z@GR%~<`pK11B(_P#S(!nPrYcYX`)yM2epHG+R#$_M42<(|*2taJDJ zFSUu_di+4OY|k%62SwgJ8G-`Z$DDF@W~=hvF@66o{=cchN~V&>2_NlFpXg&dpQy9! zdkD|jF1fTfaVnS2%!})=yJU8};LeZdee=$Vy*_$eH@7OwROm+P62Hocak)0U(fkXp z7MZWydt}}kN$CT>W_Fq`^Qw=qXLve?fyJk8kMvnX-hC^)UL*?!}fz-f;_eE zWs^!T9kS07VsqKz5nd~LXLCb6|m{oRva!Flhs>|2wk&Q+>B zEb35t%g?vhCb8;nl9;f!7Zhhq&GUxNL9Akt^aGQqn$msxi;J znIgy%6Ls_d0=Baj$+G9lLQ~J2f9w^L93=8{MgGa`!&;vwzO9WA$a~`AR4f1VhxLJH zK0>jRlJ_(In{hVnU*6vx;rHI(m}NG@r);ASXVetcj3d8mW%YI5cGQ#`nyq`m8vjH$ zI%%W4Pn5+9b{UP9|3-<6|MOrQBD^tegzYa*D-`& z&O9}#FM+%M&ingM_ZwB4P&d+9=n z8#}iy+QQIw<)%f<4_}j*XSWKH!>ZRDl*+!|Qm62BP5Qx__qkiH{|=LyynV}#w`Z=2 zbl7v>w{&^sn>lf%0RvZ$?@Um>-*Y?YfWA5%I-Mdf5Wd`S7 zel^Kwlk({@_OmBgf;Rup{M%#vLx(l$sVl33_KA0bhqhLF_|0+-j%IY8ZM#}f z8JEOT^Af+a-AsP>T zdEv9PJ`J0tE8BZ7+SGgfF#I2Vy?^#b`-kD1MYi~?lh^#nG-K7lvqx^~dEA(_u&&#G zNz@JZK-)ikoa^?^-5a|w^BG4UPe^N`!;3v@$^;*MZ%@74U~0%WFQ>U}CBr_CrVO*F zt12gXI~L8^ZhqYM;>%APSLi*9f3LDTarvp!GJ?`Qh1YkdwJLtd>-Ce-<<;10kRvKK z{rL_Jhdmd57ELT_o-t$R&bN0ne{ZbYadU#5jMQpP?}l@W)4m*^_4e+=lr(99X9f#P zx72;wbNSJ7sXUvy9h;LBJans#qq2qmFR7A0wx%IMph@|lOZ`Fj$6f48*D%;e+dI5T zJvVQWxl&8dIq&)3q_`Trq}u%sKPdT^c;m*Z^N;$kpFW?{^48}r}@8&)Rf{@?Or!N%*pll8m5 z{d3w}&G+ri%5_V4BSkjf;NxfLHoMr~th+6*-R40KbJd)C?P8}yR<)-@Z3y1ppS*l) zu&zPqLWZ`tt7RJ7q|cSrN?O`C$^8tLa}zVTq0llyI@?U*LLX*+l?E``S=Qa~rqT>nzzyDw}fH!7Omm$NHW$?H@8 zzER)XZ=F@~X07K-PDX9JkZBw@qn5k5?#BOu1s5CEU#`?oX9zvUvCW3_UR9cJ*LfdqBQ9$o0a#}a$D9Ju}frgWHuL>B&RJ->S+0K z-0-fE{+iUn#V2a#xt&uBoTTPZmX>5XYvP4tk3aS2dHK%0AW(A5mRI`K#>0oLR6rC#<<~7E8cCF)i~K z``&(B%v}7u;38+_hEJ;!cTAYBv`+u4QTzGV?O|v69z2uzcFnElA?xo~k9orcUdg;W zS~&YeH2+iOlH9@Y*Y0of6`OEdN84G}Cv(EFLPn{>D?i3OGcovhBc*4e@SfRg?yXWO+|IrF=*tUC ze`b9=C0yZRv*z*a&nrt^WhX{I{vf$nHOFb=x(V4UEc74j{>uHaaEYg>BP*;t|1 zhF-b1<+v-$T%6}b=e9Q}+SmwLrz)m>5Y*A*Xj~`nG4qZ-&mV_&gD~ahJCi=NyuG8! z-Q1O)F8#*r%KVE4q5^UP7rz~0P>j65WbM+m_mt8uzCCa1IFxSRd#!SG^4EgWMZu?B zl$-QEiUcKbJl?kJgzu?|5my-g`E;#%QS&g}&og85hyJhr&2h%lCIww)?|C@kYx(Nn z4#SnY8@hV=_;bX)Z=~IOUS+=LU(k9sudaJd=T}dis`RF1C1<;Mu(S82?+cljEAGW| z|36W5MXA6|Xu{OR)dqS`=8D!W>a2QXAH)5LVs~+K#u>hMk7_Y89J(F9!{m3;B>&gf6R$4pEPlUmVF7#E+ov~W zt~^K+O`Bm|67~1(oknH5reBJ-FB!8Qh<$(fCex6!IP&i!36q6S3$E8M=1*i0b?sit zd%EH7!A}-eM=jg?1FUCO7(aH^U0=6GYp=<(Is6MWAACB)u3ljJGTH9M>qG6K*J^%d zJ0w+XK9(`?VQtpAx3eyRl< zdidO}qyONps`>qM*j>MV6a>rXM2YVBLi7tFllZ|WtdUs0>uK4`OU zNaAHboj$LJZ}lcu<@Yf^#e96;Kk#e!%RjtvMlHYUF{c>Q>+c1&$w|*s`{6CbpzQKb zU{r zj@w4JXBGaPD-u1+C)@Ol{dJqWD%+Z;m8p~n^0gm-sb<}>ab1|EvH6Y_XT%Qte{`(k z*_K$pD@r~UFV{DSp1Kq9;9kpIuMbI!uCKlscKyWFZ3f1H*Cs6Y+_=6@o(GsA^uIov!!#g*(+Y3UAHxU-qb4rZ@3RfPrddhD(K}(sh2PQ1+^zI zy4K8k>}cjvowDHgy9w$OUwcgV)Z*Ih<{I%zqcMAL{*6C>58eKKUE834^XwH%KlmtD z&Ha0#d`p9Zrb(jLiyW>t4jJ!t)?YdL&;QcD`|8NVHCk66uAVjHw(glu^`nvk*^BS; z@iu5SUq5j1s^7df!m~EbH*u&4bi2mEc1JT<=Jdnd{cktytEhgiwWG0sVaY>XuLhTA zOxLFIunB~z?yb!%>t+bO!d!lKVb8307bJxvUoSLOKYn3B!QU?oiJv~kDJ;J_;r+aj ziEH9+OL#Sle-wCr&?;r8_Kx;hkCyCh_554%U;56C&<7^pVoyF_T+8(3zI&KWSo_rs zj=b+BA#JSuWet(dbJlEo`LMC)`%Mp9hW{#dN#CpsytNv6-*AZ>Jt4ElGF$FgNR5Mx zxX$$?mOaK_H);Dat>$Ta!?MiOd#W^Nn+>OX!VIN1k!lxytPa+g;p7vSxT27;L8i?` zjXmX{OeTwfeO`OZ@@EYU)l5MLe<$9#(UAAR`Ak|s*`de%zw6sqowZruxN&M&X!wB_ z>G~zER=P3Y%2Ie0TM|F(*mLknoS5y!Yu0LVQcvycxW0D!5#BEhlE0$ZP8LrOS+lLV@%vMr{B2X#)m+hCpT79ugg0|JUsWHd zJibufAi1{qupBbtwEmsCP|NddpZg?%W$HzYCE7eHU-mAw z=WVUp`KY2|ZK#Q;jeyY}mE*krR>vF`y%0Iue?Tg{Am@puh@rpZ*_gdN&62|T=e^_` z9N$gu?PSiY|MukMw4R&}MLpNkD|y2CTwA4W9}8xh+OPdzB&Zp*LYF&zy~ahMY0GCF z-rOZFf9Wy%j+^G}Gc9Ky+u&2Mvr*4OG-YSrfmUbDK<017lN~Rg-tbFro3y1?=8u~O z)zi+b*<0V4r6sdz(Y|X_o@!=mw|~EVG;U#bN+R#kywZn9Pbhca{m2sdf6@FsiJP5s z6n+P7V69#&HM#atsqmiPX=-O{W(!=q?7wf;3+3hWuggoFy8q_->?z-09hH*qzj$bh zM$Ye~W8V_~vwvr4`?l@z!5tjjH4i_md3jQx)7E;{=VLC}42RE}Y)n42I_n$Tg@+oo zHd9mOr?pOR*O^{7gU=~do_)2A?}=@bnV+%i6@_e`yop)NurPY9UEsxKAK2gUeOrIs zwWwgdh!uZL$6UU1X64hrOyU2#)oA;+0+!cb?iG8T{r-_ZV|wI`o+43RcGc(|5_=e3 zihL^9d}$T354-&C)VZlYcAWTDCs4hPrDn0&aYv4CH$VFJvMr4%HHh^$Vc%jb%FMDm zqw%D=zs9UT_H`!@*PM79-Q-oYMp}VcV#daj_u0RE&Ky>qR{G_@WyvtI~Z@f@t!D4o$mNyb7k7QE9TE8|81U^(!5n=`eE}8 zIyVm&&Xib?ajVy{H^J)R-Td2p$LG%Ri+d$~qiAnu>B*_)n^y_9y?v1~$Aec%>-KAx zb}9b|tCE2pn=}gn)Chm$pnS}>SHZJBDaqjH3Z5FzF!RKK45BVDr zz5xft{EvB8uUNSD>HEUWze$a~4AN`0m!_I-V81tc-90u9jWVCiSK=R5+?8MEGtHU# z_5542*06p&Y+{%w?-082ju!u<2N~cF0OgF#N$TYZiib7f2>}22D~Zx10NL*)8Kw0%|q?!&l5Uvsq%(8J#<6 zLl+yCl%95L`gL~&Ge2bm?N`(D%*v}=2dk!#{oH+9S#Y1-+*{_k$=6RHa@60H- zO8WBqvpJVzT;&lJ`6u;_o$t-LKR#X3{wgJL^7R#~*3>dM%uleLy}XTpvlcQ~Z!~ksY4HXJzl@ZWeitczk%qR1GuRfF@AubNhzaBU@VU;T-e=TTB@3&V!WUP84OvhU5uDvRohe*c7^X|#7 zkKC`8$Z_jcd%SpVskPp{Yeia3JOTVmWt@*MN?_eQr-!+wWi6-KiwRfTw3FYMT;Hsn zbaNqJjPQh@rH#LD&YhNOuX|ci(nee8txsu`;eq%RzKdF2XOD2|xm~)Wd^OK3Rn*$! zW-GUHiv($F$)6s_}txa5}bHd>1|8L@&p4M&L z^WOhH{3G#B<)>{E^e3D<-u!LBj!1*_!Y9rv=JE%)3jVC|+?e>gROaN0!#sK}{U%!+ zYFgGmw(|*kJc%*jKt{HXx$Nn*9u=*h5^pxO`Yr#nIdA2DlcQ@(eJbwE*zM}Iqw&To z*Q<^~IftWWul_aXKj-GG_qMa^U$}hEa*XqyziiWu-Mmq=oYvInMXt{E4PQKosoiStjVZjIS~^$O_%s~a z;iu?QmhhFIQO{OoufY=D6(=%^4hlC&9DLhZ9Id+TcIY>cIA?1$1OJMjdSx59i#>EE zd~{{3W#(4DWIXGToWS#YF0bdwIIl|*p4YzduwrWbW>itY6lX zwBgbDEHC@C#Kj9cs-JnxRuPj|iEei0H+>j<_08-M(;ESvrw;ydZ=8N~M(bAYr}JKV z_&#EYHtgdoUZ6Om@h+2IT!f!#*7p^QJC^3iCke8MC=1&k-otQHZq|zyCYe%{;Iptc5|I{LFhC4EBCAaevsVNrX04?AoWhQ_(8_6Yt|kp)tRx&!fHnJEt_Bb z{!jYf6gZ{t-0IMC_EmJMe>P9hms~X2132 zI{~><_g_tHIr`3YQ+1Z*{m>N4 zm2cAT1fDrs6FQ56I2ia?FEjk$JSr2gT|k}r)$Ik>()wClx79px*YCLffJqIBSP}d$n22jbPbT z3Hk!_TjtrzD)dge{WRv}k(mb)4zcc-*|w6SQs&Ozxo(F%4?Nf&`E5$^)lYql3)d-c z?YgbUU-N9vxl@mFc=kEU@xAE(A^)zE+fPG$mLJ>0^U>Ao-$yn`-f_JzE+=Ezu(D$k z+XT0~IqV6>r+-BCCYMXUzRh>~!FtKL+IJqlub#_vY~KTuhavoj-8}9jGt|7h(|7!y z%7v0uSNAXrd_EWP^Upf|=aOMh)C6OuExc3{9=c2L!{!^Q>6<1fM#yefi~RO#imC9n z6-qBXb|oFI_;|Ze-Zv~&bWK2cS>f->zkQKS1xJ~h&Nz#1JpV%~Qtisclk1j+E$cmh z;S@+k)YH|Jc$ zkFVJn(zh^B?yTSk)vd3mY42DWZ8O*M*ODmR`?D_jr>%X&(H`*T6=P|l#81U*H#NML zIdw(6YMFX{R?zy5%xl*j@aAhfxB1uSUy}ceR=qoMYvs)sruUQPhZh`d_;ThgUwQ8n z2XDo;+fLuvEEdL3?qG??;tMn5@O|fXgZWY9?f?emGO>i!Tq#?-10R+@5kHW{v$w`Z zGEuyR>)E3XYnvadiSw#ex)ytHPulgfda2mPQ->bttPYN_X}EiJh1-0!n>DMuyes}S zv&fin)=yt9Z?(&LqGIKRUj;d{?SI`xk#DhGu5(SJS*`xF)(`d6M<Utry{mfFml6^`)^)|$;gjd!G}|$h7EuYs;(JC%;@j=i%1RYk2mizkPls^X_g3-koYj-}!of zZ)tkr(s?!L+QaW`j;3p~-gQoTlMuFio0*b|hxp~|M_Lp!9d_0oI69em+NAGmWG-jy zowPVxYUYB|3)&Z+NS;3P`_KAw^%6}RZ}yy5JEk+I**V_wPQ>d&a}#*HeAeBNo1oEm zG{LmyHFL2~K~H1#zw1xx4>uiekds?))zbFN@#wQ>dIv41g;}>tDde0^{IDiFvTb6; z!SKU(jQq~|2`%&El=#(ZcmBmRx33DR^4l)u>$NUSx@!1kr6reJketWj?ejOrp1-AD zZ#1*u*IFqSudbPj=UCs$yZv~7{ro4-2X!%1wUa-q_~gvw2}ym+Rar7iIAR9>##av= z#3%Q*oLieH#_|8>qtYUlH&1pk9zRlhLr5yjq0@$^S)03g<5jH_6V#^JJ@R@~Uvalh zTF#&+d!Ueg13mKS{9- za2!=u+Wt~u$NjJSlmBY3slPURs-y9V@Q334#cwpyzg2WGcs?r-_$u|S{AvNia=%ik z?|ph^{}tW{T2z^aO_}-aK(F~Nod*)9kLA8OJ2|g$dq}rm)YRO|HQcSbNB6&0|LtOw zVUg0kUU~&b?uvw@xRata3tmr`h%cG$YBW2!@nMRvgY z;}aRq?2&8NdUJNoY2SM~_rKa&C-n(h2NwD#n%wn0CnGb_V5(brQ8UkkHifhJ9AHM2H?nzo- z$|`^Pzuimw6Q#Ef=IlD=k{)ohoaxA}OrG>@%nLlFS1P4N>g38jHF&o4?GE2<&$_G{ z#I3WHADmKp5b}8W!F8$Ugahg>S1~B9)G%eN47qb*v$|!UO|Ht{SJTY$O{ZNHnWWaj zy`G)>Xw)U069;d~{&-ydH{`}*_s z(rt^_l&5q1?O*-ivzpZlff=SZo4K_`U&RYa+|8RF)>~;>^{L{6)1x;162^sX5(RB7 zvkF@mao>8nkd^IL^X+;@mGj#_Kd$;+B{XS8j7WVPclF)#d$(;ZT7PlQZ^2uMWzqS& z!-CtxG{5wGtFH5j*?h|}$oxaZq0BQM-qzl|{3Si&8~cCxB@a3j1aH1p^!S_iH(-|H z^VW^lExA*Tb+o3$f2zOM<>DrE$I;=v`;qXj1}mc-yo&n&IXCj;P19*WGbr=iRmKX(UrM>&@wLF}1!fNB*Cx>%V>WT5FF==Mv68 zd4JFCc~*ArtLw|Vyu2kHG_4GlXoccohUg| zsG00uXBGC0_r?`h#}iGxD^EX?a%%hGVw7Z4Uby0nKL6XjpZb<`nt!(UcJ&$|@%evNnCh6u?&(!5d$FhP>A5dEa$d%7`S*sSQGRdLoE_!v zw|-o9^>rzZDNnh_Bsc5Rj3uXZ<}Xa0YRlapKX2*(U#tJ$)i6x@cKLkhuQTjF^8QIb zUV7-*+pdpukF^T+BvT;Jo=&XN!we$Ewi`E+hsZ5oV?cY z!S3W8K8lCb&N|&cd*-&V$rkUI+$XxSwjNn|J>}u`f&)4>>|y_JXWtiM|FcE7f^#1C zkGP;{)(IbS6-unmT$WXAEx5JhT(yPsbXFCspHCO=4gdDr{Z;+1uH=6&&rZzUxAuN) zlA3N-gWJ7Jk%w+-UKEpk*PMNe^K|aDq9uoeMRK-0TxcxI&T@9Sl6;Ip(Lo39O^Sy~ z-DdKq&CW_NoAb3TU5D*`oL75{^IXKWy%#k39wfi3o9V;7 zI9so(rSFQ>t6sa*GTm&y9;4*VUtTW$7W)3+dH$EXi}u?u`LN_@{dx8uKPUgWUNc>L z!@oxJSig9YqdupeFHn8G|5lx^-G+tT-Pt#v=N5dQ#gf%I=Rjr8^!R2)XM_14_MHt| zty(PZ_}6oKyP`=&{~wly;1l-i8P1%Skj)GEbm!NH#1m|DRIVhxvSoPK!OgJNKa0nz z!=HOyh`ZC5w>LA6oO%26OqDR7xZ>)Nw7P#s{{O!`Tg<+@;>-LO{Zsx+AJ8~fT(V88 z+eTj^QTLJ3vJ|aHwi(}M>}qG&^se^apOY~kwm7rYNdB1obYEIZnG#Fdg#}xag$j*r zW5gFY%()~cW0GLAjn|IjxOU+z=Ca=3R;%Y9DPj8au{f*?N-~8KeZDZuNeIWes_PIv?S5rSR|IeAUL-yM|)`|D7>aH&L{K?1e zS$RlC{B&5jL;3AOlWQ8L=kz+f?KyAid9p5DSIok(&i0}ov!ZYeXHNWr(xe+JW&0gX zIG0aY$1%_7!B3VqEQ>GJ{kRl4pGCz$lmD8&{r^cR`48J4{!V^(`}x<$hi__Wmj`~S zjJoy8#@#cMt0(y_cVJuUeYWc5O%p%HSG-zMwt#nE&6L1h`3Yu;i?}X`@^3UY*Ni=H zBsgsf+qaaS5RYm4vmBcqult`Hk(iz?UwxKobBx35yc4FcqJMRKF?9ZR|6p@qvtwv_ zM8t{A*(q;xW_pLEi(fCwz4_z!hlKw!57cV@E;#!Ap?%c;&!q=SmS`sQ+^mo+Dwv#| ze{j0h&E1|!oBZ-u#`KDbs?*BNMjhZ;^XU=~U!SeQI>y>Z& z?o9JIXUXr&(sDsl?7;e&hbPYzeQ@!!*o^u;|MG&)?sR^7eN9I74ms0@sWO6Tn~Poa z7hA1S`1W<>gZfp7HV$18( z-%K_zHa=P5bkR#f)$if2sl58lJI@}nU%B7?UvmBZWIMwLp-%Ugw`W&fjSLlv*D111 zzqX?E_ZdHqNg{z4WP7&nEog9Fq}AQWY{PL$`bxmuD8q=u>o`|G+*IMwX%PN`e;eDc zY`xyTUfZDEvQxU$^_h&b#3zNE`LHlDVuiq;Bb7SSUp81hn#Vb@wK-Gz9@FVX7QqJJ zde=+&dP_Zx*sS2)->ROk3{X7@ZMcjl24N+ zuQparF?{o4i}pj|Zn1(?(>+VK={|j-8OQzV^Mv5{YoA@26F*7$;vc~~K8rN@3^qT{ zT&%G0+Pl9WcYOZ7l)>wYaF5W@d+h7ZKU95cVi!NJpUbL8`YNd5PcJJyDuaSETjd9t6dYv}3C z_s;HMK4PX`W_k0Gdi?8n!hqXa9 zrSCVN3CYe~cE9q=dA^Fzf1Vxxnw>oL=HVdCcW;fCw@r24@ucVBVVjvVeCDb8ElsqV z5q!`oX7Up8vftXzAD)V7SA6fb!>ReKk08UcmME#N?85DT3e1>T?UL3?#_i9#Ci0-H zG^a5)HF-yeAm5!;lRGCJWm>TDe|$6Tomm6V3xPXFaPh` zbu909>}cE8n{=14^v;*yU#TBvTh^>Pbk;q!ry;qah3~iUeugUkjI9gQRo6dw5xP6Q zoyk7&$&bZblds6lQ&<<7k^MqXLp`Y5`lamM)YGvxlm6dL`&*SbThhed(>?Rkskfqb zou-p`48NzXY7w8Oa)9B`u|H*|&$i2diT@G8yLr{Sopnd#qN;g*i&-uGTRumMIV1Ym zldrZ>zWYBnBv)80DL!!expdwalW9*wjVlAV4o}tFR(nChqLDNB{xjc3`(mT4bCT5s z%xzrj&I)Xt_#vsvkJ+uDBf3Jlk^lR?(#w}FDdhUAc)j>~SaSC}ovp#8PVOfxCNDSN z`CIMzl8iUZuNj>WZ$8d9WBvZ055AxIlfc;dKYhIl)AHa2{&V+CF0fp-`@KYY!;*8h zHna8r+hthIDJ&2cf6&^)=@=n7UGVznFb4}W3xUGGDW_yEt(vkUIboLAhF4s7PWWw< zS#`QcM)u&Wou4@;Z`^F5w6rDH`PxM3y2HA!q%3FrWpvL!pO(AgOHfj0+tS0z8zPTS zyFX(GgZum|KZ9#}wf|fH|8AXf;P?Id33ajc$MX7iCs{7tbZg=cPQK2Zz4a|lf*St6 z=TF)%aGJLwv?i-Y{<_GygnM_E-F|WSErWev@8lKRCn=n~*~;)p!ItA+rn70$z7xW# zb;)xRSv7C(cw4hEIb&|Z@k*Onv-MM*wyt*jdUP7EAFD#Aozr1SP1We688a4sf8J*x zTU_yO$(4)q6q=X*UuVtm(|+Tx`Ym#k4De#>#DbMXv6|1SS6cbfAa9I^5eSBW~~ zrOGqIMeft*1^L=c?{8lDexT&T+shJ098cXovCCxda$LxkS~9W5K=*W6rP?&-!+b7G z7H3-iEij9-@eQqx%1*ek^S1&k_nQ-a{#xAkCr;fzg_+^5dw|U0X~iu+9{-wgWPe=W z+ifK&l6s5&KIU5?`NNi{?gqoU`KiMHq&yyX3-6Cy23Go_y?{?)!;o-zMI z__ESP?ftF$%N727y}rM`pTY9~v4Ro-o50Kmu@hc!eV_8z_dxiRUxHB<4?pl1&YIun zBWl`vOijMjY|^8oUZGK-e!?ETYedBZMEz=wYlh9rrM(S9HD=k zUhLHESZv&8{q^#B`@e@u+<#1K+&@|Ega2#u=Jz+017$8)UJdMJa~Jy*;W<6j3d;C?ot9FU)-Da0|zr`YgQQ~Y_;VmcOiT{dAcAjRB`5WBX zW|W_T=|Yxb^(Y^DUDYn5M5} zyP$3^^IdWOA6E}yZuf(Kzi>bOSI%0$f0FuF|JU*Jt2o>E6mAOq{H&2S5`)Xa+kR^?KRjrPIUo>;BfE_JRxXwwAaa`(q6%E40JvL}U(3$R{( z$G!J(a@w!|ozpjHKm7A_`TV+{Ghf#)K5+kppe)<`$M-+fZ*7pW+xs!yIZS-H>fGGp zI%+Z$2_=&>@11zDV$)NrnoX0I zPL#C18C~(Sv?%fN@(VMKqdwNVFIler&-O51%l^HE9}Z8F{rByyn9WE1h|^O2yU#WE zpX=b{o+T`{+Gn1vWU!Aw!X3GQi?a*EJg&q{+{R^K{y^GF>+mG@mZ06;3wR!ty|fCO zB+la-s`Syv%V=*@q`B4Ku!%Bd%NxWrlJqT0j!#i(jphrkSnxjVme>W0^`HH`Z{Fyi zbuHM}e{b4D`F-ou=U!Z}`SEQwr;WuYmR0}wzmb{eZ~YnO3N}T}z%S3gK7MG#H?3XN z#`*jfmM3)yeA|)?SE)trjbA_UEZYSEy~2+karV11-K3Xj78>kc+6 zLKbr$-o4-Z8d;iM4=lV}|IJTmTWR`h&yG)Z_vV{BTD?5>`|i!TbLZN=eVZ7$XcG6* zMWsx!EduUWZaiN+`NHjEEUTuJSlde}ytukXkJWv5hO5Zz6$h$5bohQ`xOTXCfq3AH zKcV|{?tY#eSIfO5yP5fAPw)@k`zunW{wvY{wqnW=lV4uF79Dz zWKH@DC3CX_9^1JVgsZf2e~>6$Qs{Ui{z~JaW4={$4~ersnldG0>xTg6i=h{nN<31P zf1}PWbXDe>O{~|O<8l`ygPB7udV^owaFIQy+A3}Ig86*Vg^8OAU;KUPRUNvZi(5pG zos<7~N>I|Job6(m0DdaIe#`f#7y2P*5h3gi31WJc`e!0cNw?}hh=f8a?56#Q{lF2TS`Qqr+ zm$zK1_?zrGvVTZS`^Vu@u5qw4${|6gF6AnFQqa{E>ZwavT~|hSTurK*b5ERm=CW_b zo2GUC=PYSZUvoL3uuw*KcIjVpVGsST%eF?3BT93)+~+&K5R`6rUG9I|!%*$#!wbIu zy`I-QOchyv*^qI~hDOOSA-3Kxj^}4wGGO`Iu9B$aDt~sOTXkFCI+w-4rx|{&3cGB_ zlocR(If?0ltIKA`&XW9SnKyreTT0JpOz7eh+*0zJdGWN=ouY@`&9e)f5cl%g z3(<8J57z}L@6GeoU$J~+)!H!W36q2bJn|2iZJKjvQ6ZZw(*~bIukv{|6*PPZzF@!Y z)qJIO?ZPkqd9}uGarf$xi&dz#YjqNLp1;|zUYYC5@xqzT#Y^_{C%%yEXs!(^VTkSW zw`aeY`|IV@7Ki;RqHj$~lolENy7aa4OLCFW)|y`rqU%!=HqEMgI$uiE{kz73Y}*&h zK4ePl)cEq^`qnQ}(swy7tndq7)?jsUM%I$+%PwwWetGnrOBHA9zokm7zACfsshmHi zc4=#U-Pzgf8?&nNCs@2ay1`x6S6}~P_VYDOFIw5vFU6m{|5{(hFl*XBvBtLxyL~S% zzm#say2bm1+Cg2@8Wztz9sg3l`L9@D;DpUl;z;^;`BNq(NmT6 z>S1tZ?T*76M_T_pAa`|y9-FcYs!33$_{@4f$86lO15^|moi9f+@RTV zjz5#bd49{HCH*D=&o9Y;HaMonZlr0k{lK0V#%s4GMYO0c)jst?>U4;Qu~ev|Vcki` zFZ14tELJjbSenlF;)Pjvi89x&?EO=Y|H_JRcFCPn z6iP+5X4fC=H!R^!+54Z7FWtaR)&2Qm&Bh<@Dz3fTyuL49zOJ>3B`RL4){7r^k z_dKULoo?eTR^a&Wl*;$+!bb-JKQPyf8gX?OUdcWp$9)uCle6K;4XYwb0PjCpk;%FH~y#jx$)y7%(Bcckb0_-b={ z*E)FCt8HXyxOr>7RZ5Q>)8rtIS|v?c_CGK0nU`p_ex3KK-r+~=&FNJYi-Tgy`k0-R z_MX2Z9zW$pT|m0kwd0!{k2zcnR(+Tt=qmo`=g-$0H(%=hoVB?qW7KutsuSv7K6En`cn>I{45MR;M8|VK#cg+WpLNngSO(Jb}yLB%7Ns&KuXZ|{_ z(7@z$QJ!;#K^uCsZt?bPymtIQ$1me&|JIAXwVjZ)I`sEN*%dFGlV9-eEWD`cHnnNt zcZ*dU&vG7j3tanR+d-Z%!;i-U=G=?)jxC;WLEw?!;s|5Sret5yYpF|LCjSkL?CzCf zF5Ksl@9v+NTQ|eF`vUhHlMTs_|GdoK?sP-;0LSX-#Y-f9B?ufeIs0q%%jQ=>S8gmU zZ1ecf@O)l|xo6fv-jwV2FD0IN70laGp1Nj|U4)bG?-;L!9qW|%mdh4anL2RYT@hNq zmm?GvHbs7}?U755HflCWUcPY7oOA!t6|LT#7mr=6TM`zm?X&S)pujb`4VLnrlbrv{ zc%!#N2bvbz60>z#a4<<0ChmB*T=KAOKG?1!OS^xxuzON99N;kh?|@7Z9YN$ zy*SJ$;j?&8!Sm#I_ngzg)BJuAJ z&+en)OA}@^7w9d#BHhopS8H8)XomHxnSQ!V){8~Hdo7&Hnad-4>v6kOLgkDy-hcDPGht?0xr838+-81J%~%PhNf?(L^%TV`6B zuC6-WtiGn@*FDp1Srrdj?IS;_F4kDzcx;wxs{8w&GLQ248JO$d+DJA$H-7*5kLVQc zy_!pnCNIvJp(Gi`8250F@s?cP1!o>~Srq2Ei*T_X|6IW7bU=04A-`T@)pFK|i<1Hk z`~vQlx_;bSUFCS>SBQ#y`#E8apPCPU7Jp`x%G>tT%G%oc=`XDyMy|Mk6}J@_u1YyR zPnXkK{b=Pmle27plsBK7@3sBmlQ;59O4WAm??~BrHRRzOryoo54sE^5n)iLqo;@qh z$?*do4R{wH1^4jH!rLbPlVypcUr#^pQ$5gR>>(j8H z-Jz#^!yb7z7qD{sW?H{b`u{0ytAFX5sH6KuZ|%H%N=njiT3KHBxjX0HZkYSq;m_G_ zC+qN&7tiHddA?lZ&RRUl(mS`_Oyd08q{$Qh+&S#DEYmDQXY1W_^KMO3(=MtPT$wa= z!M2)1xAKByvZY13-n2ysdb2<1`(JxNWTjZnOWU1q?Fz03Z~7UX|7ZD@7k?a2N^LP% zUf_2p%WZG#?^N-}W%j#UO~2e(6&R`WM!7Al&2PhoFoBQH)o+|T{@{0wt`DQ!tUD>{ zYjV?9pNrnHHSR&#eZ{SB=Pce9n7-z1THlJd8>3jmLUv4Q-XOtz@x@Mk$A@NfLRW_5 z-#_HJgVUE`Ugnf3a*Q#bBEnAYaHw7Wglqr1y3;&Ao~mqPJaE)=%Qj!B<9EZyZQOYBnE-rUg%c+Yv| z`QnOyQM*L0ZZqGxXnz^^bBhe&uGU*?YhJPBJ)g2@|32rxUpeMql~Rv7eV8H4y}7Bd zZPBi)FC4v`kNjJn5xIKd{DjDQmrsB4|1nJUz7@9eP~^gMzGcZ%-`}1-$<$-o#x?x2 zl?pI?ifPRpm7c)XQtiO!932+1f~9dx zYL3sYZqC> zzO&7$eagxS3j>+gyT0yvk$0f%np0uycQ4a#D-<3bDY^2~tv4i&fPY{ zE9$o4s(`Y&6KzgO-{JFovF7gsxg`d#-bkM7wDYZ64Ot=+7fWXbW=^D~1Zxv#pM^R(CGpHOL?Q>ovVnHsO|2wIg1CQl67rDqXj(%2!Zx#Dw) zgxa>xmh=W60-*BMXZ-raax&~xrw`!%KRVuz=%C}8<2b0d32mgV<= z#h2>BV|xC)GM?`s?7VXRnv3sRGjZ@~ z9bTaLw8u($Z_y8fo-)%*R`oyr#mL;=>0+_GHSc4@s)cvX?|hVVT}V{v-tn7DC0w@% zhb$`m_HMsI(yiDlKfRY#>?_=M&U5;1Z?|bD9v+_X#$c}ZqH{|RS&BatHlH7y8?r;z zol7_eD&Svu%6A<+8i01pS4#;=2YJg`EpyP=E+9>+}-9! zD>0pe>Q%-uS%vrcn~63^lRG*qiG!bKTFt%AM150TC{zpPRED$%71E& z1pnQ5BcF0|XNg|7zU(1Uy$iK2dkwRCi{?#_n*Ad#{n@|EUpf8e%-oYM`7K@b)gJcJ zcYGh)*Kt^F-{_oP`_4e;((OgX-vw7}cB^DPSzY`xXRht8)2y6%EQ zM!J}DtIXRwf?@kM{MumaR%{(S_qXGpi@i``pCcXSHf{Th82^m)ZOoItS9ag~ z?EK0nr(|8j$BdsbPad6h*`&&?o-nb8`HlX!2{T>4P29NNsr7$L4ChJF|H4J7D&fEU zPlQg0v6SAaJ;~ctIQO>GwHk&^Yt=tG7Kv7c#H)Ni*}dnr^Q6^EH`S#pCmcR;bwbQk zIa7g?%Ab|qZ|L50!>*`QrTVh+=I=Jm_ckwD@9{2Etca;k{MkF{w@T-yD80@-@ueyA zYtEC!e9G5dih6UNh_p|%cPcuY^Td`roHgh#~AY- z&v%=YB6$-Ts$^e3&5~PPWuGkKc4l`)zKrT_r$2YA4r$z6BKV@>-%;Ut^&8llcX9=_ zZr=Jf>PKvD)fGW?caOaHN3HVp)F!gc21N;0Zg|Evwx%K02t1l~> zJ^0Rc-}&r3>2-t>v+>RQflo9`C98CMQWuezoG3&yQD{XkTY&;NoXIReqK?G4`YDs;|qh2*2bq z=y9nk?faY-bFT5n>ysH0jJb?v%Cg7|FBjkvrO>>EcQPKC% zj{p0nJJ@Soh~4LUB;Ue#W2Tg z;LH6$_7F*|6@F&O57LAI_>Cxs`W7VgcLFCEG3TYw#5; znzmqb@k8N5`C%XTzZWU#6E3MMoBmv1j!mO1wrkCXpHE*HcZa{Ul-cXWttVT0FCgem zEH8`T>6+$AZ!bp9TC@G)PR?s(!Hqq4o&Waie!ujR8J|%0?fW`Q7}F=#+*x<)Ur<+0 zajyL)%}KL4pJ;m2omeXVa7%BK%UpYvo6j_PC!U?KX8WZ4!k2P=O0Orr(Vnm|c$Gfq z+cy%M^e6pgG1|Hzcv8x8eurzfC;Xl8CSO&)OyQ>dNyf0ENz5l1J@~dvsxMTq6gcS^ z_DPI=QuBm6cf9`D<$ubTpL9p&a75B!Wh+CyS;$*Rm2cKinim5ht z8=nNIY~M0zv5ZGv=aaCoPb}<{q7`>;o%*Mh`Q+M(caC|KX!R*_!wD2i68PgC7qs<2ablKnFGXWHV@vSm*f*-pBhs;q9&bBFQd+szZFKXbkJLGh&Q zL>--1uhjlEZ8_V0waQfVxa zt>fg``LZ}HM%#?1&6ZR6S{JLv{3)_~ms`60S$4Q0%`#-ptXkg(Yj1ChS-CZ-wrI`l ztdo5g8*i(&uMvISZROrlyzY>CXmR4*D^GK*rmNVAHg8Rv`~O6e$i*yHDA+o?#u&kH#wKQJI?fl|GCSARbso-r{8+}{mtsG(s|q0 zzP@JvKP*Cfna;P$m9EuRjxJ&xuOCmVnN}OR(K|ibC$;ly;onHrn!Kw!#eUDV-tqU{ zgwUh&)8j*ZO3Q9Yy<^NsWIk+Z{=&R7Zed`lmb>nozh2SdA1rgF?z~}|X$M9#|+hmn)d^`QnW`5sgq3P9=QdC9GdCIjfmGtkQ#c8#9nOoLROSirC z3yR;#zf?M|TGiTcC4Yxa1*ezADQHL9yH8Y}Xk#cHDg8v_lZ%S~BKLhtI}17% zpO`$s#!`A`O1Aq%_2^%l=XLqsoNrj z4Yf}8l{uEQ);Da6%ruzjqI^qZ0lUJlY(4M8nX}CVo!{|yZsXjkE~LCDdCdz8_eIG9 zx_92*;9fp;mF9mrtMX)jm5m*J!WaGu+&wul>bPRntcGQGcWqU^7_U^dtKnVui)DQ- z{?1!IRQE3^ouGX2vf$sX4a=ggm#h5Jb~!I_;mV=oMUh_Zkw17`xb1&_dDZ_SF-Gi< z_lrC4a+GFvzK9Gf`Csp!9sNbe*DdE_z?cA}a{JxlX z%*%BR7rW4^a^cW|pNSVY3);Fne0M96bYJvbp=zCI?3IZxc6Q8DUvOCP?K6)rHZJG4 zFAD8*Iq&|3iSaIX^5*hB7k!74J)(aPO?*+|qAzm6R`BnUi7#3^;!<4im#b6>E)wT{ zA=k0*oyV6X7yXTk&RYxZWx43hT2k&J|Nr}iZOYe!Tt6MIRVRt~5MM!L)(8bj(CReMZ#TN%>tbVeq@}ctrRkfX~ z1@_L8D-+YM5enPkU%c^h;!z*4*VjQcVd6Y!=2`hPG6*4 z){9=avUEuSvrKwgw%}erhkn;Dfu3L5ceuOdcgMBAc)#X_ai2?l`-`t(Uqsy(U0429 zt^KP{`Qm-$s%Fu@HzvN|?YNiWI$NgmUdIdhH7~CBx%_Wu?Hu<(CxUFH_+oCyznfio?>)Yp@3@!hT3)PDCBCSB?|Sh! z?2C>2qVLL97rWwKd6Xt%)!%4K3{Q|9F-$PccsSk+l)mvAaF{nLfIo z=CCe^5#93q5W^PRr5}2Bulcr8DUMfm#W!w?{X%PAx90o^Xh@9sdCuvn`gX%`yGP%@ zG*nz(-}Fr~>FInnjV(?>>n9wQ7x*X@`1|OJy|;X4^Y&l0|5N*Pd&PR&*y}&`EN}4N zlJ&kSmP=nJW6H7RofYZ^9k-g*mVYyUX?EgWR_}_v@n&zeo&M-yH`GFdzcQ!W4_W#Hen13zc zzKKmo` zarzJZpEh6L;km%|Pom&^riE{rIj^5^`yJ8XCbjxo`=*D=0_z38-#y8%fB$`dM@9I? zPk)za?Z5i_l>fOl{`Mcuk6HgzRBOdY{a&ne&-cLUxl2AA7kIDo=zH4X^0psWbQaz( z{`O$$R(rKacNMp!dT6K4^1Z#C@rQ`^eDROglBtzzCI1T^dH+dpi~P*^r>j#w?(eLS zZRz9ZecGp4{zBqe`dZ{ivD@rbq_m>FE4NC{vf_9 z1?#qNdYH}dXH8*ok?4o!_gxi76OPpPEmIG%t8hy_Zayb(@!mV{)&!sA6pZI!@>IBJ zp=q6UB~R2&=q}&U$0vR+K6dF_^ZL$Q{Rh^Gx4UK6*V+A8)tajPe@TbFPT0SMm8af! zP1WCG%d;!tTAje7-41^mT^Bul-h6)XC;!e0f5!EE6A!H~-4ya~!Q`7C_7)!aD)gcD zpWeN6DUGQaF{h{Io2~qx^uqMPBD3p%SS{Tq++Mh6yZc|a3EY#WCA037pIZNCO`YzE ztJ9|ia}{Y%U2isfr|QzDAx(G8o;Kfo_NQj)(<@DP(w;7kP1||wQjwI_@>@saGIFjh z-n(VaWQFPHTDJu67kZNAaoUpm&ev0C-lpw*b*U)IF>mgtpJtn5QZp^Z9rIRB`tLbc z^+ct|>7BDqU%!)ZZvCPyb7m`CpRsn1|L<2X_NBb~7_&P|FUoP<)-7||C&cSsGncp4 zNST&B#lKp_?DW<1$K!0y{@V6t!uA-!h5yX7jLT-dUOH_{OrYZaSvhZOo^){*&EFvZ z{PMmyCUeK1MXPttJMDQ|RQyx+iLi6W-+6NsoxO4D=M6{A;=Nlkvi0IkGk0D}+nLb4 zH)P^8ZS@x$T`P;%@2quR`t%g{&#P(K&yvrJp7|O3`|6zd=**p6Y1SE&{O#APoVc2* z{XF=*-LpSUpC5*aKGEBtt^4nQf^PWPIq?qjzB1+BV!g0d?V9$f-IqM32R_ygj|;u` zNvm#gQijZ%GZvBYTMvD|8Snb@jnO0R_JiyUr!yo}A0K*Rp|$>?G1tP9Z9hBLTg8{p zn!JA7o@h()DSR9zB?%VJ;u^<)N-Z?Io+7iaM4Clv-8~77qphV!h4;2SDz|O=xZY+ZvA7Y}q5ex_JBI81J+VI#-ffigq^d+^2JL&%@Jg zhZ4eTMa!IIckU?-`5OG{j!OQ-^E1O|sz-c(S9!fw*1UY~slKAj`lEYJJ&9c>ye8+|{7@A1u;uJyjCH2d+o;2VMKl)E>)<9-_Z{j?qP?h>1tn1fAGXS|hf9r=CR`CY*>1Rt%K2*0kShV%j8}+&sFH*wqzmr_`WP!~$_wWP%Tlc)Edy$dK zd^EdxKEsZ$X>T`it{0AoU#he1l}hI7#O+tCmV5quKDE;6q?4t3aa`8PJwoSqzq~Rz zcmMgh(~Bjhc~36idCflHbx!%R?Ps-Dh)#PwS?1}YYQM({TbWya3t2yMSvGIBU-Fj7 zl}VGs-z$7+?b`GD-eUdi>AodjO`nH4De3P@pJndwQu5o+tN!JI^CusEci;ZQk(}@H z_QltCKAkVV<^7B6^B!I~Ao^@hBrkL0zqK#qT-F`f^{R1h_{^UXD^r-G&GXNO=*RTm zG}+E1v2RxOHG@yAQ&PJQhLxX;S`$|-o+4+~kXU&k(fPsg2PZQg>|SKDXv5CCYpb3v z^V!%w_27rouiB@o^ReVV)0O!;<=ob1#s;#UtcSDyd1Os*4w$0Jbkb;19rJ-N1v(OD z_B9q}OVoB4zxxp5X7WW~#-+svHzY?^ZTaV|v)VdlvS6+>>$2(T2Mqo{IBgsp=9GGj zweNJtwD(7@_{TG}9ew9-)%TVsRf2zpcE_!24e8QpcPI2lG<2*s{kT`-G0WsGkLOWO z#M3fuxZ6rUvezz4Td-e?O*)k;AX{t3J3EHMm)iCB=iHOwIxIOO!Y68rU%r9uOCGkO zpPtVh*$t0rv%S>2wCL{dhL;cO4E~t>eDH6b@d6=XhUk=>1sB5%=H{@pO||wnn-#?R z_P6RAT@~G14_Ibw%4*(?FXle*i^CH zKO#o?M;jjg&fA{U6rIGVcR_7}iIctfi9KIfc(R|zRT(W|tuUOo!P(8kgu^I)%F%05 z{}<(`%j>LWUo+kC?Jvyu~?HO zxa-oz6Jc8-HBy$vu^pbZZ{>9Nv&RkZ@yz+vw}7 zY=+A#H)pJ0xBOh0HoIR&i=ol8ORH>W#I4+LJg#D?)8%gozYpt3UX*K0@Y3dKdl8n| z>VE&=xwky8yS%&W;#hswn>Qw2TXB8%uHVgW3tNfMV204|bnKScEc4&!wm>RQgZN)zctFxu8b=|W!aGla( z_;&i~tTUhMP1z2cyuH2oY`3%Onl*QecKSW~SsjM}nuQuyG6 zfG?5jr!8K<)OBu}p?InIy#04%cRvj8e7DaqfJ-~OZH~sOsZyPXkL|e6_eHa7*D-VcWs9Ana%C|DZw>Cai!gc8eC_wyvQ@p{*ST5BksG_w-nj7NGP4| zjh?mH=KrH;o$RY$dLWyhHtL9|L>bwrfSv#-2 z_ipV%gK1y)#W2>nNncnXnCE}bFiXAcUHJwFzY_EF!Tvi;Y)e-sa@|@TwQbWC{|dXG z{yMKWIj>jtTCi6uVOq?(e>VSRUVm+0?fG6U&Q<+KOBfzf1hj zZnhww^q;NXxzC+l->~jK-I)zZ0MHn;e;N=5Ju(pAv8}XQ%PO&L>-iNz zC9-oiu6g{_<^PkPpZ~pxpFQ`b{nzL%`yexPzni!4KNr=Bdc_hn8AwRL{#%GVx=Jkpo4 z^5|N(lhynD`r|Rr=f=zb5$j51e0I8H-G7#(e%+(jvg&ePK7VK-rja;Hy^N9bqUAb^ zyM@OaQjQCMU%1X9uU8~le71Di1~$8=Ki&5?K0IB;zO7_c`&?^po_Q)op|dv>Cr9l2 zbL`>0$#)m1tP<5%_FCK{oPEH+xp=|6`_XHzhi{1S+rsf{O};@%LjK!VRbsl{oc*aT zb1!fh8wIQt-R{k6%~SGiL-e{evn%Y3Ie0dzuRr`@lf?;RgHXQ`gQ`QE5$iu*_xin0 zP|4SF>lM+;f9J|2-u(Yseey&81;LFa9h1fOHY6XEePggJ+E{H~Ly?A+_cG2a(v|;C z758)uB>d!zQxw;fXhWX?XF6_c7-`R|KW&po;Qxwh-{ zMGi{+2wlgi_UTXU9JgazeE;k^UM92i>I9ADVLDc4g)*3D>!0K9a0pagGbNZ?TU++= zno#@r&UdEV(XY2w=sJ7pZfUf)Kc=zx&BWWaw-)U!N-Lfy@V0rasaWjC@9oLeddHn*Zm@S)IM^zfU@neR0qBBo`IcQ;%f0(%m*| z$4i-{n4Rl6qd0TQiOjEC=RTK3Pmxz*!yPYk1hhV2K@wv^rHU41Ni zvKnu)sT3V$_~jP6rt#AIrrSA(HIGE!P@SG_IOp)64o1(_-uKzSraUa|XTBI$GXO?aVKdsj8jMCH!G z%qK2y=LSCBbYNyId;N(k4il%Jc{KU`i#fla?AD9Apz$YRx(}n()aFvpml=AimVD`u zwlL3O2v6ZM(B={1TlnJF%Jxh9E!dadc>i!_4C6LKZ~b=;(gnMBDF0BOGsmpC*=Xuj zMLwVN%bF9v{!72yu9}p3wf(WtqRnbeFO%$bUgwMd{%Lw#ErR#=(^(I=({9H9zL?JY zJG;I>j8B^P0sBm;3{ysTg%K{rmr(?W#fsUjP*wkZn&hsy5jimfO)a} z`%hgxkdk&Y_|2W$=WRW00+H;}t*tI3wcMqaTg84Qp~(vQxPX%I#Ea ztooh>y}kIctntCYbqyztST&^19kD;Ak(_??_`8R@3wK>^Fb-wJBv%J~b zw;cJc`OO^NpHy$~%$JLP9qch#)1jo);|KHI+x;8suY6@c$dP~Q>H(p&f89SL8eZ!^ zEAKm6mCLmM^wk4~JF1_l=iKN^ubXv)<8gTXkGN$F#?6WkpSma9h<*6f{U7f_f!$(Z zr>`E!PAk;f)f2yL`8>%|dF}xDc_(gU@76F-P5!d2*6q{N^Uojn{0sgO=w`A@Z^pXE zIn5!v|2aRg)i|Wr-fFbSRoZ~t-|mRuvp*->8TVOqX0dgrxLov~DYqc=eBQ?e6%iue zn%Fk&^jpQYY|ST$DP^a$?tfyfNHpK0r5tr;^31vS;HsO~mcWucM+?cW6seR&^(nB#G7R`*@!ad>Ff~Chn{3HC}vl|9-iTNBJf8zRcYFOibA2b{*d`@8%6#|Lro#coeG9 znfmwC-7+bE*Twf6U#c8qwq8G{hjSNm>IHtCiGsR^jJwyDEbn{a_5I}Bi(6(NG}{?> zLEdM7a<;DJKWk|Vo|p@ne$!80{UPEberTh3hF;6}zq~d#r<%x35Yd%7tmAR`qJh|@ zdtdz>!eg%Iv}{}SHvOT(e+ljj2fplht~FF3(l6$dTC>yyW-t0Lk5n zYkD#^?mKgRX5NdYFGUubfr zA@S^Tanr^78y3AOH*jCaw#(q-bLRsFuP^?ba4zcLUfW5U4y&aStS$+)Kh|`QYU?|! zmcg?;)us1j!Y;|i!fP963nqs*nBO`eYw7-_WoGqu`&rxG<<34e#o>wZn2dJ2;ppEw*Tn-2XG9`$1;}GjB%!RFT~OhGp+2TJ*22ElOGbFQcXOp}FM6 z%)v2reWv}qb$GaU2zeQW9nM>?6ES3vrI(*5rU)%QzEgQQ2Os{HA`igPGjYI8Q%43zx*RR1#6sN#j3b2{@w8M zg60?IX#TlUV*IKXg#RgpH&~weW54ckgu(0n*MIAeJlwG_Cv|Hz!?G>2A{x9hO{3Mg z1SiJmcl?u``z&cr{@*Vph0hmCOj$QM^mOR?I~LO!=53Ci=l$WgOmXPJHAa^XZ~U)% z!bgr_Uhp(^{vSyizphJfSlIJL;`N)8DSuz`%?oD#|I#i&EGjJdhnL#*32hU8R+v4D z`uFh-W0uCbdrfI*| z!Iv7gIXcS0>oackUvGSVC#wJY*CoX>q&Gynh1{N5S#+D%=DGg9w_=ri)s1pWsaLW> z#plJ&W|`;xcfIc`Lzz<=e-peVU*1@H>Ag?qmXr^FszRfR`dtc=zs)M%s_Ss0)L`zx zs=xa#OMX}EKG3?C{r>5WU0YJ$y|#XwVe!vgcwhAarJJngQ{Nl3?$d3VySwVw#s%{i zD(N)rjk}a}Rg!V0bRpNqZ#lO<=e=H_qQe%f_)?9dr18v}l@jS|&(FG5W@=%~Hbeb# z)V$dS7r`q%lSI z6{qc1-pZ2^b6}pSy2RBwr+w}7Oc8cDbXg$lt{~O0rqsH=Ma`(LZ;3!R@7Q zRWy!?w7yRXTlQrqAE#vQ0fXf+ZnN!59ggofR5VlS#~YKBcdQ0)W=wvPmC^RKN`~+B z8pX^>j5CkN29`XUx}a|3g2v(v?rP!xvnO~aACkO&S)VPRQGEwPc4`r?1lP>>@0t$& z_`7>|+pZPUjQ31AX?jLfXx@VB|L#3KxyPfy%f}$)R7Y7JH>Y?((XMSzT6fj0KG1ye zVARYi*%CG(xpPM*`1~wLo4xTylY6>nUS$rj}l zxqod|KMvpjvbVohnyW2kA4VB$l?fI2#+BdsUF(wq8iWrnhak(O0X({ON@f`;UFK z6&5Vyp0hzZZi?Y_OJ2o?xmJFPW&3>JNAd32!1?TChn~s7OWbM(KK^?Xvc!2^XXr%e zDeqdRs$0aMCY2UwFQ#FgX%KMc&t^4-+2k(@`TZfG$!(-H$e9r$hP`mTtPW}Pw0@sVdMcP{C z4KMF9_jLWQa3y@kIgu@;&17 z?!C5_x0#ZAG+t4~<+Y{rv)fZ|Z1{SA-J9J~r;IKpOj+5OIB~*+R^>BI=Qne)_P9)c z=r-NeqwCsk&Slb#GhSbkZcL7M6ioG=p%BZ!k#l#CEr+zLP@4va_mmc8twm~5k6h+- zPTL_6{>bf4XJ5qxrzHj-Ra`v+gL*0^K3c+}>FG7`(h?p`?>(NDLGwZsL_Jl5W`-!* zEzw%(wraA}61ATlH9mHVTRn1v+OMd7^{BnnV4^aAlG_r)pFJjuzMjU5)b}0f|1p_C z$fL=lSjZ=8f`E`$)TFQ_rkTz>OLQ~cZ%yV~qWsduYO=wl))Ljb9_5#szo_i>uz2bF zYr;O2rZ38WPd-m!kn~`icrb-S(yMLa!xWaEO+6}$Ph=Ri^{75RQDM~RGO05~Xr|Ay z2`gJBXbAcCsI(oKWbsLLrrWZ~>re0)O+KR(KRN$Ij#2v=)z2qtHZ>fX+?pa7=`(G@ z(kIcIdUVvaPk3$WTBF99!W-#*ZQ}bARiA8cI+#t8Khgh0eN$(STJ(vqO}#nl)+hWv z8Q*lRQ`~)0ZqxKP%KIn%Rhg(VF=did&`HKgZhVuRpBPv=^-W5CVqP?7j)MA0&7xUz z6w^;y7R`%M5I?C}G&4pq{G@5o+&c>9Cv}Tv-%%_-X@r)hhX_tbau#m;Cff04`0+xXcpC%~*@-PPoI z&;RJpetP5I0%eu-3f06(J1-qLXZNVFd{O#-=9eYiM}s#h%uJDg@q)2tE^F5NBi^;r zTSA^LoXDMZ#OtY`@Rmz_7sBHotX9|9BP{*?{s#N?tCCf&N&VrM64h>8FPte|`}1Z| zmG?ZIj=VSPCN@c)zPb3~MzJ4KTw3ps@I}h5d%9FmJ!B5c3A)YC&Cbec z54L~deEKxwu4|2{_tfd88c%iZ*k!+HI(qP@aMK_DD*HvQ|8)7YA1wKl5q6btDqCJ3 zLshiMw;RWoCcijlzDeq2#P+*V3!9sdZJ9Xj?OWOD;a5Fxnfd1BzPXqodsk}XWvQ2^ zc;@jN?P-$rGGzX4&T=bz>*S6Ues-wcrY2Yc)gMW7|Zjm0`CodtA?JtXvQqv|0RTv{tRvaXF#V zO2d-q=BSXh7ycfbSb1;?)0=$u$>uL7&(#iCdnj(F=-!lBXc-*3FQFHEF^R>H^{_e3=w`M!F zK80yKY2yV7&! zooiOH-|R0oeu9S%a6GLRcz^gq;=gZV8vDyP?F$uuD3)h9^|(}MW6(kWQ(+f=eG~bj zxj15R!m>2&7wxs`ubJ0;U;bDy_gB(_=asGJs(%0f&EEfP^1rD}`}8xeOK@}a&)KlR z_2BG>w-5fV<=XOXN|EXTL)GHo+>;Ui8@YbmbF=33zabXCu+K^Ko!j;Wf7ND(zs>V^ zEH0m9-(Rp%=EJ&2>8E$I{`t50FKh0fogPB>yrZjXi@n$Xzd!3=?RxY2Z7;vpf1kT% z{oU{*9PhU*Xw7t7-Q*@?`{jSIqjOQ|vI+bV7anwq3CLYM7c!}A*~0(#U;E5`jNh|C2A@?g^1Qla_vze;j7D%K~jym(ejnm4^*$2R4^krUr870nKj zaq`}zy;X?S_s{KjCk>7sI<(kok$mXK+nav|?$lK)Ub6gvY;oY;?~9e~cF4a~c%!7c zuSt0E0Y#C&8J#(GTl#ESO>G;ut@DZKzSD5$!Q}eg3mRD({%xM38N)8M>z7O7+;j4q zmoNCg<(ba=97SK}^te-Q(FyL0{WCfvA^lM zEBfA5ZZ*06bmEix%?nPIUhr4HcslnUukP+G$w__}0&0&e7UaK{SNr+nCC`P2VqzJ0 z?`ajr`#8{6n3b){Ok+ozK5sKJwYP#l2s9Py3pq*FV2MZ$4Xp-u&NT7V&lBe05#T z??3ae)SV}uzO1Y3kKLL1aoHx@Lp~IJ{1c>T?>e>eM){4RguRolY-q2jn`@A#Y4>j@ z)4ofaYSia_f2T3;e_+Ln6^q37^Sy3=$GhFl=Kh10in{$9isvM`P4&37r(%Y}JpCk* z^Yg`Tc^AG}J?qE!qaO<9RqVUL@$pY-qTG?ZSd%kChkd(CyDfZQ_~v&mLaik?%QMW z&)g)UDrEJX=i1UO{JmKw)9vDYD+Dxh^g^w||A`*`Y?q|6edx;A(E$29QbFR+~xW=N*6?r_dVSy z;&nBL&EU4Y$mtc#YkQwR?|N_GFlA{aV`-M-55M(sm(N=H&;I|n@Bf7c`|Gpz=V#U} z|G$szg0Il$mCc)5`ooz*>KQLc&TYJ1eyH5;mudQO`@3Hwgk`^RoRayaQTY7LW`E;7 zKfb2&rBZRui-bt%<`_Q_EXMMkraTE9JQ$JPCyfa;Ny+dku zS*z*nxdzqY5ls8a>?0RFY+ds;ZnwYMy)~0UL$}|1-LifE`bNI4gDJC$Tk-VQRo-ua_@8FWe2S?)&dmYxwU-+gp2=y))##f4jO=bLlVfDl3t? RwY!6F{P^^ragp^+Jpc%4;iCWm literal 54172 zcmeYd35j4h&%p54yecA!fq^ko>7E%AgCe640|SHdj&_|l`y?-i#WE;QW>aLF^XOmA z9;e5Gje6%?Jr5puR;Vn0wS8&hE2+c@R8Uxd+7`7}wm~a?{NX*RJsIWv&-hW}`LFxLUHBuGv_Dc>5=*DqdoiJP9zCT=e z^GqZ5cjg-=H=SO|u9o2-ExYdI1!>Rq3jI4*hpSx_5!|@_dROE#hUdF8^5%-He){sX z;a@+u13#a5bR-GR`pj{3lk%w!-tOBkjoKzooARK%POLzu^1S;3mNzeUJ!af?pn3YY z+s#J{e%jZa+c#hL&+T`|Pp#ZLNxU~UGDd%o*zHXPpDOZ2ii7^Gp06S9Gx3Ps*%L8O zWs){|h4U?4>b9?KqvM9cr4N2@Zv1mV_10eYkS>eHbAfK0a&1wUHplI{HF=7RLhdZ% z;FtT-bIms}eU^FFt#kO@8PA4;yxI{#pOWvs>sqpoH9RSBO`4t7^CPOZiVkm9-&g2$)dj8A_ z-a+mwuifU?uv>Lh_g2KZOG&4H#S8bfRjgTmeh<^l+AG_hElu~DdpVbs-{4qM zcjl%rLu1u0yP$l@g}LpOGiKN=$&|OMynT1Z=A6v0oqLxYiRzx@FgY_;tAs@`-22O7 zk^H}@<{OlagDx6sch%QaZ1af~oyI$LcU}1fzMDKvW>*~kG|ytuSKwOskZ(%<+mf?J zjF%63E^a;3d^%l1Xpz*d^WICfmMdPEaI-Eh$wuh1a>D*F@x{v(_2%F6jsEfDx^4i| z$LBBRITt!81-z|ZHeu1O<@?{??wlfFDOIMsOnPqZp7IS(mOTAr(Cp)S<?Q~N|?SNgVlXZbyr`mY@vyz|}f!243if@E7(?htN> z-C;0O!Q}qp)VvVwg|`##1e%E74KRFAy@2)ql^qjKem7grhI+#~vXLD2e8GDczMWdm zyF%~gsyZ$9?LNwRf{Pw$JAOTpdSSirW#`||=J9f$X1RH)Hu_S_<6tj4_ClYO)H7vq z9IjhBcyeCx&v8z(Vh>LJ;Q95?bD@&A?d{ex?lcq}vYmQi0Vi{6LgI&Dwc9^5c8eUV zed4q4gFN5e!)f>$N+`?}o9Y=FWoPxU_%S zEe89ei%*=5`#!60LvE48vZClV_4Cf#v!g@&A79&;X_<6OYUaLarc(37xM#+mcXQ`A z{o23D;_%8D%a$p0gmfuvUUR9BM~?m0@d>&~+q~Q-L`5dt>R9q)h3$-2?@hCew6CqK zscqf2vOp{LUD&bsioRNt(?y?GYOt=}^)2=Cu4Rkz{Wy-y>sopI;+iQH9h#?7N@kv4 zygefB)H|=aH#*Cwe!J2kZ_NA6DXt zjlDnVkT+ktM5Qp_?t=W}!>j-Oj?Rnv%a*j{-vQUIjr*q_j{VxVbkzdC*+)ZreH9(w zIsLnlI{(wY8rN>^zo`~2n_4cv&8w&r(9zd%arZv8gfXb^tk!{6fq;cumwcYt*b;e? zr8hWmPT{=?e=K^lr$pSDr+rLe@BPPj7VW%zZQe`^zQ$ESZEd$WyQjHdnt8wVX`Q(Mg>H=U*|2$CQFYRMt_81yD^ET=dVO<|B(t8yi?&}YxO+OA=I_w0 z-|K6B$S<}ek|!ogHcmxt8fz!xG#Pt^<5oRvjddZc`#LH%`#HbiVN&LFcrN+#&0a^d zjdLYkPM)~5^L_H3yQd3k-(C3UT>Nd{b;D05Z_X<|eAxVQO3jD!w?uSWG-rE#d0LnJ zbIDIDNDX_rv~~Z**PQES zf6G>xcg1V(UX62t4YEBZ6^|TlMwb7K+Bml}BVblZcC5O_v-{?Iqa6h5w$HR(_&oG# z_)*)tllUcXvi&VBSDDYgaL!A|^Y>?}?M>G7e|TnY1?TJHDv#rfrcX5wv8lSt7I&Uu z?X2DG`nt|s=2tA1v+Rfw>dZDd@$i?hd5XoWNs~_WHPqfcb?jHumF$O6_0c))U(>jr zafnz%T-+vnYID7v&E|`9*DbKRtL9|ve&Bt{iF%vhbyKeW+Ba3%wU_m-@y5nat+D(K zoLV>2nF9`gJkJofC@kyYW6sHW7Hc&7XBQ=IF%frp&d&ZTfNOrc-eg6_A>Q;O^)wyO(#(^uJ-seAF@NufW zNz3Grfc59LG5rpX-}7f$de&lA#-1s6c0H+l5MKG~pR+~&pN*9)>l-(;-I2<>Q}TD$ z730SSdpl1r*9N_Iu?!Ep$Z%>Bvjj7>@UeQlq9iQ;%t48RAd7}2}R@Sd$ zua!+Lym5Yy;A+RDg|n`3he@(XKi;Y4a;xa+Jmr+B2QSaF+H{}oSdMZ0OMx3oVN-AF zSj^T04yXwGgZ@Mc;3gr%o7<6gFU6-r0=Im%BmW(fP=*`Vp${eAZ-p$$7*d|2IY z%Ew+izM=d7{`WlmTHpGsd}BC@ryN^k!zK7_s{GvjYyIklPfRMkc-?AoqgHvFm0aTu zAy557rm4^OD0T#`(Avb_w7BlIi+I}Xw%O0VX|GLI{&cx&S>~zf#q1WX)-0cSC-IqN zPoL?_+7LEj()Uf0{s+3QSg>etC51@Y&JfGAYDcbnQ@?j|3( zC)zS~UdLN_G@{szBbMgXr6t_Y`yJcR$9Qt{;YC~AW>n9d+BZSU$9b~C(>vOmU8Oed zPCv2l|M$19^1kapSA56{_K7D8Vq31L23)(cS^m?qV5MC4Vbn<5p zE}4h++38-|uixbt-`v%gw!89aCG%t7S+$<}^V&5EgWi1F=Wy>?+?D6MwHHm>#db$j zk>k8Ttl_OCuiY5x*gx{^`QoxJTj`Ylugh&O{{ETA$XBl!y__MT`gLsg(pL{;!?yb- z@E^>~xXEIXyzlC#J=MK)O4UQ$#ZxYrPYz#txyhJ6dgrsdt;LyZ6J~H}{5rSUYSo5v z36@vqtk-mi=kNM`?+^P*4xb|r7Ya1`3%N=@ZeFs??db*8>CY{$?+(BGMT}Sj;R@9|8@4vWW9E> zt7dard|p*Z=fV}TNlLQ+XY(tBJylX&8z9$rfAgnvPuDM#bzk@OT2@cF@$!gcDkrAB zFz)UanTE2rPVu}FUify zIIv;&Y7Rjo_j|l`;z#;sG5H_Ni%#>JvBsP;Uh34BoBSU6t94Sp*f1`!txzrUGidy> zwRY{_X-}_ta&MC`+#!}bPh`{5(jDy6jw|+P$+bSVOb(h@@KHeP5zp4tYuk+HDMoC* zbf2SjmP7|z>bBEX$KGm7@Rs~&EIslm&iI>Ar_Mq74~(7P?sl-W)qM2)_B(Lby|-I@ zXEAXq%*gL;ALsPSL#Jjh-|093JT@d}+V^!8MWZ!PA!~4*Zji*uPz&VryW)y2>91 zXEUerpNjC$EqM4zIKg#p)kXiaW!GNI1@X@cd{O%47WX+8+u*5RULIppe68}Ge_xG? z)bqElKV|v1CT`7{w(9e<1CPa?G9-O^Y$lM!A{osSy#&$Gg~XBulKoVUNfU;-Ok0&mWcFu zF5SGeVUm7ZWpb^WpQn+`1@4B||Aly)uN!?$Gfi54(aLN7KTb6x!O;cay%3NHZ#q=!f-cvDofg_D^S^TQ=Z|z|UP`~&> zxG>;HM$L(Q&UH%)J^qT9O}$lCGPOeDY=_hnv6xF28#MpSGv6FwWw5qswcn9R9jjyLxdN^FsrQ)wSaorv-`ySXGw9H1)~DCwcNu+_V?1&{TVB7Nx7p{V z!oBthmdnnhh;jFwIp*jqnCG=}j%qinPw0%q4C^iPc{dz;a3T6#h4{R<2N#(#w{7dR zQ@&bWq8x2nREhn9N^yqmhAZ_}LJ$7+f$OO+gPx?~?PEz0%C(V$38 z$-2VkuYAU<{njW)W$4Ti>f_j5X?Ezd-(#WF7Mlou{frC0{nfRnsQ*h(-tzK|waHZ8 zD`g?icU_L&nsk3&M?#Q>h^sKll$?@m9O}6521-cD7Q zduyJuWWVK_8EdXrCbbJ+%YU6`_2Y7peBe^PXTOhfT=;M{Z2B{X-Ft2uh0V(S)xi38 z%f|(qMSNO5OuN#%q4L+4x~)^r=bpM{c#$isEbdHQ#3Z?rxnlnetq(q3o$3AKd)lL- zlY&7pE%z-hi9C#dqRTjGmI&{Rtp6*-j&v2<#f$lFd_H?s#Gg63X%4$L{hBX+F{N|e z#oUuNHd8FFOFX)08n^dVo=6hko6_T6hr}DJy=xhpFZOgZYc1(xi23=k`QCy36-y+m zQ|3BMne+WwPKAc+6WdbO$;*nAc81l?aSh#Eu)6IQv-IA&r%A;p7j+x`&YHb(y4j&a z!ip+?Btv&MJaqZ$8_w`T%4K=MMOQzr^OnbgbJT@@B%XVc5+Hs#_TrNMw+xFcKdN|z z+%DtOnC<;8|Jkise_gES3iTyz7vFsJ*z;5MvnSn=)=Zy&T*j=iVzT+0THzHxUvTdd z;kzk&gHu~BTiNj9Qccb&zKb@B$%IMu$?dJ2{~H@3S`kflGF;!gA632Q&DW}b zB9P19JiWlY;pJNgt0&LAo_)HpDM@VpD~rsO`o6|XhQ;-_sw9M;Sv*qDaXMT4 znO%FzZV1U3%CA0j>#BkENk`_7Pot`<%yZ`( z-o5=QY0^Wjvo@0Q#V)l+5?udE*X+*OI%Dl?29;S2bx*Q#l8t1NQ&~STbp7}2x}WlX z^^|4h{roDY_<9As9<5O^KC;H~b?<}=zqYR8IJH@1$>R+Xvvi(hZ(m{YzVV!*&EJcx z{qyn;+V0w_;VPzX@>+hU3g74NAO0?%yYl@~H!1myhCMtDm$DM>{I<{+Ib=LalswdC?K6GZ%z5sbqw{c)IG3|C;sp zwrMU+xL#eg)Z&Wel(_0!$5+1D=pxB{QL#W->yI*{zv9$}yMg^&HCAUY2rySB^1q$y zlvw?LZEtyY*cq#nvj0+RH`}v6-BS7CXY5Sf)gd=p3w|H2=VEq0l(0*t?oYMrG1Dnx zdzKk4SrD=JeXh)m-L5)c_GeV@(p25)7OW>WXXB?ij{nb3*t)i?{K1op*P}RJus5!n z*e*NGD0$wL{O@g{f)|yaiL3iPdUL1i(f1Yn-Sy52?S@^hCX5evMz4Po`;(F5R#4;; zZiRxJhdHyu&2P?mwAy)}uaQc#>4~E&_1B1Gzy9|%R;6@h-laZnuKepxQWu<;IWKfy zYs#P3)UxP>UF`Af8ji_JiVL@P)iR#C>)OBSNl*)uWGstr9_tnFXKCM;rzmx6ZBe*y z@So*j(*pT>nzQ|Vym$rYU;O&ReRYuf@ymB@3pI3Cn$~KT`gxzvNmQ@96!G_IvI@`p z7p^ZQzo%a|p2XYiEV+QO`D0f2{k(%g=VSAA4ShURE(QJG`EIR=stV_Cm4rQKE$=0+ zShb_>{zJ{RH-m3X;fy}5B|hsakAp_oqLAJFB2QjO1LbLZ?rrMY5X9`<~F7r1D{RfmsTPtID=8uGtTeY5He zmlHK5D=Xb~-IU|sOwhP?9dSy;_y} zt>3cn;}`Yb8Vkv5YbN^ph+R4&C$sOOb?HO-eNmzOdK^uWyL}an^zDn6C#ENCo^yGT zlIstf<=c|iFL+m;JAcJ?m3^g~vK>w~ZoTl1QEy{nq|~YQqiljxyesclrPp#TGz!ou zx_9BQ=ys2nbrLHtC9iH%RbacNa$YHF%B-ENyeoOaay67#8K>2nnLZ2sD6n70=9RCh z^|Gn2Tg=wB{+-X1a=GB5#U9n|DOdPxKNWkFdwVkPoOs7$*1miFAElNyEZrg|Xf(CE zLF0h#zMCvYNv>V1`S&*j?f#qlZ}Z#fdlgwucZpuQ^XNm1-Ln}2KkOea=1%#`vZa0T z!vz<=c$Ae`y}B!|c5Mcyx76iu7Crl_JdIn|KkAyRw}mZva%GK5Z=;C8<7Fz{e_w2J zf0Vi3z}bIJS2T})RO|6?+Y~qLTphl#_VYHYn#adop8HOU*!=BUo>+z06jsH_$=WFr z?u^cYYvVfXbSBBHt6Zg>`pv~gZu|SpuUAdl14TUU2J1NVU(Swu_UaO2=LG+t8{%u6 zm+Z*g)S&v2Pfp4@=4I`b=#W7C5@+wQrEFL`5SCtGP`f0=o2%(<wQp!e#0y3IwX&AqJb6xTtIyZB4)ztL`lg34YD+pyTM@w64;0w=SmsJ!}TnZ*TlyJ7(85Wy7w@5BL8~ z)wNg8d*^nG0&mPiU4oK)G)_wk(lS~o5uZleYN9sK$o8hKt`@@(bq@3R(8JyKIFee!H+ z=h}M(f#1_j51el5>3XZfVYp1_LHX4>Q|GgDzqgCc1$OH)dl4^Q^C(!VAA zOz9l==a!v27#a{8>H$ zQG9bv)Bhi~E4r++Kj-eA9qXRDq$_{^)4TfNI`-;!x9;lg&d+RlsQGB0WM9tOhdEF7 z8JIQRYr3-GT4X|X^`ZW?O9EE9o4jq6t@~lU%b+*xV`>6d_>IgR1(*tr5H zS8WNbeZe(5AhmwtKR>@#R(|F6yW|y&8wu@{${1~*u~ zSfb;?9?r8~=AzK;XGTmP{u{cnx<8*>yG_gHibjN7m{|XQpAz{WFE1@?CiK#4z44d@sho-fF z(S+ZRW0Wn#Lc1}C^UQPSMjH+ZkEPEauWhWF1)utWt20+?Kao>B^$oH zYWl2vTl4#poxDn)7hT|S_R3n4{Bqj{m&HsQ`L&*<$=P1H7JFFN=1J{eKJT47We;rT z&CjqEynAs=r}n(10`KoRdh7lc=8=nxQ#?F#$GfAue~O=FJG%GiEdAOqS883P7JrLN zm;cpw|IW1skCe*J`Nz+`cXrYFuENXs6IJvVp0D;hIbT%qkZIXdQPD|EzvN@XI}htiy*hm3 zJiFGu{0s9gt&Lmxc+AZ~eQa2^Z0}0-o&zrz?{GH@+vZUF z;A4={0c$>H&r6C%=8rRU|Lxsf3n)LqTHmu%W7P?9=@`^Mj`N^5nG?%5-t^PMSb z@-dfYhOcZ_jbmIFyXmMid~R&qx}vS~u;dJ`H-fp^D^@q~iTc^>4Ooym`(&%SK#KbJ zLbjmx3zP0G2wS-HGh^d~$=cSgSCbFkJ171)t4Cr(?9Vs zGtB=+ZOXp|Ti$tmUi;{E+o#%3g2f7%jRzjRlY085{jIsVxp|XNe2GgE5S~1*_zj(MW^2S`=x7=@Ds@$WKCRbkQ9Q?pLW%WwS znNwqzy#8_Qtnc#uZ}?7HM0d#;RN|1) z>s+-O^WS^ppK3~RE}F!6KF#mjwMCLYr(WF>$-DknU}NlLPLsK{>KCnj<@;Q7{|7(w zDXtR^*Oe8V_(;UX{kU+RVOY%%?#$F>#loK+sXm+VpzGLOmCp6o2j(ZevrYGM?VL*tY!U zMy=^05ql@@_-fnsH`%W8`9`7T+xE4z7Kk}?ssC(koFnl>X12<1k_D)qyj+%O){%1$U{I;8nq1En*EI!#mNtNyl1-}{F zj(b!m&OgTXPuxT5Qux1_2gNnkYj7;@-Z*1J&EzXn&U}0Dp6lAri+w?7Hm}MvC|LaN z&(8V@`}V3Om*%>-{_PJF&SqHc zm7jj_GynQEe_2^Ir^_>x@@KLtURTb1**sO$@QUIuuT2(zPrW+*`^tM!G5K4&XVpJF z{I@*P-%3Qje`3ck-Jgr2maJw}-goKC^?!Ol(p}QMZ_oT~X&|li%Jfj|EQO$w2I=Ix z)3?6aJT-RN>&anN+pgbW{H^Zsrq{OJBVAW;_Idli>sM9l)IYQNKXsPsh4Ue`sa`&Q z2Pz(izInhW+L1Q(;n(Zo0+)R=>>h5L!xEvy-WS%fZ-&uU+d74%;+Yp}3p0=D6{zX; zF>dEtoZvmPpDW!oaZ1-I;SCE@8G<%%T+{taYMR%>OZ<0sFIrk}xa(g;Tl8H0WREXv z83fkcPziq9g7s6W*}Ucx`M?x=EPFMvJX`oUIS8 zJ%8hH+1i%|dNW-up0g-f`R++RfAGllFlGi8x8;>9@87>EJYzw7g_9YNBTKLO-{h5f zlY_*2m~?&C@yx$e`0kMruc^rKvzl|A^)KFEcj@ty_*9>@hVO56E(|F+Sh+rSXC0%x zkZG;ybGCguyzl39=gR(nbHCb#S@!#ro$u~VntklJ`X8>+m+BWDCyOK--fG$7{&L&P zFkYGBXI)cgI5ia|9~5z$&!e{BVeX_6W$RDX6% z+2^b)?(||F<0_XAT7p@TON@1$XFSVIDE@2BJRzq+Rqx2uZ7q+);xm5otk4vF*%0eg zxyzYjU9-N=$7=q#l^5#|et2_b#*M9RL6_ULWId(|J2j>(t92{Zcs%=x;5*s( zMg>YbUhG-{f14MC)c!ITFjR|IXYcR0qv*A2zQL4lo#By>njhY061&YJz4B6q+>T~0 z$rHld3q5BPeS7gr#Mxlx&Cj{3IL~QrnPIe4EX4Vhl!xEt^V7cNeB9!HYvbb0>qOY+ z#dys4{b9eEm-Loua#UV-{a! zE@_^aIkBKnZc_b>eUY6)hDPUwIIZ?1HFo*szP0T!wrTjZ?{{TzfRXUVJ^j|qj$b8a zO=#Q9Ucz=>&7<1*CcmDq75|53CFf}h?@PCK%=pmoDE1@YpByF^IbVxIA$DEn(Vbmt0&x9qYTql@?N5V>XeG*;t)m9Uij-OfoDY*s&EI(I-dL2h2=zr(fj zc=gw)Nrh^>pT0xBXVwqR+@|K9gBksICVxCIF_XK&{kLu7tMzY0X3ehq$!2G>V4BCa z^G2Ij9aB%9d-wAFy#^gO=BETdPO58s7ja0_dTrAhu4z{He|P>C5`6jQig1tnf401( zC#ElaeeuDB?$8^;-#FquR<2f9a^l~en>P+kbbYh&@y0*hzTd(Ebk^VIwTRptwYg$N z@sn0Nj+u#F{%3i%ykuO}->_lLG0)|4)0^T}i*iJ6{(kSbjLTD}hUA}N;&gby zCZG1=(L4w7HU%G5y+w?oYwCojcZR>Np4?pSq|)c{q$Sk+Y1Fx-={o>kuKx^sU;#`Gnb*)y1{Z@{P?T;Z__o2_jQV@>dQpB3sP65pAbw`No33WwOVPelFZ88&s%TZ36=MmCU)=B zsdv9zf{P3zONuvcI?)k*H;`f7zq_GtISd+&Jx@&Tx!dH{`#(qi;fv$)Dw@$&r;7i4 zx_F+o?e~JiZkj)rA6ahQ@ILwfW2Oho8ynwB*B@|ao_^?*p{b$9pIW`MeE{^Np z@uSmQ=XLoMw@#zgo>OyuPW%q}=Y4ZiMbXvMYtKsOE{z1$gZ|&+ z?(C~L-Vt1A{J~Q2@}BbLvJo>2HnegjZpr%{aV%`!_07kdbmOWX^t|O--C1bk_iT>E z$#>u5zfUanUViw7c!ZHpSv>n2Ro=B8zdnSl2@iT}W4U_aMv+~CavH&{Po{`?wK%_e zYJZ90<^H4tl0WpKuP0k+T9mE{5DPixy+QIycTMWen^OB@_2qilZ+Iv$=F}%LoVc2k zHEVfMw3+e24dvO>PyO{dwZQXij6{UNVYNqfe;iLN8YgNBNb=oM-FSM4nxFBJ{=V z_IVkLVvpawHq+{bzTOGRH;KCgS4AB79W^hY?$#mAscJJLo?3JD|Mt0dbn73XZ4s~f z_y0>-JT2q0?%K4aB3Cy5G_CY&`l9;nS(BnEuVqWvtR(^SHYGs#Z3SOL6yovj^ft+TEtE}@^)aJvY*Ddr*BdE8>*z=R})d->bKKt_#x5 zy_xS`a#}RJ)JL6BrL;@bz@}#VVRgi-uS|!nrYJt1-OjOh<(wtI*Tt;m@VWNk#Xz@@udKQ)Ow$f`ymP+b{YyZ*uFw`+H)JE{v&Xb`HxCSo-SXw4)y@8}_m3 ztvUJqt}uVug{fUKtf!}yrN5o~gEYd!Qqc?wi8{?^S{%FL~ zN$>1jJDsH-nXUc7qUdXO=ytxOrHaN+ty2jZ(J!{Vn7eLTeU;+7*!TX6)h15Zw$`&% z!M1)yx2x3V>5lWB?zrOnK*qYv|G+h`;G;{m_8P0VP59Ttn-_KcbNbGywcA+dGu!Uh zxbp6}^CzB29yz1Zp;R@K;`H**K`p$U--W2W!%_Pp2R5jM9@Vd3{pD(&oDvqJ7jEb0lV zaoPD}!RLwk^O3S zi)C7U*b40~)hC+gS(aw%Cppadwq|+KwR5J8CU1`mNeLcXT%7B4ZHDdcprpjV<$?a< zG1V2^W?k0Xs>KX7KJK_wsGIlt#k`&A|F5i=#pDot{`w@H>&?nFs|uaU?kKfBo3tS0 z^QO~3*bOaOj4p2Fe8!k6@P@l3SFpX~tHIXNs5jBC9*5rCzcOMPv&cm6^9)y8n%nK( zf1M|jST)Imd6$oS;nLJ=X-gXIW@Xf+ykpVY;&oQD+{(m>W%*hq`&XCB)eWkyC;jbe zeyZo?T02|GXOi3MZ*B8c671_Fs<^qlHqA|#aA#ctx0zwVb%wT})OSZ@ay7Ti6MZY4 zxreF1#C1n&z3M{cHf%cH%HFD^t@cE1)m@^_D`n6iiOiE@L5mwtCFee&W@*!nxsPq?yM@+UnJ z$iBYnwe{72mroM2-wJ-x7QEn`-gHmE<#c(D2 zQs4yZ)X8s_ZBuW%m$GZ8S-bDEgc-f6_OI&Q!+Qn!dBrOA%IbI5`I=~@ic)<2LNDHRZmqqCdbiwq|AcG{4V}r%4ol~M3FBYc=yhRc z;OQ{U{ktqK7hSk1k}$7<*Vfjbr{VQeOBI%)oc!;Kkr&!0b}c?}j-%?yS#b-lfMs1$ za}qaR{Zvqg%%cCu-3*Y`P}^+}C(Z2IO4 zre7y)UKLZ8wD-Dfx7pO?YgE_V`DC76+3)h{Wx@BSArB_+o$2j;!^mXc@1voHZeQPc zq_;@^4K6mC$0s;z!DU-7k4N|3hUI1MDyk9M!@K3{V*dp8vIOzYE6z?XR`$~qZd?f6 zWnOgQ{;pGH4=<-JIj}3N`P|!g4Wi%eO#C^$nH1ID_gBvE=kqYWyM4ijwWcwPpMRYG zBP%)V=Hp3C{2z~;3^*LOt~BG9!=JNB6Y`BzqYv$!_TY6;6RYL_QZAE|YjYPT_y6&E z5nKFYr|V7QLsQq;mmTykNbq&wnoyfn(`?55K3#!l_2v>q+MCIplA@AF!maY=(bx^&&mpR)_aEkt`YXaXIW8Eb;*Gx$M|DG{4%-Bj; z$9dNhZ^`ImG9UW;zx#ZDXw`1v8_4RIL{PA>`5DxF#T{o{=_KZ5MED_^dhBeg8Fph0a* zg^ci}?UjA;{AVZjO=$~S`E%8kUBW^COudUeEd+!PAG;xG7e42wpI*(K?Co3bw99^# z=W%Lv>`W*-{IpH{l#GXZ#QIf%pH4SN?9&h|7c7~<@h3;NtK|cuYJ=;|jWN-Q+9w`z zA1)1FmE702?}J6$*$Kbf9zYjk?(@t z6q`v+TuY@pEXCGEtMmJd{$pt8yAZ$oSwvpNnaIVVll>-`{JnbfPCJ`YN{pIo-s$R9 z2^(MXotf47t2k6a()`5<6`6Z#zb^#5TXg;w|C7ia)`HP<;;mhj%&J8M9g<#jy^mi1 z%B2X#?J$u=l96iNW^XVn{pyL^^4w;C}sb7 z%&WEcK4-Ax@b2B$GI8H!G5baAj&-x7&EhR?3Er^o$}VBdUbFV|MYl)VtX4M8iBClg z8e?oP9Zs?mT#%h|K={$;^gBMR7h^Xpe8~RRX32sIo|09}1r7?8H@?{W$$G!Bj<{8N ze@3NSlz2c%=gs{;Uv%lI`o*p5$d)oYf4O2whkKs%{j*6a4reb&&R(^`TK{FtlAJor zI-%bG@43IpIR+H_HoPyH@ci1^BcTwd?p|E?SzD*c@0pXJ4|*)=P&!Ho9AW zH`3-~>{GYigHZoW_6{^Yj# z1KU}UP}8e%w>Fr%FWd`l$xFjZXjG8uKpRqjV@d_?Y$lNp(DH z0}e|UZjM>;%H`Rri&y;WVxk%O=P2nv*4msY&VQr-YUDzbUGs!0R-Zd1vG4VQ51JN+ zH@yni%hmZk7C04au{>K-wQWm;nb)Sz-+%NvAp&TPtzuo6^!Xbm>c1$TP ziXWzW#!lq+oVsMtYDmx&D)|^1s0m<9}Wpj4m#0rSy{@nAp7Erg75td;AT4JU_J0KFee0^QM$d66e?#zdf&VsPA=? zwZ|f7jWzZ?SMT++rfz((=;!jH%zXx1!_4e{9gvyJ_4SDOzyAkUUpAcnP)@XR#oAPb zX)h#XyFAur-D}r*UZ#4#bMB&GrFnA3Z(BFcThV?yC~&3brTNqAZoB6zWhdKM3clXw z{&DqV?->SG&wu{fnI>}a+Ch$5$^ZXF`c0$Hvc&yiG@klcO#h|%oOOZ5r%&^9%1+iR z_g(UyU;Gr4?&5t@SAJhxb!F?F)|X!2Gz#zY8?Jh0Qaf|S=ZVwPdF#F@=gU85`<`h$ z+q769@7tvbDmPxYF>9=Tu2}gnUgi1Lry*CTEq(l{rb~nA8T;S1nNiBSw^@A7@-t^S zX}vKq^_ND?9Icd_b(omJsz@~7I2fubQG6}7L^^9L1&yq?oH#IWXAI6 z{iR-QD~+E5o#G$QniRi2`O3s$*N@8Xva?Y>4NebRTVGA8o8t3q>kG-%=FHu1Wk0{j zo#L2wc(kT(V3r*ob;}-Q_A=B{s(4N5w9n_tEyjWa7MVEIq=&K zL58Y3BAHXCm&Lhe&R|n8E1BeC|1$Zy0;ApjCAMiiBKtUZy5*hHX!KVVEqrS>_vwjk zi{O*&_S=dm{9q`=3>4n*gtGoQY zo`zNbs$uNvxfyY0fvbp{wyC^*iTw-Z%8p%KyOyv1$L(UFQ|SER#@z+&Of7wLcAk*o z6`8cz{>ozG?v_O&{y$F#He_!#0LRl7)uo4i_)ZCz(MuHj8y`26c!EB&}4o(S3DW^o41w%BrH4Gsf}gi7L}zFvMeaYayX|bq&E2Nv>6t~Frk?)vZogZx-|^dxC#{_J9esCWYG%Xq zP`>~7Gpl*aWTzjRu;4PY`|7;Ahdvzp)gzkWR__zJQ;_|n^qKvuDhlGVDubW7@cus@ zxNt#?;VI^-tjzG7$+{1B-&(p{X}Vf-Txx)?Zqma`$D}wD4Xf`%Zjfwxv-*;1$FscL zf6Nme#j!}TPmYnx@6D+HyCS=-qR%A8%Sd}8k8La8reCSwv<1=*DPGi_Sn}K;o2Pw4 zf_d4*p1!k;_uSoAgsSYzyYWNqwSoTjihEX)i%csXv|q^DpO|zqrnP2)ft@+;hi&iY z#q8Pl?bqSLX~F^@IYJJ(Z|}Z#!eGbba`pI>itCqWE}g*?SaR=a+fB)iuHZwHp9VY> zm4CaVOg>)7=jdvyjj{93%zTl(^z>TCts#HYJkLh3+O+XAEID;*#ot}l7b|7%^0OVX z;O;H0U+9+*+yD8%W}#rYLl7GJ{`Ss3KFV&mCAj{$T@pirDOr1@$V(zG$ocQvS{W_o2 zWaZCW6OS)6;9!i>4dgwY^Uc{|hoa!Mz10FX8~$8+UZgDfukpF8D#Puxj1w$Q9fEQW zkIt)?*eI7se!afyZ`$*UckkFQEt#{ed2LVm@3t8hv4Xc^*nf8N>?un=@>Z=YcJ<#S zJFI5^u1LKwZ>{_l9<49ycHWybyY5I*&0f22f8Jj=tI3aD$-(=hH)&`+fPlFwoo=b>+tg_I}?WBM3jUNk_e~uQ|-sYzNN2F3LYGdSyY2T%J z1lDRVT&ccicco@{`+vPNdVW0)@w{Q38*XV#J~QX?**m6@W^a`hCt6-qd87MegGpb? z-hf>PU#2vz|ChhnM!9jmg5^Z62afffn$tZ}pE$~7T-vI-BhtxS)Mdry$Hr1O-u|p;M&-C^< z9d{C#ae+tR{GJa77JYQnRoK>bd+xO}2AYYBbldbp18X{${GAl3)u;6NLr~?Wiy}gy z4`Nz>|L#^^Z}HXc$(_UrhGJ*EWzP!QmaKX!Zn%5VX7P<(^3O!In4=aK7tD;_Q5_p5 zz0XT0Bx0%7I<9?>H$|}pZnS@9$7KzX0=Rr+9V@;|Nrbe2YDZ*)d{SL zo%ngXgQ3#KW54yD%-2{}8p;2xdS}JU=Ede^vMYi&-4P0q)xF;q_<8Ym(MMjk8)uex zDD(Fheq%`JR-}olqdWtAG^#% zpKrIeUc7Lw@y+z+3S-;HpLT3kxh}aoWrl=g|E{xFmv-z9D%$(?#Q8fvesc6L_6_3V z_S$8m*myJW+&!TjJ+S+r6ukkHxhq)+jY}9t`i!}=PFuT z1C4k#**@FT%COk4wdv0z#gbmrpM1B!M);n(_qnvnNZeZP<;45q51LOuttgRsocR1e z_r6~nC){9C+N-qF=itTe`M2K&<@(6D9a_1rJ93eNrhaGd1lRnz4Tq*YSeP|yrkChX z#locyO3$Sh+kRTPX6=z$DT&YB4Uby#R3Gh~zNX=a_SfZJ0nP8lCULG5&w95f$T;<&DjkJ@4v$ zv-oUyp~^FIk5IgF#n<+tx#HoX28q`jyO*%e_fX@nd|q{}cisFcwgSSZ&3O{}F05rs zzH_ts)iSrM$LnH#eV!zJ)THMB$wR+8f4^)9uM7Uw`tHY~n%|kbHU-^CZKe3v znMMjy8e1K|amgG%Cs*jd zj(^-$t?@uu&MHosb79YH-ETofF@1LL_CJ`g_};xW_Ycf?oN?sK#93FZJ@QW)o>}iY z>7G#DSLe%T*w<+MU;b&s{KXfaoO&M}K9h4n(&NuZ-4tNn6ySa=xy6_&a8ays3le<|73`BlhwwqRZEa0jBkt-{feDMjj zT`98u@phe+-_OpID_`7sIb3DdLfuv?kI0sI@g+0ry6*+BeTe_`=Xd;?6ZdVLmS#67 zuT4!0`@BcdYlFp+=u6g(IbRhw-OcTfejY7$YSDg?^L~lKpX`^I7XB}J8ns~#o9+{b zU6cB4Ckt^rWuFuwTq*O%gME%{SdC<4qolsuCQtSFRqy+DY*voaK1eMIJfjxT0BGUqKL-ruEx)- z^tY~in(FSd`|?LumZ|Lw?F;Tr+$nHi$z6tP%hT*q!)AE5PMG|&V{K8NsM7jd{?}Ai zibgcSSth4;~i(y)lW%nL`T9j8lC0WdZy}UJQ>#Br#`4K{q(XW?$wqI%C z!93aZp#sZ39X^kxuXHDs3-<3@!I`vjtMK~Szk_$Q$bO7c+$tI!e~{(t9*%|o&dVPu z_|ma7RAh1Y74b>DoCX)P)7Ra-&fs3UsQ>-{gI7FX$S_>qbGfVifR(@#ucKKDo0`Mj z+h3U4MY(;-Jno&bm*LMczn=ZZdS9F)$Z=G`3tA^UEA;_^#Ao;vy@hJ@O`@F z7_&gc(ot4$(*r@x-RTGY=6`y5?AY1Q&XOx9nk89=zMIBe=ez&O#E80!P4*|xd{-<| z>p9_h;-YQcmNmDu_&?uYdh(?k)8*0F>ek8zx^_GpRZvdeh@0-wnDJ%gd;wJy>}ApD)|ETa}8Kk-GF}LvL$a%RlmjCq$ z7MG=Gy#7F-o690}{(@P5Wf!emo3!xN#pTChwu4@U zO*_JtK6PEjX_kxjrNZ}(jx9cUYIfi4%#+HWE`JJ2H#)vi@S4Awja;yn!%gACn}S5o z%c*zd0#gHo$Ze!lKvxwrPdtMaV=EwyLgF2ikCO73YC2yMN} z@Utv#Z8J}s_oe+`y65oa_I_|$FfVnp*c=z$E$gybj{luiWBm47?Cj(GHjO@kfA?x_ zxUDcn@Y`d9y5B-uJ^DWW<(TsO=W!%ecJt_yg1Ma|i!;2{UuYy32k!wpEd5 z#;%4p*N*JFd3Ndo+v!W+uy49O;nCuQA9wovn|qx5tDk$&R`U(BbhNI*F&cD3m`mnIErV*HPe%9aMKdMAJV%S*m1%XX+KZ*)$W{`MDxOHAtgPm`qe86q5} zwU%w#a^hn~|2u12xq6<(To-SBKWLrVxaW8B3FDA=o!WaWd2{F2&a|9*q3S_@mJ$D{ zq{>Dq$#WsUj`ThY^Plf%!R-)c>D4N{`|@P7Fa_1E+i!o*QW45^W(I89KP0*xRz|~sk;BV^!JwqPTJ0?D{pc&UCNp9 zGdSypUY%#;z1<1%{hA&#l2)DLd}yQiYj&|@(Gx8<)mD4D{jBnX|)}gr}Djhs;Y@# z$mJ(5C;Rw5yKyGDrO@r&$!QTT8=2-#J+o(>cJ>;M*XB~oJ^PPHJ#j95i1m@n~pFZY09hh1)f71D{aw;04H{)-}JxS8h3_thw<<4_DKh6e6%$krpm6_T1nc8wM2BswpBL8MwvUg&%p0CC}<54c- zriR%!{CMYW;YgmEvipZaSDSHDx{3&s-w*yvWmgaRgh@O;_wSq6W_h7o*Ux_mKb#<} zI&aSABPAUgLi?#8Y$9^4PoL34Mi4(kC8ptTgY5KRomFO^3{94xdh2 z{^nE5=rzpG*%dJH^ZBlrZLWCo)1&3^%8fl*=1Dh?%}{23QTt-g?WJ-B#jFi8gX|Uv zpZe%=&x1qtnOSE~tfc0t+PD2FvT6dds!YWZb9b8i^J#f+dnI0{^f)`cfREL0cKOz4 z)dl-G7}Z?2J!Ibzx#81!L+|6uPyIVv8lYG_J2xOem1otQTX$QP)YwcDobLR7`TTKN zVXDL@jSlff4aK{eTM9US|J9n@r~Bh@-QRNuek6YjpH!yWeX7q$vLoccCQ-GMcRSRw zofm(NxzOw|XYPU-+`LyFED)WWcXsc^)i2IkA6TaAo%<;C{rN>F+cpY5UN3E6B5dsB z_3ZDKWs14%2akR2Ze1(qxG3UTAot{WE7rv}ZKcV)uM{0S;>^md1pMDF{H6Fy`j^+y zm@P?F%^R7IZi_5yF#l)Vuy}m#k=>yx@{bO_bPyUib2c3`dXZU)>bDLb|C*LWS*El(~5P@k9>h zGyZFToY2%Nw3_B|{?w+oMn&tq&MmzvXK>=eW##G9!YTznUEHMWXDOFl8-GRV<%gPt zDZf>dxH{YF5?NmM?e#qQqFK}J{O|b1yvFWKJz*V@VdZ~)?tHLcaj5)DRm8%5S9`L~ z@OoBXUzXg%dPmW4)!8ju`0g~?mpn5l&I}G;kW|9&IQy_mmb2Qz#B)1hR@beSd3e0z zt!9(Rto=JS+TLYP=Y3rz zb?XJ=^FZeP?y-LtE1DmdUo5u6^LW7T@8_Inv@VlMxZ{w&!&+DGD5vcszD*3xudSv3 zmFn(5AGde_Uf-L)%(2mm^5`u=z%)t-?~~iIA3qQXFTJjf11?o$NPji z+WGkpI0V(a+|suu$h^Ao@{|j1{71XaJJhkO)S58fcyz5#b+g6#)z8^#1htc<`@C*0M%8SXPwBV8*28^OnMb8&GQl56_%_aTnofEGg4&~1I$jdOFk>lFaxr!@97M{s@B{g%lOeEK&86lEv zANKWG1;`5YZk<~3xp~0>2_MddQq7%htA7Y@dKnu0oNMXX2HTs8GMm?YtIS=Iu`=*w zp3i1!nSS>f%(rLAa5%gQj_RKoEu#Nw?de$VNmEW0g~u#Wo5*UK)-9LhcC2DH^QF4V zwio}Nem(MW+YPQtzeCrK{hIIA_wN3>`In5{1&VX5#SAv=X_T?9R#%&K(<+{4j&rQW zWv$$l$%j(c{K~KYZDPCTme`#&viFtw`B~*G4DKI@aCM21iOgK8BI5eD?Lr0Gss>|<6?pf0LHbF|&V&%HM(T^J+uX&v*_|HUb^D50xjQWeN{_yis z)P3i4?Lw`e%sKxee%-gT-NN5ZerBn-XyJ>rW$O)ht=6{KxA`ICRX!F@R#*Rjq4Oq- z|G#!%Wmn;rox65^s(4iy$Wf=yqwme1gG~_1Tu)GS7H&zkB71NA9gmdT?Xr2bN2pV`4;;-7ZxhpH}qpo7uh4 zGfwk^S!cd%Uz@P0!YHJn+d|C5R_5yT=#F(7yPf3DHD^UB7#rw)I^3%J!Y$27!YE1a z@1H=i18PAh&tyzd>p2&)Fz26yzI$mx0z<*vZ~G7RA921jUwsc_!-lM#+xU(<3r$WA zZ9H0U|4Gz%v570!KX#5QEvqe_{y+Mx!$I}$hNUbXKZ1ie5(^R!FL)~_Q?ib`FV5oQ z%lOYTTcR>8*bb{*>pbr;Y&JP+V*{z?k>(OQJW(N6`bC(k;^eJ!=bS0^ zy|;C7w#2FRF&&u?r}G%?ah$bT;M~*5-K%X+R+>-wRkrMvrDcl4BU^>V{58hAYnIM9 zlbG$zF>4yn`sr`$m39lS(GB*s2<+sW)t0l*Gmra3v;Q|w);&AEo(MW1XLLy{*U!nz z<>#T9O$*yHAFG_%cVu0cQurSS&4`ufPKX}Vd0UcJQf+O_tXfntQO5UR*G_BUCz;%P z9)GKN@xnwaKj8GmfCtk%s^SjScb%A0W%%Rp(p~*e43}pxluFj5Kg(L_{HSi_*CXr+ z^%hTKUoiEV>nNH!Ue{RhY+dQ4?>UfvV> zvvBc@iA$oGj_q&Ua6@NrY0UeC)OAT^q$El~{Lh}o2 zaP`C3!Z%0w>^`z2&l@TZT? z+?W97l`?rzE0e{ul;5x=Uq83v(4Y9jeUgd(&ly_G(+|?$l?0a-RAeLGD1;d5N4eZ;Q=ZMEH7nr)R z_{bG5L7xvL;w?IIT^pA!tnd?ZstdpOD6Vi(P1D(+#_~;#Ze}ix?b_deVuACcSxhJ1N}TvyW>OWq<^6X<`DYi4eb-xPyZ=tkk2-xUE1}5E zYm-8>3}3R}pXVm5>W=Gu=PHENKbvIO(32yS{(Iqr$;T?JSFn2i&}xyHB|d#Y#ftg= zo;?#_IrCz!($e6#mcZyo{eFhs$D(}htjbx_oRWEY)A#n>FT!7iuglAmJ*On({-$y= zbK2Y|lMXJFQq}RjZE#faiox%I$K9{4FZAzz6dJehLywh_iBUJd;_+W9`!hSQx<7R^ zk@iulzqawn#cy0n>AUZFioWH&!+z$H=gaT4zq*_+zGVKq(6S(>k7ETx5RYA`oiX>) zVou+s&)xbM)>gc=>VH}~V_8-B0nfJ+F3di@dG-V@-o0hpQr0evd+Ryjdd-aQF_O#N zId?uVq<^rnpBoLdh2vxlVuO zvCcK~)a^xnb5kTP9u{e9vAbF_`NE^wCcN`xKHTQ%T*m!N^X&h3Ofxp_jqTumC@5TW z^WEGazRv>3H^&9BoBxQJ8HCsw*^;ljhd*5((FaC|CrIkBpCvUBQdW zJrlgINq_CmOLwyJ+`YVjO|z7nufII;ufWs16@5kgH-meW4z7$%>C!#({890ZOqrPt7jE8d@JODt^2aji&6byo zXZx{FIyfQVN~&DPs;>X5&EjU?ezp5@CF`t4C%3xwyMqH*B$ziE8f|gE$gb0DwSOMh zRWaf0#Y?^k+KbI%FiTU_|^iN|?g(Z5^8Rz37FG_(|wP`s%a>BT%> z^y+VedfO`}YI{rSj^5&n3H4*=$d8yfy=!#~gH3WsVgnniCBx^x`tLTMUze}CUh?~? zm(zG}y`3Q!p}KUQ>i4-n@>E)W`l=nK<i;xz{({4#ppl z&0ZE9A}hW4!hiQ&*TQF%P1$YUG&4Bjzlo%4l)lrOYobzV8JEkqEirVy9=+m*&dme4 zCKYE^$2v#EHD10o>9^p5;~KuV+&o-LGgB&BGjGd(d zcaI8R$0^qP%$Bi-^h{@O+HAch^zOg*SJ6CNAzDg#0UKUs`-PqqIxYUPfoGHF+N-I> zzm7S+nDjepPcpCa*7>K_oPNDNbnnsd0|IkOlqW5{cj`rXR)K1Zh-qxd+o_k{G_@Ms z*4O?UXo=Ca4%Nqy>@3YV9TF^khg z|MPbUys~x56;hwI!{P6Z%_{yY5|0+1=e=`3F{@cc?qc8O%~L&9SBWK^;Op4(`~{1t zi=w+yw8us6hP`KWH_c6)xm8R{x;)kR=k(;ui9+AjE69J}^rHV(oV4=Zb(K43{$8`X zEV*#0p8ENvHLsG|w#%;makX~aMfvBmZ#=%k{o>i}&ju=13xYjAe#-nC(Ufz@`M{a) zyRIKg)?Zb-i}{aGU8!Kj?u+6-JLIlUZ4*dhSogz6X~T=JUgr6~mm6o92QofvjD2=b z%0Xk3ev|d|{6B(|OsB?)t`l=Myc<@ZpvqdZ{l}%6{bef_f1F&^mvr2@Ymz04#<8%3 zTiwD>-&x*&E7W1Ft#jb7_?IgT8;=Tqxw-l4yzATUl}9|bKH6$qc6X$Ww*<5`o+IGvWy*g`@TWmNc9J49*n$d9kh){$KdU1>RawbduVDnc&;oNJFh(3F~YdPe!#X;%>F$GrcGg+*Ez*Zld0|hkCdWI$=5HOw@xZOC-P<4o4AjQR!qu!lN{v} z@SL~kMIvkDf#1t~kFB|>BWfmX8p5PknY^kfKOsWmn$GG8n#y<8jpp6kx%|)e>w*_~ zJN~E($ME=g&p4)Lgu|8SY<9yp7kaYnt&Qm_22vJI)kzivLEq?!2iG!O&Fm zkY{StVv)5)&sZ$wcQd(#-rstsYuC;b3zvjBB)v-eb5hjLc6#ANGY*d9@)?p$-eJqu zAWX@_aAs{rMPo%PGY@XY{*{T+NyHF++X%Gbtd*}#J}x0 zyU<2|%c_#J^uj$Vk4w)7G_w@mh!T!I?4s`bwsQ4CB}R|1yp@lqn+0&65V?4J#wo)t z+x1q$wU-jJC;fE@zdCjHoy|T^`|kD!>&dier5-v^<{LNP+Sc4wZqlW+Yu@596P;_z zuT;p?6*n|33CdYr9-t8!csSL?Nb2A>ae$HpKs{XP0LCn;7to13qSw;p16K}rEzx?X>`dcr$ zl4@AiwO&{DsT5j$llkD}a=#W)#(Rl}9IkO!sNMbiDJRurpR+;f)RN^QKpPjXM|u?v|~R&!Wf5#rV_t2-C>;_gg!eeN4UmJzd7Uapuhbwzlh!ePB- zUl@gzZ?<~Jt>&%0H9y^0XV?q!#x z$uAuw|EsJB$q=X(L9x?o0jeme154)~BM=sw6Q%HSzwVZ6g2lzRvEOx=76><-)eebB7jc zUjMi0wzI*U;O_NvPv^y?zmbeclsbFL{mRm92Vy4mZsP1!=F-W!vO_<}?o#i4X`O{L zq^mBP$&1c^JZG)@&iyuJ9HP=3KkFSs?><=mJ;?t5F$g+0NYkRPS|9lf`}y;%iYzw#5xK~{mUk83#|poah)wB<_xy!=eD}nuCr_C( z)mFbC?#M^AxrxZ!cAwCy}%5|Goy~}w2(EQF3lZ+K_Hs5tT_cx%UG_^4!YU*_85cRI$~KmHc=zs=YJnY|C!dw@k&cAM;OK z`lPbb_E{i5d+bu-ze+(F|G3{D`jhm0$Im^h1C-LW+PaFe*PVH+ukUqK=&;Jay$`0p zT4v0(^Wn!mx94@1J=w8S@N_;~j9@?i{_L`;5|fo?shi(?|KjiGPao1!AN`$m?&YiF z(|@-wv7h^VP0zCr3fWw*wGOeYusWYI7h5oW@y&`K3!fKkIG%T_riK zddu5I^FtpvzT3FtZ^C-v?Glr>XR{S8i?+;(4KcYpi%%*4|Gvfj$+3q7j^~d~t%=Gy(ck1jsS=r2tk5hllWqGl3dc5wmX&1B`zs;=8xly?G zyt&N1NqyE(SMOmyDpmrXtFd$%O5 zgFB4%n$UCp9$t6TNX_kY3uPImE?_)3y<5ZM>VzHEerI)5%)eUoDEnI8oOEu2@M*i9 zw{AZ$nEhQrf6@63-9n0niA+1+>73Cx`*4TQ!KZIK*Iu+ba>)O!qT7eO7%#z`DVzUs z30m!5|9%SJn>OcyuxF1Fm5xn}SZC?|w9iPJ-Qi9B)O`kZk6tnS;*jB3r|C57jkClH zvouw9r$1($D#mj2{c^ek`c)X7_&kls{P&e?O*&>`@2(c1K;Z(9X# zoe7)yv@hjMf(`FSy%~Rne9kTl*8i(1JmH3Gvi0(vQqI8!O()`5Jf=&nU+A%hd)F?p z6?vbtmp`-3h!B776wZ71!>e+|S#Fn`4?Nnw;BL5F`UB^AJ;yBfE57@jyfbjOcsDD* zd#;&G+IE4SRoTC?K4(8*5M1_s|CHk0!XKh0#0u8Qz1x=WFV1qb(rv0bmqmv?--Py$ zsgHW^M3n6Qu!$=?d(V&guRHFpP2aXpJ;=emP+ zhATe@D$koFT`+m;w#Rol7;;aqxqN5u)IQPtq9DWYlBN3U&!oNjH|Nd1u4bulGPKpR z-{PgcSB~N7X)0Ga_)Pfq4*yiNe7-UD=foSyzJA+3H^$9b>==AK>)7L%8cucUh72G!+!!bcf_vTosf`5J2uUc{NY1fP|;a`p# ztlzsn%Ar3s@>Bn`Co)S4#jbo7%bpPYZceqp^qZaktgQ{tEQopJ{Nt0izQARn|C!yU zH{Vp)?0;$C#bfw5Wqoqp)+L)6!xHbzZSLH(h5N1Y^{XEX>dflG+doI&d+W`zjIr^~ zr0Vng_N-gy%p7x}bXkVi9wm>c!UlJ*sh<|Mh6uespDKAt_wU5lM~>STuhCp>k=mi% zsuwDh)M0%@{YUus9b0F3*7RNOQ(;=(nph*Awo$FNB+t)W`0?}82A>z4NqC#P`>{Na z{{9aydlEB0cS}|YKd;;~W%rGDpTGPF30}J)>ga}x={%l0K3Q#S&--2DB)3~!LONoR z>Z~oD%O)8=*ipl{yTxv~X!g6F{(pCloc_D)g9`6?HZ{qpB)8?2<@X}z`B~ezv~osf zMJ=`P(z1K^@z;BUKYAOAAHLXTVf#33|L?O}PdTplpHqEts1DC(|H1y;c=i25}&i|5e zfp?}2UzqH=9do8S+(|v>;^(|4)K9|Q{F&542SzLZw@i<>zfg{o)R(cz{rW7rdWUtzmw_U%GT{ zQ}i1PQOyVwkrhnQmnQv;J0s}gzgK9kd81bRtevM>bT{sK%ocKPf%%iYyQ)@r=-!gC z_WYM~uW->iO`T;G=XY&6!f=yyxrN%f-1l#jPoI9gJA7~SC#I*S;p@eCUI%EfH$Ge= zF1_JGcy-&tOwrSu?+M29uq7`^Q52q;b3Je4*-6{7WOkoEkfUnj;e2VSlAMs0OPR7r7?rnO5*zSbUI(V|r$Kdhcd#%$U4`+h=;5#!C90{M)Kl|CN- z(kn1O>1=fN2Jw^bmHnr#u`)nSdE?-LU%m{^|noR?hAmOcN_jlit=*KKBP&bFVaewL4W!q&?5A_d=iekItp zdrZD?#{W%N7?)KQ+ws2Xit{H}G|p`Gn$JDyy@UPgKI^-)zyLiR1Y zx{mY7b@Q7yE$-fHAK1?|`HQx~HtDz7M=m=&`5WM(_^9}E_w;2Fx6|v-<+JY-JL+{t zDAI6|(!QkDgpH;mkMF#;5O+!|mKK(6KCj?*?!Y^q|Hr@QJt*Wb|MvH2ucV&ox2F?2 zWfm*2S?GkHIksBK&EdFnm;|f$jckX9ADX4t-PU_wyD;VSG80pdweRL0ymdoTF3w7~7zd5Ffh-D?$Fco*4PJzVtR^N+8a9xQnfyk){ZpRAXG zJZpnYH>F-q3N6u=P>fb9n7_m@w!^7D((&6=9+l==anZ8v556=t)GA)KXg(2Vl)PGL zQ@v1{lft{0);2$z&1Xx$O(>qO!Q@i8ttEJb4mMYsa`KaDCk(sRcd}*&=x7mz*(-U{X6tdI8W!|5<{kwfd znC}vvm9OPq?Y-}Em2H-v^wedwuO|P=DV*_q@3Ve+g zY@h#e#t$twp*uB36;?av@jOgq|MkDw;J}uPdzd$w9gJ)F_>oOO!#kxvxxSI(@{h(H zi^?qE)zj(fK;@iDir@x4h9l z?q6v$>(h}x=3MLg9bL=Ti!WTXLo0jh;UClVrY}pmJooQ35nJs_yPiscy{oqIWout> z+F;h6!87NpULV7*_BLhic*QmCXD|9@)%d@DKfA8-n9!UL#n~6)#eO|YHsqWm&2%iu z`T4WEUk_e>_+46YUHS@!mW4GH81H^qvKc z+YO`UgjT*Pms@@Nk>FRhz~H*m7tdSx2MW)%|FZ4-F}csjFS5S0vooGia3is5J;Tk= zsTW#L@tr;zyZYv_6vag=O0By6gblK|t`)BMUyOcrJj!KII}F`u98p{L+PSy z=55Lo*KF_P`n5Ov^-RO|YqRF_{`z}u&xOfC&2Ij;RSz@VJke#=Sl@C~?wFne3zOnW zqZqN$wVz^*@6{b^U9=?c#?l0}g2`*S8}qOHU(3U1`tvHg_$s!PS?3!HRHlO%TEi)4S9boZLD z0F(5diKaJI>|3S;9zLi2dTYiVHhaB-=I9O8-U4gm-*B`g)JMKImv;`E=zV!=XOs1R zd)?NVt%ZLoQq8|>-n=8f{N(h7YdLhI+0MzVX5LY^cZLGH-oFW225(M1I(oBC#>HrB zBAaiee)y>){!_p8ia(J%?8UiouVVn~M*}_C^@;PV6G{x_EpK+EMogJzV52Lw`i<~w zx$3}guLYPojY4j!i=Y3vH2UOX$9Qfz^_wYDmH(371}}LM{!acvifwenk7``BERN@{rd1UL>LamU`qU(znD6htY;C~I7jL)i_cEi<0 zv0r(%G1dAXPnGAp6t;c!`v$IPQ|-nNv1{sX{hQvSAa>%(YSWr&OLz?y8qQD6HxrZo zswgEt$$7&?8S_x?msS-My*4}#n-_gN=Gn9}dvm5ek9e%I)9iTqo>?i4{vN?oHQ#(W zSbp&8#faaM$^wsAdX#6*%Gc#)Keyu3-BA0xMh71qdy-(ed;gS|ne&yGJvbDnJ*(p? zvySZMg3VpWy;kge-r!OY$n?EUq+_oum*6JFE6uOVU*AtoKeQ!MMrm)*=jAT9#Xd1U zD7?Sip|=ox>?zFoeS4? zfvVQsH*78!e^B0$F`Gwoaend%#r^;%x6L=j4$7svcXj$We<)W@T zZ~OOsH&GG@dZYc7!E58|{pCI0+a$k6ZfCBYa(auiNMzZIOtJY|x4-mM&Nb%^*z6KI zJve`vNzI$67-!wSDDB$^1lKCFs0Bv%pL|<+xAxcF2R)h7AH?J>I;38*OWQ-==u1RB zyKH{xG~*xf`Aa`?w#~G=q9^53ZNKr$K>;I$ zJzWV4TQ6+R*O;%$m^f+2t$mewB1@gSzFvQLV2)Jb1F^q`MepxkF8lVA^S7;@QgET8 z-^YOU;U7QCt$%g<7Ef*eJiC;?8Nc4|HIbM;p>yZ8h$ZJYsWqjjJ^H_B=i2^ne;in+ zX^Hq5PPLbraq7yRg21Lto{4;(Cf}zVZF`lmYVW?(-GzQ@)6cHtVJOboDrsYJL%l4n zC&#lgOQ`yD>$3&H+?tKf4_^G3sK3i7>tNoMy2$Li%BNL0(=rQtyZIj)YnXQk>hDSA znmj-JLz--{wW{U3C%o;F%Qv;EG^S+yGWw~~(#yUoY-8nyFR>3k8L#7AkbgX`diVAZ zn`@`sTU)>Jv}p9&s-J86bp15)PL{8FJx`5A$+59kU*&AX`$_v8YfeUO->zF;axNwJ zUf8Cc$#3TiTrm%gPB^kIHcNT`*XRiW^`G{17fg0*`=j`G`GTjW90J!4D9JP1#?&6> z><^85D_xNE;_9>yCb^fn3p`?MAFmh4JoRy}&eT2bs}~s6YrS;RtcY9D{QOgu+1iP( zUZ*tmRUAHYGyc0r++?RZ_gAt7)4nf=Ie35R_sQWA*UjSm>Q}EwG^|W++U_I9V8kl2`e=Tw6 z^HT20Yb<{r$H>f{`)-4S@jP*s+a)(97;Q*>-|jZAN?YW??)7i;TaV~oHLNrHUb1$3 zNv!sRiI1nLy3EgvluuCz@G}$st>eBwq~?~IVu@h?!44766Z`&Hr|B-1E6JIC;BM&N z=STjQ`aZnQd->BlmAGSb0v_!tJjz*Q6?l}9NpxL+2vZX4@swx!O?OzPs2%^N_5Mn! zO<0u2)ulbB7D#{l^5)=tJ@<+m>C-Om;X7Ef^gKhg!%ug^Uyp0E7rY9bF;{WjLNCV$ zKbIDqRK8~!zB10C=xipt&S96WY@Y>IYFJOcU?XzfY_)g5nwHEyZ8y`X?wb?07p`L4 z5Hia^>gt}Pg9$JDuXm-L*4JAcaXG+X*(CLUDRceKF@2t}WYIU1sLu*Kf6s1A33PP$ zCMuBVy5jEo56lUrSA(nfz37W~%wEu(xFO?T?d#b0?X|KM!P&CnV)l2#J3aWz)%CA! z*s^Bd?j`THx|D5rZrzt1uzc_TwB5Or8=_+FuFYjL^FA-RZtI){9Zdf>Sw1}L5Y%Za zq{)2G!c&7T8$vv9a5?TuS zx$?4c@%;3pi&vx`6>>2+MP1pxc)o1Sk(_%uo9BG7-7a)!iE;_YJarFAQMoPJZ%$3C z+xJ{uHoLg}ea*aCbLEYx+pM_TpRf4Tb}*BTY4Yd!v4wtLQunT_cT8}UaAVPS zY_VWo^x|N_|Fx5J_U7hlpMNbAA^)1e%>I~Mec^0|Tz&Qnl8=_X=4wq%S4?8Cd+yG= z?QGBg=_`L&3zc(yge|h`M8#XN0deP8o9B%w1sk!jTW5cedq?G>JI)CBQ z=O#yO=f&t#{F5-bKAb@|IMwhNLDx&6`J||Y<`Mla%TG&+A9i;YygCz>r(tTMCn~s9Py4-YQ9`q_XHe4L zB$n1rGw;;pelsS-ecW+&gW!j?ZKbbOeCBTMS3eb_cU(ckeC7v*%Uf0-oMF59o^HX% zy10I8m3tk$;tAc;d~d}Y%{})?_xsuYjSC*zTA5@dFW$M;;Yg;}_mxR=YjbCRw3xs& z@6nd47MGliRFy*1inW==7ux=PczWl_s_lP8Tex;#|MU33?;rKsOQU992|u#TPt79W zcyY0sYkb$E!;DYvSDR{DCWNLibU*Ihm_K{*>ex+D3DW;;BPYuoms7hUmv;3};@PK> zrLmK$rOKKtZbh=ck9i<0FDqX9Z^|@b0hK0ehEpNU4;4+D*J)~qzP$ZG$79cu1ZGy% zeMK?;iVf>KLX22MRz+2uy!`)Udf=rALRq2}S}%JnUfnHx zbX_KjeNX$l)ymfXdyn<3H(DgO!QzUFvwT90Tz6vT6^Hek555;%9DVcYI{k%r=S;Xg zIkD={nchcNx_DB1wtijz>bw0)ixzL2vaQBbl#HUxS)MNyoN|U~rQ`f5hgWZ2U0ES$ zD|zmXc#`t_k|%Z5vz%O|=fBa|!cf5(_iZg>{{465J6SerL>cV1;aAq+X;{|u@5l8+ zlYBoM%#6P|$v~$|{(pl~*ZS2z?{AuT*zu37>RPsotkyZ_%efve(t3WtJxf@_;`)?s z^_)*fIcpBR%ife^AUq{p_n>3s^Y2^5>Zfwno5jgbsusxpo7cO1=iyJ=g;rteo z)$;S2(Z20^Vb|Dang`s!!esTeV#QI(x~A@TPs~cP6zgJLb{}SCauE~RvvAHzl`sFS z9DeGaFFdW1oXXUGt8B{@?F@D8}_jK`%ftcY93CalfPM=VYF>pW(2rkfY9aYIfc2Z~if&kq?&W zG#G#W{dt{(>?R?BsS-KeCohIr7B2trnfv_x7hW@6XP<~qy48QA?%YD%8 zgN=U8W!N6KV%w~g>%|YZFVj9L&uVIP&e-J5qKsKT*phOM-h2u9srvbzPd|U@l2W(N zOD~x!>&-P)|LU>g?W!Y%+UygIx+*vuG~JvQDK1#nuj6$+V(I<9$nzPgyh2vTqU?HC z_f^{+mzb_r?fk4-zbs8MfHQp$+gtlz&T?zt| zn!4Io-dG-!uY5NBk#1sYgY|;9ZHF_iJhPi69=zqWCCv^{$#;?v?QcPXpu^Woy&a=mz^ z?@O#oSHIa)w)KY?VkZq`=F3}NE?(Rez}+knE!ZX#V_&gIOY#0=tt)K8Q{QAe zP0_Af$$QByXv2lMOKmrtlY7G2b1^zJqb9#S^Xi8e%2qz_wkrq+{NCFA)>rZ42QMr0 z$gHCMA%}U)iklUl#P%LOIpLqjvJ)bg-+0>3zGyzl)I;4zOE#dgfA^WhTsd2%FA?UP zDSneYf0&-QP;cBF2} zvMtWdyLcwH2FSb03%pc5uu9U$cJ14Z6T?gTUIlHsZV+ks`RaBHKLINT|MHAT@mr;v z*Ux-k|L)YSJ=~`z?X#L@`2R=LSw=_i9D~Xow>BP_bB5E+_Q`^OCt4Ot|6W;Pe`A%$ zl9Iib57=Me+Q*o;V5;f=>3{kag4R7O3|)M3%ZX{ZC+5$|nBH)N>D0PQ>hgQd6GE4( z{_r_EQ6uO0{N3WF9rYKbJ(!=12F(|$+HV!h8#GVncT)B8e=p-Ve)~|d+wryBmW3}B zm&DyY`siMS)P$Y~GZuX|c$3_380vp_MT}GQj`bnUpT(>*-z$1*{owaI)$f%2_I2>- zgKw{}zt3E8QaqzE!l-T1)J+b*h402~xTLje!I8IVe_hzNs(qb(q*wly&M8-|7_Ah) zluw&xiY>b^|5KKy`jwAb_qTHTRk?<+^olp{cp-M;r0&kwe3jx`H=O1OI`xu&Imc)J z%md-K1Q``{OLGfEolAMDy=t8D%h#&OEiT=-cP3kAThbm)Y1yuHXTt@>-Sd{Y{P*7> zYJd3Br*^M2zOT^?@6U@aXRfKrnD*wDrQRWKWyk$9C#?52Dk(XFWg1c1rQoOF<4M!3T@E@}HGY-6VZt@pTDTofAxx#cHNa zyYck6bjNx}!RNbXCr|sqlPw_f|Fg~!-}t}p-CFLKc)6U)IlA}Qmv<}k`_nes8mpW; z-fL^#n5&Smn}dmIwyLVmDn-$%9U)s8bK2%k&-mc7tjPY--{QZL_p}9_8_T~4xJkc$ z{U=7c??uR_m&d*d#3?gbc&2QOY`m={S)LhNw08I5%HpOq?uyHw_5XdmG>U&cw`}d= z$C}zH98EPVU;S`ey6t2HtMI=}jiXiSpDLqyZvEW2e{JnU^Q~uXJY7DCXnQx9Irvt} z$4t5(wy^i#+-<*VzAfKiu}J5p$=0h3HF+z}U0DBS=`P!-z?B@zAOFT(Vi3Nx)nM`Q zyPV=aPi{Ld`Ss7z`{|xlJz1XVxf_cAJltqy6z67pRNwc#jI#{?ftrb?VlLlT6>Ym( z5RegXC;U@4c2Ue_nEozOQ75hM(-2v zI-dV&-p+dhhl1lGd&si?NlfI#mzhp`E?FF;$zIkY~NcM{1%l{L8KAM`l zWXI7sQ(rfsJE|W{%${ca-D=Dg6IJKgB|p0|DWu6LS;)jeSe{>E=dPO^DcV^Ni^Yzv z$O=`T&@Pqe?DX`tw87-|)u~si*J$bcPqBBah@2<=dPCEp7e9mFn7o_EI`3443zK<^ znEaeA^Xwnl_sG0AKJ8y%`e5oooryQs6r7D%#QgP*qEl`{b?Zra2`=NRsSOj`ruK!& z=DgmWF8I|s*T!mh&I8Gd>nxnwE^E!s)IE~9Wkb4o$n-aURUA`x@7UoOyiLz9hBf1> zeQMd;umh`lF1Bm$eysec!hTKf&T_Lq;@Ok(54_L4JU8gglBu6q^*$zDc_mnC)pXY~ zZJB&_l~rb**TU(`k0u9FLI`eLVfV0>=iam<5+NsLtCie(&~_qb0W{d;Bno+2X%O;2@vf zoZmavI0Ri``2F#o-ruwAcgzDaI@M=vWiBaGT*UXFB+Q}X(~b-E9NnKDaFoih@9AZ` zaioT$u8TMM+4Vz*X2;rj%swDCaniy0S%pD*2e0(Accw=2Uo)w?`&ThVoZ9J2Vmv*phocFEO z_Fw-_+o2)i%eA5X@>^cvTibtoUXD3&#%F1#-A`BMGZXx#Sxosl{Zq}fskhXRzPmW3 z@*R8y5#dYIX>AcJNc3B8ZcU+qi)Uw)9BO%AJ=(oX+ zns@!|XBs%Re5hY08(|n&Hf^oYhWMvRucxZYC#+yyyh7XHne3taDhJ>F_#1tAU(%}w zo2&LRTB!Q`>Ri!zXsfwF;KtT2ht%`w(o)lQsI?~uto^WVO>6zs7iBgA_4~gyXLvs0 zJkk@jdh#LjlN$2d?z`@qH9H{bLF19jyZ>zZ`G$STzWYTHKh{0Q zl)vHfwU4*YYhR9jJf+}O;(2|+b2nx+F1$SLjq!uimhVr!UU4@6%l~O_+Ez@H46r)o zAZ0Ch`qby37rr~9HvIm&xqJS`Kbb3RoM$O+%=Eq!Ah5EcLc{3wj3y)F>v|FOw<_h9 zy^GJjEOeIR+L!tJGo)9C=6pP?dQN!X24Sy|uWIYtQkLx5(67T6+mf}oQ1jK}yuIP~ z^k(awyzKcS)akh0R<8@EcFi%kU7RYn`?|sHueE%$O=a(We>drbY_Z+y>U{No+*7z! zgIjcVuh{2x>X)}emTX$LZoZMuoI7vcRK_VazFy~lS7&2G_2rBME9=u&r9GDNIc@5;b8?78*5MShfL|su zoe#1USFB~Idtc1XSI(NMyv%9O94&E^Tg{58|9W<~m9^}SZgP}Ml06}>rC;X~_VuA( z`oEk%EC-5JFW>(Bsx-BZ&;M25)g7tk^Gp8j6^T^0ZC`X*A=2vj-k3P2%Jpx)NN;^1 z(88d}{Qim436pR89d5JvDJ(O2{A2R(ySeQw|E@YTPyYR5cHzXj$bp2KZy`Ii^!7JcErt?OArkop2(d#-Q zzEscpZX;^^J1^nCXXlUW9(vY{(mMCoFFCVRdrDb`#?loVBpL%9 zJ1)j%@2QKQ9{EgR?f&XEUHj83H)d4X2EQulH83!lGwmevh5g5(?Jv1hq=mITw%KRL zc5MCDE|cpu%HJ-Yj^}x{Z~o!e>o(o9`26yag|<5T?BDOTucidK1kL#;a{0&HIluaT zNj%&ikk4QJb?^Rk-`9sOHW>CEI99#IY3Y;as&jeg2<8RV_^4$avvBP7c=}4PHI{eI zV@ZDDBYU(vI3z6QuL`(jaa`+I7-#*x$5Uoc)i(9BVU#dFsyst$MxRwu=TF}dV+A+A z*_O}lnZCU{ZMp9oOa3^Qbvxc3T@~GZv2^7}<7EyjzQ49Qf3#I}@zS(;d#{&P+cG6& z$b3(|X7*>A!Nq&J$A!-;8rI*^={1X58SEK;YwJ3{7ROp=uWFU%SaGpG(cH0Q#?7DSudr^k+#zwyCv<-A_o%W8-VaLmKe?{avwP>q zo#oZ|e7V zerEz-{(O_@sT?HEe?9NZy>0GE|GzAjb`FdzT9r`{RPul6$EZHuU8|g~`|jzR_d>%l z|Kp65y&QQ{&3U?xO_Ew15wq*K+_SbU8Nq_@@8y(jFL9Z7*(Vq)To<-m@@m!*nHZh! zqf4Y0S<5YIZJH{}KVzapA@}zT;SzgRf8|~8pLxu+^Y=OXVph8HuNB%S?UMdzYN&0D zKYH|Kk57EV!rp%_Ou~U7US_(V`+jZ~GJCY^(WTD0m(ucN`lJ$??e_j??z&Xv)9|BP zIKQPgpTwssyta zvfr1S)UVyK_bpVl_>ll!KdS1$Y+#G<9inRq{M`f?Nh!s29+?>oFSR$WofU(>#N z?T>z&u7#U->raR)Yb!W>%5SH`mEiDOS-aU5y<>PC(cHb&#dF)CudR!9RC`yted)gO z{L!5g+v~2)=+@#EoAIOc(;S&SGv2Qdb}9B&X8Wo*Z%4M)qVPmN{;2{@`~);H>Bq_mg#Re=O@yF6Jp( zrTj_g=p4~?)3W3MBt{n;&+Dh=yWm8Ks0V*Pp1f=Mqd-u+l+60lWj;==lZ zlPfQ)bogEK(TmfZA9`o@Gp1`Xb!z?@b7lw?b+Dh#t(4_7kg*mIfuidH%>?R;S^siH}lO ztG?Q?SDA%#LetsrAz~N34h0HN*y_HtOK{Vv{8t;iTQAs@w(fZM{Mzr64>%X;Sw&u0 z@$Pd+W+A^p^{?=Q%C;3MOI#QKiQZ~(=-O?W>(6JqhkyAK@@@A1`W~L=^Hozez5De) zes+tWN~OlqoZF_Jm)CC<+4}Y0f$mN34_`Br_T977mtm=L{aHO{CKI-4QR(~F?we3D zqo*pFBiJ){+w5nVF&#NKj!ej5xoN*5VSf?(*^2KXlb`7?QY8Wu~LlH1H|Qtld2E#YlBZiW^sC*w5cL_W?iSZ2rTG08 z^qMhOym+3lva$2wj@jQOb(69*KAQG&A6HxZ)Js#XeZ5lH{JGYgcIVx5FI{2IYn5Am z?}p!}xo@AUUA|}Dt@$K++WjN@1Z$Xo>pW=SZZQW@Xl= zB-h+I=6^1o+$(Z#+C)#`e&s2rrGAJcf0$uvIXAh`jcv+-FZqepQ#Wml-@h>~dye{T z<&#(2Rld%vGY;j{+oPYm1_qVxzd1dB&zcycr znC|1e&NgC(kZ*00ak+v0^p%2|9xR**`fS%4yB7Vs%k$yV)Qw)L3OY)eZmxZ%B#n=U!x3yU8IpLB0r!~y%;C%6N1_xGonab0y&55S-^M4fmzPL(W z>w%*;bLgX@uiNK8mx;LKKDoFiBmr+K`lbo}|V^P0`xjrY#~7Pul+KOuv!+Nbls zQq~!@4hOy`=g;c){=E8>&9UdGVnxZxTUX*{Kb8CP$FuXy=Z2?QHnTSz39Y+)z&ZU_ z?-Td@h7GX-n;1X6*d1MJexZL;z~8+LQ?ZN-HDR?`XV56QO6|VfNPW78Md6~@Kktheet{h&5cva4`=m> z#%1hvxytjfl6n6GsrAQpGdCwp32yy-FX4jb`&d5C^XZpg=1vT{k-)ZQak8e;o=acq zKi3<~y>dl7(C~X;`J(Ljih{@c?Hx@wIQ%{|!*&XX?28wTKK)Y93-7pxSRCwjGu$$3 z@_irA&j&eQ_3XTI(j|D`Z1H0S2L;}lUwS_!SN_8B!+aZ4J*B5vI8Hpew6Z&9#p3r9 zy>A}96WKP=@=DsKx}_KGT@?)vv0RpH%W(d3b?GJE2^P0{0&)!(tE_x1xcu%lhlT%( zrG4vjnHEp2O%_scpkG$mY1$^uDdpRH)t>(gueXV}Zu z&8@foZEbg+Ci5!ozR%GebB`K{)-Gn*da&YN*v%s!7~V=&$<-RaVmSM-?C^KD+OW3z z;!np8+jj_TH8E6FZ1P&u-j=vP^0M8o`gMK|VR==Kj@oV6eP$vFpOtcB)})y@zF*$C z=&0`G#euyl3u-kt^BE}qE!xd(|6O2vR7zkrBgc_=y%URUn!m`qUAm`i619)pK(X`Q z)XnSLPk+;{>wU(5$Zf*ovf6jr>RZgt9udq)&c3kM?~_Dv$%17Gn@%uYKPKQ8l&AD; zd)u#r3Js6F7GJw|EB-*7blf#T%?k%owh6x~NcWD5VQ1O->GI@fDKS46-(LGe^|V&@ ze7TqEft-&%*q=8m{O%XQ?fK~JDId}4H7utOXPNUglzKB7+{|aIV1KrM+9U7Bw+{Uc z$yYGCJ=aiqH*e4-^YunY!vqVRzO*)I%@Zk*u-(CV**{^2LW9TMQ+r(Rg{_K7d*)Q) z8Z!C%{h;UPeJ)ORJJOLIe|yRkX1m%7%@PhyOS7~n(`B|AwRgkvjW1`iq@Ug`N zQR2@CX)AlRw}Krf>z3JnJtF(U^i4*AYjZ_-iue>3cV(-Wrf1!MH*;#aC*T}Y8nIERUg%oB_?|8#-Go(O>@(zy6`IUWboFtj7w#cG%P+`d+g#n=cSlB z-;Uh%`uP{WSokt^vB)K`X!rrs0!;9oA1 z#Vx+@+J@Ww3+rBP;dqx{{cXd6s6!$4J=NlO6|1%yzUN-KdizR48?B~E2ZHwdhMM=4 zekn{nb?#$r7{9_=Nht~EZxdzfBm~%IyXZSjpL;V#=7agH+dtJ_+&%xv>o$+93a6}yaoO6wpGBJ6%4#(d zDuKqb=Pq0i{kFnlYIKNB;Pk@KWqFrw#4#~s%1)F_x0>On#+~A#6jWzrvi$A*1kKFQ z-aV(2Y!>cj=9o~%E`9sku}ZeZyC%O0Kja~`C29HDwEkG;z6oa2c82+_*&Lm9;C9Uk zt1U})0?P%HZak>pdgAg;=B+%{b}Rx1(-z*J$fS40Uy0lG5qEM+VO}Z1GJ-^TK z!T(LwA5V3D-IIy)bUPixH^py1J#YS^l}(E^`Df)xYi%}LT_}{aUx%sJX2DIqFXoZ{ zTZID_vG!|CcY3rz=fUiEkBrj|7-t;V9b8^wIRDT7{68{}52dR{3YYP0x_rG{i>*7m z%=Gl0=71BmMswwwMCLhjZhbm`v#@l;@eeXvGcL;f6l=}B(818hr9Vsj)YKFMN2RRe zrSs%?>LnWO^3pD;N;ry454|(V>Tt(nPOG4+1v|n$k_#JD`?$+qtmQ~F`F3dCL64${ zvleGB%boMnKI?l@{f3&&yi2=1zOP;6ceVI?{XSl^*6Rn>%?e${8SD{kUi>b;+^sR` z8DrB`LnjXn&vQB91+I^hy|`sN1SyAjapeA>^&?C-n=yPL0P^ynoY{2TP4oxf~OTExn&{tc5jx&M6lmKoUdt7Q6{ z!Ve4bw^gOYb{&b&T-0Ot;Vm;`TET;w_X0eBLb;CIwK`#wlU=-U|D-E1%4^dmUq7>1 z`}4UKUHNaH*l{t#x!1>|r}fwIEY6Nx z^LL`#DrpIiXcom6YZc0OxoV{vf7(7leGgOPrl4=>`k41~J^p7s z`{=9Kw|Sm)@Am}^9RIJh+)4V)GxhrE;6Ep>I6f(uC{>-*o8;=SYHw6i%zo?opLu8B zJYFqzqd)S3O!yRz1qO>*)@-;KGjaPHH|646e^m}fOV3lT7ZBp0E20Pp=nF(O|RR z^Oo6S_p0aWdR+&r-z>hgwD6>+3C9JN?uuN4C^M0!A2GpEFV1UhH!Mk56Hs;V;2Zh6 zzwd+>9c^6o%eCazsXp)5(vrO8pMRCPp3A-(^2WYN@%o`UZTVt@7xy%l9@@EH{M4Ky z3j5VA=H0U{)9jaElQ*}sWlb~Kd?NT;dW!U|E9WLFzW2UrZQWt!*ZJ?t8>gyw+D1{~ zw}O`Gq!s#aHGN%pOKn~Dm;SQi=nXATgazuaaT$LMzbtci!RybnPhapmeviGpCHVI@ zC+Fg`3M-x@2gmMLd+|>s@#W(Ur4wBD2~6!z>ogR&XYwLFAbF#C)&AV$;h9GbFC6&V zA2I7`&hPlGmDZ}sb1o@P4=nm@9;lGad1vo;gPo1u>DxW)(yI>Jt^2E9^}}+WzAsmi z_mpSV88;XFy8q;Ue_3s!de#Ui-W^%{?@8n^?Q%Ve_@Lf zKW^y1e7S~hApjHQyt`bLq&YF7&F#BJXEv!!;X_3GK(yVx5TUX z-S}|n*d^6`mSXv10pA@zWS-6|zTDGoCV#llw!+?dzJGXw+nfy(629IR31>;WFemiS zPL-&sZMw>D1dBvp-F-Vf<=W$T>H3K~3YIMEo+TOB(-+WmH{ryd?V?TriAlR_ReoIT zx$K=Bo3QZStAG^ZW1F`& zJy+BJwNU5yi(j(e&YqT7Y*TVG&To2tV3I&!O=X$StTRqpbs5}C*DvF4zAH9On~&jL z=CtmVX{}M=rp@tvdu|!KPPu>6w(XtWLPhnY@TRHkA7jqudCb_g|8Me)na@9P|BebQ z{bOymCNbZBM&ec{d*Np%%#OJGthd_wq`JDm(%((f`L~kEj|*-a__TurAH-~*`ee?o z#07J{y%pZy8^(G->&>bp#!d1|J$5fj*10pk!qHIka@xw;s z+qi1A{+yb&C39K6Kl#2UQhv_Q-Cl>e)z_);BrGytthrzC0@tC1HeRKLVYPa?j3?Ic zoV?>M`z&+K?rRO!lfFBY_NK!B`Lu;C=)55zyX1-Bi5Cx^stB(2 z`>;IM`FhJ%WxLxmk{e<(EYtd?3Nf<9_n(+59QdW_VC%I?-Mu2#T2c2N zl>8{0_TwTj%wF+UF6>STtq)uo z=a3N}ba~2ZOU)+RLv~+UD&HUN;#GH;?fkmy?&LP!v|@>mnn&g@{WJaIf^9|3BGdOZ zc7>z|p1XZ`i%zo3YIl(Y56yR#WiuyTth_Wo`btQTcJ6hql^=ET?Av--qDA;;%{>ry z)OA^p9^VmD;eyHQ1yyg?i!VB<@Xq__^v73Ix0Gz3`8C3N)A{1!@~#Cp#S?Q_bGc0) z7A)5)`taZ(ZwyEDzaM*;>Pq|hcfARnadz@NRr@SP>uLNM*QcJ0O2{*s-84g>>`d~3 zHyiC=G{58QwqL;fhCgtrg86p8Yf63!%d`)NU!Hnn>h~tDMNApa$zA8`UNp4mH)JX% z$$LjkuhHyh;{Vl8 zZ;cHX-NP5Y(eBxge+J&%%y0D47N+le@w1@)y-?V(xcjOHPSk8u&R`W!opD6@dgLyX z|7z};1wZbFWH0_7R9jjRk{rks?_KvCRX0a+PNDWZ_!Fhm7Fhr80p|)?=!;M?md{zj1oJxt|;dE*>Qf-g4 zf1mL)voGp|i2mM(_wB9UEWdnr;rm-U*Q#X8Zd!A;H%f(=9pc*&8rmjuw{zaaf_S|X z_FgAGX;$gU?=_sOAR1)+cI%}Z!YTUmbzkn)PIT|wU^#ilpE>iGE3RbJ{uc1{tu^w| z%)cSgZhzs|>El%gVv>W{zSUb6mt@t< zuc%-X)`8*9+f#D~wKM7Q;BTQ$A-Md6$+b-f7-9=ut%Z%O?jx4YRtw)igTwSB~1 z(0sTs%uils9<$NvRsK_#PI`UMWP^~3mT#!&wj7pUzHRcNY0DQ!%S;#E>n+G6p^%y@ ztT54J=V7I$_mu|0W^y~zW+(YK%E{d?om~)ld+Co{Uuk&p!WEezVQQsPkU^5e7WNuJ3$$CX}w_F!0!ZN$zCN@tIvE(eXCw%h-Jj zL=U~`z4%`B_)Ec=OM7_M1t;dE^L*N0d+ytwny7WUCg&y;%t$_})6cyu`4Gd2Z7-VS zT23~t^YuB|dx1HIHRVzTbSPVz#91#%-y0``)U5IsDFR=`GQ^`gg0QN1Et7 zwbH)D`ukJw0(FN<{qz6RPPr5^Pd}tssJlGhia&4H#})st*JX5dcPwn(7O~f&IXF|f zSj0!b{LIAu1rv+2vpRyxlb&=`G6!a~TKv5D>WTTneLiacnDu8mKR>E2xj`dlO4VQa zv_rE8iKWYzho$;9s>;wuCt%BUhifM=inO zYlpbIy{e{>Tg-xwI|MKOy;HIMkW={1Pwo|)`d2MCqnz&1ylfA`IF}9_FdOE6sPcPd|9}iX28x6Q}sh(n=8-fHf~HQuT;y6V|V*jYipBN`|Nb@%liRpvdP)2-}&uS z_{hdkch1naxa43xhv&>$ORRMD-?mSR>3rz^U*6wms+V?PSy_!ocU-nzt%H=$<*`_oTR z{fenKj(Pd(X*-8MTwr}jlfPO)ZAzMqZ+5ZD4msV4D|fa`D^PNCv$S8TJ6otdM%XlD z!|~<02U;gA-4}7z`Oeg(vrlaaW3fATjk~m9ONgh-W9Om{rfq+JEID#st7ylWJFYu^ zf2iTUIp^vkMROP9l~o@K<;0dRN%Xd}E(}?Icc)V6FYW5ho;;1mA#Kxn(YYy-4?~vC zmpHa?2Ctxb_rB7v`ZIkR8IN6O>6ZMHtTO+GT+V#P6G_>T4`fd*mgu~<>*y+vWlkE4 zHmc-an%%(te42sUT|FhO7fSEX`?&3v;0J<5R^K zdsg|Znv}g~$80alkaaIPc{&TYa#|J}F3{c0E&k$&tA>poo0!nwcPhVM-92(b-kI^? z%5njPz?g{F^-EZSlK1x%t@*ZNZ+Vl>$KFi|9;H@_rZSw)7oTm=T6}DwHFJpRpXjBf z^Eh^7s=vB>$R?1#P&jnH z>3zINtW&mo-{IB2_m&^$-q_hE^mxgRe*vGQ#FuPy)idkXiJkuHg{O1-DL0Y()x|8~ zFCN)Hclu=HwR;Ok%dDFX#sLOx*A9P4d&cM|*5LE?WFkM$V~0~qws`y7tN*{TvgMuU zmO`eV9UD1!XkGoe$70XZnLL^bwr9@y?ufKEUN@&?ouFeu^}0W|; zo*nCLc)zPohz(3(aO-*fW3}$05ANK_t4(_@ERvnQe2b&mT(4vg_okMbTd4~V@yJ?r z)|N8um{BBE*t)zaQT)WWA3d#Wgl%g~xun#lXzD)O(XfT{{sUFPc?;r7?}%9F<}Y%X z+PaBz*SCIotG%qPMZ4YZiMDn-9zQsRZGR05-|ET7b4ov4o&NH)&KnWSf6S9qOQrT@ z+}$wUY;nG&qtVZ_yMp@mvs_m$JSsEE;^nCjY3s5D@hz{;e+f3_PO{{VqP%%Tw9x%VWw_581ej)ny4kms!cW z@u)w)Bh!o8p37e|VjEO%Y+PCVaSxNKb;{C@f*$|4O6M#1sg|5cU8DHE(?8qWTHU^=7WkaMdx1xO zt-F!2vCJ&vhnBTGPk!*v>@yZky->vTqTuI=ORJNb@=Fx;%EMk~ES}ud8!>$?xArs_ zM$Jd^6J-~Q{&qe2k?ZyQ3qH9QSw4L@bMVAV!TC#!KWDP8`Qp~CoOAO1+}7Sj6WjfJ zLQnZU{G%^9nW+*u3HYnUfDYBHb2LO=o#O z^M~g`}73J%YyM=>`pq@_p8vg)sUl!va!76a+1u)8a{e9vbg!)QszSX(;6aP- zIDduBAM8)>uIN=Ny`eVsVWsbO;fXgM!mB85W zjG|9n0$#3Bz1!y17ympKy6)Aw)yE&GIYw)%$^LKVSfspX;%rufPXB$3KJjP&Z$D@} z{h!z`KR2U2b{P^zvp?Rh_SEHn_SX4OZ2HBYoVB(L728|BC3@^O^t3e=y<~9nao+A* zJikSyT8{PH{%E80HU0#r=fnk%oo6-`%JLao2%gCCIlU|2oLL|y`K-moS(XC6&&?j$ zd46x%VSAB1=kuxCh40?gu9f$>y*P1B(v}|9o}0l6tKA+Knq7Ib&Zhe90ejYcq2J~; z`f}6<1a;R$wDu2dhYX*5-eH{>*r?u~T4c2~!Okz&sqOrf*;~Cfp3JZD zEZL@4w``rsq>s-ZMqFsU`{jPJankw!kNBQA<(`xg>yB8nSuN&Q>VN-*&o&&pciq-2 zH&giPuc%+L4l}P`P<3L?zB`d|^*_I&xu%!b?fWCzUpm)PZPQ=Rky7N6~U{1&Zy7N{*bYsvBYC)0T*?_+cJ_bd}$BpY}9!S8qSmA((>mqn$m zT=@IwU4_q=L(kaVKQTpf_lqMkK?W=5eY~aZkl*z24d0%Ul0IYIqc^;k3rMV=dDeU1 zy(79#i~eOcs&IbQ{oZBC{Fl$>)K!_}bLm+w6>6(`QyiZP%XndSZ;3a$9QOohaddUARxQWy1Aj4u`PRn~!hUa&GX? zQk;5YYh1$jq%+McBEJgUUmN?;eRY}m`H=YHR!6hB^Ig--HNPDXUmfmpb;kT#qM^bw#lJ1( zl>Bwl)RKu$k5Of*VC#(6M`Z*3rBG8W%%@htgP9a+z6ti7r3mGTTZujQMLdoJDSRI?=4x!f>zXMJU+?z@~j z)9P>EsbBi|^;P%ifX1D7XLJ3W;P*l5wy;Chqn6axn7O-8CSEO`@mb|JW3}*HuM?-g zZ4vu^&;7ot)Zwahovp1?E>Dwk$vo)2Nj9Retm@c#h95Hy^hrNV(fe8Ge^9WfDb;e> zp0~>bXL8)%SI)fQi+0u4%@NNupZ<29v+k;Uvue(%uw_!S9>oRuJG4p|g=QN~%=X;3 zW9pHt1J60R*X-PpI^}c3JN~9Cx2}gS2 zdRj5)P|Z2d(zD@A-)}g}OKm^HbW}MuO?|ewMSj={{u$D`FM~^;+>PfIX)2X`{_p*D z<%_=BeiP5E-0ZrcRQJyv=d6tu;%ef-;A74QLIYEg7Y_+Dnwtht$VTTKb!vK z@URmO7w%nXWeMQ__rLGkrn`y@=7ryu+S734aH`3U(+&n-d-(;`?zekh|HXa4WvaGt z#O#G45f9g!Pgk$mGBaS++u5I1+9>W>w^25xiT%a(NB=%1nDNy=ZaJj6t1VOac*E0u zdx}ehwjcLQycyno&NXn|L#xfln$%n#$MM_hC!aiRCMw1~RY&4R@1rG)!eZ+i+>Bfs zuHO)|-@oLL@I4K;k2SM7+)S6Rt1Qa$tkq^(%v`4w{kC(~wWYs(7RN7KSHIzK{I*q^ z5mO9m$|JN6soXsOT`}&_(~b6@LzC{9i*1;8RB@VBxxVKdF4NCOO6NL+PWnID!J#R? z&enP2lhe;T8xnPO=0*0UUw_dg(OI?U?PK;MyZ9e@F3l-h9KF4-<#U)>*Q^RR%PNTz z`K_P&D!wIuD~tS`mv-<(V$GYGFYZ)*bXmB#{lm$?X1+K365aZ~=CS|2DcpHt6T67C z$gS6}epGApe%`NiC|`W zo9G)zn0&TkB;P2ddAR-V>txxm{XU z_r|#cHVFz0H|#n&17@Dp?5OLhHt>HUIAvb+hn2?{3omTceEH^eXv>;&Q!5!xpL(3( zx-x2K9?PzyYknrIDL8A{(*6F#OOBNZlZ_NV-L`T06Lf#;@y|c24sq|;W_@;Q6|>#j z=50?MHd)C|^nUug&T@vz<>c6-^CbVOzL~#J^kG`iMT6!G9Ig2~mbdh{@3jftdi4Zv zQ(c*GM%p(H{p8=qDr%2hHRn0=^~{KR!kzut(O371--D;ivcqb)Lyz4Hxf7{jo0C6b zNk(===~>2^Z2tsfdW1Cd-O9BdbGFK+r9F;P&f{19J>@~n$Ddc3e9o@nobkInD>pA; z$9+A9NkI+5pUi)p|GsGDH8JHlm)eO7GS9!LEDc&Z=gri5HOcMTpN+&^9%rsq=FMjR zf0O;Fz}#?&)p`88?w=1?Ze{Lrxbu5n&hrHGr9XO({EoffCT*5!su~t1I%`Mh>$kV| zt4`GrW!v|<;?IxTymEzaktIHVZAB#yZ%BRj*LPO;{FLqI_T7zsAJH@8^~*cKk-BmJ zr=2Rfd(J;E`RApn^{NqDP9-ILGnm=D4i(8?md2ZkG}yms2}oQg{Ecm;Dh6dtzO^Q_M1ag6n?*w2TW6w@Cx$?iX!tyizhUl2ZHs(Qda4SEut#rue(vQKrmXAFwddTA{otlIeaq5v<9DX> zROQ>74HC|=7rvNgv?(U*jG;|5!yC>MpSD@cN@==U_3V?H%U1TJ)Zw}b>&wHDLc3Lz zj-C^ctJxQR+WetV#T$dG5|>!Z_cmC)TX(rVk)u~a<16P*l@3#toV?lFT8^eo%RFXM zv6@wWQi6(cC3~ff_Q%ZdXg;0a+>u8T=HK67@;39<%>Q4mvMAOSo7uO%mN-=3eqiaW z4wINg7V0fiI!kzO`QM5WJAY!qUYX+e3sp;Qf3dBee7Yz-gZuW6)u*#(|8n2C<)Dh= zmCCy%=ay}L!5@|K;GT-Z%`~+Y*2>&v(eamN?{0X!aqYc`*~V+M9$G}sxMJxsW#8-1 z-5FA`{}}RXS2XyniBH%o<0&}p)Yj>*j;((m$NS<<&%DK7qV7I5F?oC{PDJa~xi{8A z=cQ*Y>YwrONVdZ*(QmVV{oZzU>FFlQxIYz3xdwq6U)f9$jyb6;DQTf+vKW^gt2pIr`A%PWVXbWN17EY9 z>n@aTne=4c2RBijGV_)32_LmuE*o;p`lhL&(HIr98Y{+aAol#uFqVXi6DS$02 z<%&-;|D?=KS|Ll4?eBVUGQK#L7QM2|%Pm^x=*7)%7G5}bsrp>o+^qBBCJR5lpTPD@ zM&tT-Yf<0((}jFBGH(5xcBe!vsKIAzitJ;?PN|c7LIW5V{NAuPf^9|5=gZ5McN(rc z6>fZdYOTOi`){UMT{FKOEL!1oY0CE(v+~{k$-Y}H)+CVAD|Kz|nH^hLuN~QK-g|D< zqWIo5LaA=|Rz16RNzYc-HC!a%MuCqjQ|6&1ulL<_2}xs(6WKPYDMiR>w?WgE_shAsspX7=k?5cPCFtwT!PD!6C`gY>Z`w6JNph*iv{-o-`#=7v}>Jh&j9e2Bkh?P|H|$ZLIRQQz;MJDRmqt=%QJ zrm0M&&h6eC>(y%l4%qTaxf>@`-2ZuRx<{a&!!#|aR{_(vGr4BRyD$6Tme+k|``pXZ zFPz)OsrT4SJm=x`h29&lMC%wQ3DxKKo9$@wdZ9iiZTZF}29pdTazfWOX8$~{ujFGP z;aYI|vgAs>4H9qIrQ@qbzTN0rx^4I3i4(jt&rXrQ);UX9@MD+$Vbf>F8vi~i6g)CH zT>Q+385=q@mrdGiSrl~CV#}Tm>6F@=k9^yfs~&iw^n6yh@YiDt)f& z7~gI!{Te5-ki&n$qOaUxr7ivEuFc>st=+umANQfxG1~Vwc}+L_x5M4->*b&g%l(+e zqN1)GNyvVcYq8>3-QHNP>88u?EG}B!&zI=a#5GB8`lR!>_T8_)=n_?x$MQXPnXLKz zZTfY0KbYTS?>YUhF*B@~{i5srq(~z^Ne9cs59i+Ytd3#2x8Rg8kI%&YJ^_KO>zx>i z&+WD7b6O%FUpzbS=DLy@S@$-){&V40eWiVK;(GlD+xK0p+5YQC{cY!!cWpe^^X1g+ ztjZ}_BXv!W)pqSw(>Kz07o=>=Jm%RfDW+u6AN=dd?KMRb8Zr-G?vwOgW)RP$@O7n# z_4HRIva7EJCv=$pi20e~cyM{@_Pg7dFMjiUyKwSz884eTg6n54QkC>cGG@Et`I-6F zbeY6umeUIv)9NR;zy3BUV=FV)+LUh$dEb^^x?6sjZ>|VuSm7g;qul>5ENXwfWE#sJ z)n{E_s;(=9-{Uy;$VsR{u;|YJzk$gz4rN=uWj6eNKFeIBEdGb~i!-5nS#m_}xL5H{ z$-Z!A;y!ZZL*ZPXlRoi@3D zd->Oz??+^WrL)DJ%$)eh)nv+_BCXWJGlT9+m7UfRdS~{x+@SQo=FO82*Gouj*WPK% zw6Al)bNQ#DUklFMTgXx7_{v7{{hSxu!z6l>MC1yVPq&?wX16>!Pws*3R-wAu8oPqB zm!Br{2q)g3$@oLYafU+Q=ZeRkJB~=Q>$i9ReU!9yCo|79)u$fWB_{i4-c6mz)2Nxt zpLnI8H*xg>p~&Yh!tIJ0UtV7InLoMoUu>W4n&lTtuc>~y`tj-XOv?usW~gu7^SR-7 z+~W>qUrupxw!iUqi`4%mKAg3@O+DatZRUY0ovnYa@AQ0jaZz!4wQIBgbi0dxHa#fg zX`4Lb)z#}AUd^3TEp&PlSLrX-d0TYk=jA@-Eq}`51%FL+4Jul)?r!pmS!#*7E(Rvc z?k3fpXP#i<9I)U2-PIbb-jsVpaCo;QLV**8h&)o2!y- z^hEfj@Y5yHRaIT@!vFa1Q7WFfPTh#}{iTi<(|Mk-r`)NEFPO%AZBj4)d`mxZv!egI zy?dUuHM!-jI9*s_wEjTtnL<^DRnAj&SFFC{Y3a7fWqr@Ab!EQEJ5@j2Uo$b`9~(2H zrz3yeKhB>bQ}+GkKj+S{zF~V&F#F_P9BVoDJYG1_^I`(ur*9E9{u8|!WNk~lTzoF1 zZ&~&zeH%+k6z|^BkSoh)y$SlXZcBB-!rW z6VpO7!fYgtnyM+K6vs{qRQk9+H2#;9=X>=kd8KcM3(q#~+EX^`f6|VdJKo=2vB!cl zQCF;mf9`kjDX;C)|H#ac>EQ?z-ttQGxTwXxMXkOQV`Dp78v5=R?e%!Gd10&O&MPq+ z_Y2!F@*MV3*U|jDGRd#4b6vx{lBb~tZHx*NvnRVQ`gZ1l$kzt>Ga5hi*AKOyanbk$8B~#jhuwJ{=Y5QN3xhlkcUPdzqd5*295jGY-WjE_STk$0u~| z@QN!xmVfu#UBG(x(&>16*-KYm{bhN7{;JQlnd+0aB;BdnC}HWCWD(TNuxEDOmal;> zmba(!^++Tx&lj9}V9TdF$A6n_-F+`oPmcNhbiK9(7x#Q;xq0B%#20ywo=rNvqiJ!? z)v&XSIT=T_-%nq#|720Abp31dKHl@Y-evCc_m(|Ad)B-s?{7@Z^eGi@J(gU0 zHBBMpciJcU(^uM5_ax7ZPtR37b;aJnM`>k80MES3#)Yp!58LXs%DtK;(SAjJmbCGP z`uE(%^>HUy@79V;>d=o%XE&-VxV5uD5a!~{4^aY@?2ZzU;wkGsZe z`h|rL=Ph>>*9_~n-^E?Kf|YH3>khjv*2^bz7H!xuLsI7FM8}z2^ZFiTM(-<2?Qo2a$J`vJ+OAaNY4sPb$w;mgS!%erXOr!eq`P4dyc`rD<-)3$}t~!mTq-oVTbomaf6e>QCIIfGH!bO zTkOY?3fp6+V=`yw=w17M^wG+7+Zvmf?hK4zcxJx+>IJ?9r>;&g`5u~hs8IRmYX#rb zb6Qg#<}A4wEqKoJg1Y7xSJnv)FYj$ye=zK}#meU*?`)zwm8aYPI)DG(zD4@8Px`P; zN^f0j#$EQf{c5|kR(f#W-)t!+o~3Gvp@I#ZzN_5dc`GUX<*-N!YQC~gv_EO#^rDqT zE=rxAYnYE+&u__3e5m(y*@?cB|63+o&zaR5I;VD*Xq%|C&uMRMFKvtWn!!FTY$x+V zUOYK$+pik-=3Kg7W8a37?j=w6ru0>Pa_ySu+%vT^{kDJ1@6;)g!mjH6mi=7%Vpi(q z9-bXL61K}NZcsnJHztJZ^1|IaqjOej_%iQuND!LQ_2%yDwLMmkPaM@x`<3wX!Pyxd zB?p`$X2^9;Gn;>+yk*{n>UZ_>b&HNi-2B35zx`#(%*{{Y8p@A9WVt)-kCXW+#X0f~ zhgnWFe0S3*y3{`@`i{o$c7viTwUZ9;WMw&DzqrLOkvm?#zwJuT$pm-#z!+f}tGl0` zmCUG^TEU^-%@uHcmVx00d9^+NllEO$ck%K6-||-fT-mIaH1zcfojJ~a@zRWY+f)}! zZvSr@@Z?{*#=VYkp-*lPCnk3tkTi_@p!?{K@V04%8E@uSM+C20wa#*OyQ!vHq2Y0n z$Mds)pVaT>(&OV*u65kwXc{f%&nTX7L8o>J^RJgeJ?|U-a{P-B>z7)0i(`RRfAPb+ z59`v`N%SVaUlXXPmcHd(8;kOldu)ozbPjJ0*w&oUz zTN7Elw&BZFZ-(C7#r1*3z50SpAA_>LTvB_z?6!j!N99wlJ5%g3O69t~$39znxn4nj z?Ogt6wHZ#2nm6|*zKEXPdF}LrDR*3NzJFx;Ykltj8TR@y3wQnBxU83Xs({na({D0b zzdzOy=H1VD^Fg?yXq|n#nUb{@w|enYK@m4LSx?!gCQ}3XUtH0vc>2?KenCk2%%59x zwfUDlc^HvvU1-?1EMtP@3Q0}r8xxk#pA|omQSxx8dcmzjz7P^HDQMQ zHtC%CfBIsx4k=66X>)5+>OzdF&lu}w1B@5qF_ zn3_G-X@82I+3k_Do_a^zr#e&5QRLp5lB9c`$B)gb(ra=J?Q5U5sQdAXV+UiSRn|K^ ziQTWubr_dWxq-R`Md*6yAW{rSYR_iVeqs9h+Y(sVn(f$ppw7EUOI%go zBr{$yH*?b-XO+s<9>?8FVhuDmZeuRlS;M<1Pr&bw-8qi6EA5J8V@2;jlNO6C<&OPX z!SSNu$BHFlosn~ny|F}^b@8*hlao7FE?~TIqS{nwS)GXS z!l=-ai8m$Y$2I5AGiwoT@iZ`qKAdyp)%^s!377BtpIi19!I@G0g$jHArg<*!S$%X1uZ+244A*qu2iAHs zH}JTcS50cuuwKZ2!`>=yecOclt_|y-B)yWn+}`<4}ZSv)J^sd^c2be(l$w6 z(&O~3mj)hb)ti;eKCqbIe>}h8_w}jPuiG15y=ybDdNV`uhKc+Bi|>S64%RH=cH-Ht zAh%?yP)lm)vPWUg^^5aQolo;hj|`Yxx=zEgsle58Mf|=+zP4@Z$!}vi>Ij0y9yVi>2CSE+k=?`jnJ z(sNSi7t>T(_m^oVvdcWgFKg`H@}I@??fz5cedfv*XQ%Sri#)ZUNwMmD*QdJ0J_Sk5 z%w2}-cKb~K{UT*o{+4BI3%#c12+v6F=qP7oAlQG+=f@4>w2Bl(tVz-_sZCy zxBiOc;nbIxJ4}nB3ZCxHy-=cld&R8{hpfd8#+X^`T2Y?)_J`JNwMps<-Q^BUk-uKa z9RFldA-=gxJ$CiI6$gzXR$j4_G@0BN8_=M;{@LS24o1Hh)|EVrvwx+|&DnQp!iTpj zk3SULtx_JiNmXxKPLoA%(dGx`jN4CX3cNq_yj;AcxOm=Wh4)8iq-5$(?yR06S2xe{ zm2toDXS;3UW#JWPW8Uk?)qLjmow;a&omflqjkm}DDV$mvb-uA-)*QQ4z1^=1c`sP} zS~pi({gQ`fm~yavx?S8^F5~JQzjH0coPO+h;c$ubz{4M}BlKbl-iWw)f4x2JE>G(_ z`ClykR~9?3xtF=(p|w*|bEM0Y-K(@uRcfZ>b{r|>bk?q%c2;QDF{zi%+iIrVsMoT( zv@-67h|<#UCj+)GnUrNNt^4xIw+Y>$e{Zb6I)VR)YVeP*6U_`+mu`5Mf3U#Uo#*02 z!BuM$WOtq0s4fu`*>+59!iT5}nGL>6FD!V@@$<$GS&@ZP^v?$rOLTH*TU77+#`%Ah zZc+6)!H<&ZojmIf*Im{SY!=%dpBoW7Yov diff --git a/bin/game/compat_1.9.nut b/bin/game/compat_1.9.nut index fe985b90d0..c2acf9e909 100644 --- a/bin/game/compat_1.9.nut +++ b/bin/game/compat_1.9.nut @@ -6,3 +6,5 @@ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU 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.9 API compatibility in effect."); diff --git a/changelog.txt b/changelog.txt index cd9bbe7ebe..cec584eaf7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,51 @@ +1.10.0-beta1 (2019-10-29) +------------------------------------------------------------------------ +- Feature: Configurable minimum age for companies before allowing share trading (#7780) +- Feature: Filter on town list window (#7621) +- Feature: Ability to show Newspaper and Ticker messages in parallel (#7612) +- Feature: Show coverage area for stations and towns (#7446) +- Feature: Collapsible vehicle groups (#7417) +- Feature: More flexible docks - can now have multiple per station, ships can use any part of dock (#7380) +- Feature: [NewGRF] Railtype flags to allow/disallow 90 degree curves (#7352) +- Feature/Change: Non-rectangular catchment area for sparse stations (#7235) +- Feature: Improved performance for road vehicle pathfinding (#7261) +- Feature: Option to show local authority boundary of towns (#7025) +- Feature: Experimental method of town cargo generation that scales linearly with population (#6965) +- Feature: [NewGRF] Houses and industries can accept/produce up to 16 different cargo types (#6867, #6872) +- Feature: [NewGRF] RoadTypes (NRT) (#6811) +- Add: [Win32] Select MIDI device by port name (#7666) +- Add: 'getsysdate' console command (#7658) +- Add: Currencies NTD, CNY, HKD (#7596) +- Add: Icons to vehicle construction drop down lists (#7358, #7485) +- Add: Security warning to players that company passwords are not truly secure (#7351) +- Add: [Script] Various API functions for managing vehicle groups (#7225, #7336, #7716) +- Add: SDL2 video driver (#7086) +- Change: Inactive industries do not make sound effects (#7752) +- Change: [Win32] Use native GDI engine for rendering fonts (#7572) +- Change: Scale oil refinery edge distance limit by map size (#7514) +- Change: Do not display a news message about old vehicles when a replacement for it is activated (#7401) +- Change: When filtering purchase list by cargo type, buy button now performs a refit if required (#7301) +- Change: Don't apply forbid 90 deg turn settings to ships, and make penalties for turns configurable (#7289, #7372) +- Change: Make the chance of an aeroplane crashing at an airport with a short runway independent of plane crash setting (#7302) +- Change: Keep town growth rate in sync with house count (#6777) +- Fix #6219: Improve helicopter's ability to takeoff from commuter and international airports (#7710) +- Fix #6407: Show snowy ground sprites for train depots (#7671) +- Fix: Power/running cost sorting algorithm was not correct when power was higher than running cost (#7561) +- Fix: Tweaks to small-map colours to make dark blue company more visible (#7436, #7450) +- Fix: [SDL] Do not offer video smaller than 640x480 (#7442) +- Fix: Incorrect display of industry production around tiles (#7426) +- Fix: Show industry name in Land Area Information window for industries with neutral stations instead of just 'Oil Rig' (#7349) +- Fix: Remove redundant and broken file lookups when loading base sets (#7348) +- Fix: Always report error when ordering a road vehicle to wrong type of road stop (#7316) +- Fix #7043, #7274: Improve performance when creating towns during world creation (#7284) +- Fix #7062: Remove ship max order distance (#7279) +- Fix #7189: Fluidsynth volume gain too high (#7253) +- Fix: Add setting for whether industries with neutral stations (e.g. Oil rigs) accept and supply cargo to/from surrounding stations to fix exploit as old as TTO (#7234) +- Fix: Properly reset dropdown menu windows after changing AI/GS settings (#7092) +- Remove: DOS, MorphOS, AmigaOS & BeOS support (#7326, #7388) +- Remove: Original Path Finder (#7245) + + 1.9.3 (2019-09-16) ------------------------------------------------------------------------ - Change: Use natural sort when sorting the file list (#7727) @@ -245,7 +293,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: 'unban' console command was not handling IPv6 addresses 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) @@ -351,7 +399,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: Use a more appropriate 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) @@ -3242,7 +3290,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: Possible crashes when quitting 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) @@ -3250,7 +3298,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: The overflowsafe type did not like dividing by int64 larger than MAX_INT32 causing division by negative numbers and small anomalies 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) @@ -3706,7 +3754,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: 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, therefore 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) @@ -3814,7 +3862,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: Make snow appear on rail tiles dependent 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) @@ -4095,7 +4143,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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: Translation dependent 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) @@ -4216,7 +4264,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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) +- Fix: Crash when quitting the game in one of the end score windows [FS#1218] (r11071) 0.5.3-RC3 (2007-08-30) @@ -4348,7 +4396,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe 0.5.1-RC1 (2007-03-20) ------------------------------------------------------------------------ -- Feature: Translation dependant formatting of dates (r8906) +- Feature: Translation dependent 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) @@ -5311,7 +5359,7 @@ Note: OpenTTD was migrated to GitHub for 1.9, so SVN revision and FlySpray numbe - 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] Performance fix for 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] diff --git a/config.lib b/config.lib index 2bcc643fba..dbee012207 100644 --- a/config.lib +++ b/config.lib @@ -52,13 +52,12 @@ set_default() { 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_assert="1" + enable_strip="0" enable_universal="0" enable_osx_g5="0" enable_cocoa_quartz="1" @@ -82,7 +81,6 @@ set_default() { with_iconv="1" with_midi="" with_midi_arg="" - with_libtimidity="1" with_fluidsynth="1" with_freetype="1" with_fontconfig="1" @@ -131,7 +129,6 @@ set_default() { enable_profiling enable_lto enable_dedicated - enable_network enable_static enable_translator enable_unicode @@ -160,7 +157,6 @@ set_default() { with_iconv with_midi with_midi_arg - with_libtimidity with_fluidsynth with_freetype with_fontconfig @@ -291,9 +287,6 @@ detect_params() { --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";; @@ -370,10 +363,6 @@ detect_params() { --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";; @@ -549,8 +538,8 @@ check_params() { # 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 + # PKG_CONFIG_LIBDIR variable mustn't be set if we are not willing to + # override the default pkg-config search path, it mustn'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. @@ -559,10 +548,10 @@ check_params() { # 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 + # OS only allows DETECT, UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, HAIKU, SUNOS, CYGWIN, MINGW, and OS2 + if [ -z "`echo $os | egrep '^(DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|HAIKU|SUNOS|CYGWIN|MINGW|OS2)$'`" ]; 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]" + log 1 " Available options are: --os=[DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|HAIKU|SUNOS|CYGWIN|MINGW|OS2]" exit 1 fi # cpu_type can be either 32 or 64 @@ -629,7 +618,7 @@ check_params() { detect_sse_capable_architecture if [ "$enable_static" = "1" ]; then - if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "MORPHOS" ] || [ "$os" = "DOS" ]; then + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]; then enable_static="2" else enable_static="0" @@ -639,8 +628,8 @@ check_params() { 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" + if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "OSX" ]; then + log 1 "WARNING: static is only known to work on Windows, and MacOSX" log 1 "WARNING: use static at your own risk on this platform" sleep 5 @@ -650,7 +639,7 @@ check_params() { fi if [ "$enable_unicode" = "1" ]; then - if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "DOS" ]; then + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]; then enable_unicode="2" else enable_unicode="0" @@ -755,11 +744,6 @@ check_params() { 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" @@ -767,7 +751,7 @@ check_params() { 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 + if [ -z "$allegro_config" ] && [ -z "$sdl2_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 @@ -790,15 +774,6 @@ check_params() { 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" @@ -895,7 +870,6 @@ check_params() { detect_fontconfig detect_icu_layout detect_icu_sort - detect_libtimidity detect_fluidsynth if [ "$with_direct_music" != "0" ]; then @@ -939,9 +913,7 @@ check_params() { 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 + if [ "$os" = "OSX" ]; then strip_arg="" elif [ "$os" = "OS2" ]; then strip_arg="" @@ -1032,10 +1004,6 @@ check_params() { 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" @@ -1091,18 +1059,8 @@ check_params() { 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 + if { [ -d "$ROOT_DIR/.git" ] || [ -f "$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 @@ -1138,7 +1096,7 @@ check_params() { fi if [ "$personal_dir" = "1" ]; then - if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "DOS" ] || [ "$os" = "HAIKU" ]; then + if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "HAIKU" ]; then personal_dir="OpenTTD" elif [ "$os" = "OSX" ]; then personal_dir="Documents/OpenTTD" @@ -1353,6 +1311,9 @@ make_compiler_cflags() { # it happens when using the FOR_ALL_WINDOWS_FROM_BACK_FROM macro flags="$flags -Wno-self-assign" + # warning: is a C++11 extension + flags="$flags -Wno-c++11-extensions" + if [ "$cc_version" -lt "30" ]; then # warning: equality comparison with extraneous parentheses flags="$flags -Wno-parentheses" @@ -1428,7 +1389,7 @@ make_compiler_cflags() { if [ $cc_version -ge 402 ]; then # GCC 4.2+ automatically assumes that signed overflows do - # not occur in signed arithmetics, whereas we are not + # not occur in signed arithmetic, 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" @@ -1527,10 +1488,6 @@ make_cflags_and_ldflags() { 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) @@ -1605,7 +1562,7 @@ make_cflags_and_ldflags() { LDFLAGS="$LDFLAGS -Wl,--subsystem,windows" fi - LIBS="$LIBS -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32 -limm32" + LIBS="$LIBS -lws2_32 -lwinmm -lusp10 -lgdi32 -ldxguid -lole32 -limm32" if [ $cc_version -ge 404 ]; then LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc -static-libstdc++" @@ -1616,19 +1573,14 @@ make_cflags_and_ldflags() { fi fi - if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "OPENBSD" ] && [ "$os" != "MINGW" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "OSX" ] && [ "$os" != "DOS" ] && [ "$os" != "OS2" ]; then + if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "OPENBSD" ] && [ "$os" != "MINGW" ] && [ "$os" != "OSX" ] && [ "$os" != "OS2" ]; then LIBS="$LIBS -lpthread" fi - if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "DOS" ]; then + if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ]; 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 @@ -1652,12 +1604,12 @@ make_cflags_and_ldflags() { fi fi - if [ "$os" = "BEOS" ] || [ "$os" = "HAIKU" ]; then + if [ "$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 + if [ "$os" = "HAIKU" ] || [ "$os" = "OSX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ] || [ "$os" = "OS2" ]; then CFLAGS="$CFLAGS -DUNIX" fi # And others like Windows @@ -1677,7 +1629,16 @@ make_cflags_and_ldflags() { fi fi - if [ -n "$sdl_config" ]; then + if [ -n "$sdl2_config" ]; then + CFLAGS="$CFLAGS -DWITH_SDL2" + # SDL must not add _GNU_SOURCE as it breaks many platforms + CFLAGS="$CFLAGS `$sdl2_config --cflags | sed 's@-D_GNU_SOURCE[^ ]*@@'`" + if [ "$enable_static" != "0" ]; then + LIBS="$LIBS `$sdl2_config --static --libs`" + else + LIBS="$LIBS `$sdl2_config --libs`" + fi + elif [ -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[^ ]*@@'`" @@ -1712,7 +1673,7 @@ make_cflags_and_ldflags() { fi if [ -n "$lzma_config" ]; then - CFLAGS="$CFLAGS -DWITH_LZMA" + CFLAGS="$CFLAGS -DWITH_LIBLZMA" CFLAGS="$CFLAGS `$lzma_config --cflags | tr '\n\r' ' '`" if [ "$enable_static" != "0" ]; then @@ -1783,7 +1744,7 @@ make_cflags_and_ldflags() { fi if [ -n "$icu_layout_config" ]; then - CFLAGS="$CFLAGS -DWITH_ICU_LAYOUT" + CFLAGS="$CFLAGS -DWITH_ICU_LX" CFLAGS="$CFLAGS `$icu_layout_config --cflags | tr '\n\r' ' '`" if [ "$static_icu" != "0" ]; then @@ -1794,7 +1755,7 @@ make_cflags_and_ldflags() { fi if [ -n "$icu_sort_config" ]; then - CFLAGS="$CFLAGS -DWITH_ICU_SORT" + CFLAGS="$CFLAGS -DWITH_ICU_I18N" CFLAGS="$CFLAGS `$icu_sort_config --cflags | tr '\n\r' ' '`" if [ "$static_icu" != "0" ]; then @@ -1823,17 +1784,6 @@ make_cflags_and_ldflags() { 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" @@ -1869,20 +1819,12 @@ make_cflags_and_ldflags() { CFLAGS="$CFLAGS -DUNICODE -D_UNICODE" fi - if [ "$enable_network" != "0" ]; then - CFLAGS="$CFLAGS -DENABLE_NETWORK" + if [ "$os" = "HAIKU" ]; then + LDFLAGS="$LDFLAGS -lnetwork" + fi - 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 + if [ "$os" = "SUNOS" ]; then + LDFLAGS="$LDFLAGS -lnsl -lsocket" fi if [ "$enable_static" != "0" ]; then @@ -2361,7 +2303,7 @@ detect_awk() { detect_os() { if [ "$os" = "DETECT" ]; then - # Detect UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, HPUX, MORPHOS, BEOS, SUNOS, CYGWIN, MINGW, OS2, and DOS + # Detect UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, HPUX, SUNOS, CYGWIN, MINGW, and OS2 # Try first via dumpmachine, then via uname os=`echo "$host" | tr '[A-Z]' '[a-z]' | $awk ' @@ -2372,15 +2314,12 @@ detect_os() { /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 @@ -2392,8 +2331,6 @@ detect_os() { /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} @@ -2406,7 +2343,7 @@ detect_os() { 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" + log 1 "Allowed values are: UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, HPUX, HAIKU, SUNOS, CYGWIN, MINGW, and OS2" exit 1 fi @@ -2498,7 +2435,13 @@ detect_sdl() { sleep 5 fi - detect_pkg_config "$with_sdl" "sdl" "sdl_config" "1.2" + if [ $with_sdl = "sdl1" ]; then + detect_pkg_config "2" "sdl" "sdl_config" "1.2" + elif [ $with_sdl = "sdl2" ] || [ -x `which sdl2-config` ]; then + detect_pkg_config "2" "sdl2" "sdl2_config" "2.0" + else + detect_pkg_config "$with_sdl" "sdl" "sdl_config" "1.2" + fi } detect_osx_sdk() { @@ -2771,10 +2714,6 @@ 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" } @@ -2852,6 +2791,12 @@ detect_png() { } detect_freetype() { + if [ "$with_freetype" = "1" ] && ([ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]); then + log 1 "checking freetype2... WIN32, skipping" + freetype_config="" + return 0 + fi + detect_pkg_config "$with_freetype" "freetype2" "freetype_config" "2.2" "1" } @@ -3191,7 +3136,7 @@ detect_sse_capable_architecture() { 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: SSE couldn't be found" log 1 "configure: error: you force enabled SSE, but it seems unavailable" exit 1 fi @@ -3493,8 +3438,8 @@ showhelp() { 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 " NETBSD/HPUX/SUNOS/CYGWIN/" + echo " MINGW/OS2/HAIKU" echo "" echo "Paths:" echo " --prefix-dir=dir specifies the prefix for all installed" @@ -3548,7 +3493,6 @@ showhelp() { 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 " @@ -3563,13 +3507,11 @@ showhelp() { 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-sdl[=\"sdl1|sdl2\"] enables SDL video driver support" echo " --with-zlib[=\"pkg-config zlib\"]" echo " enables zlib support" echo " --with-liblzma[=\"pkg-config liblzma\"]" diff --git a/configure b/configure index afc1de51b4..239b162ea3 100755 --- a/configure +++ b/configure @@ -75,7 +75,7 @@ save_params make_cflags_and_ldflags EXE="" -if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "OS2" ] || [ "$os" = "DOS" ]; then +if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "OS2" ]; then EXE=".exe" fi @@ -110,24 +110,22 @@ AWKCOMMAND=' if ($0 == "ALLEGRO" && "'$allegro_config'" == "") { next; } if ($0 == "SDL" && "'$sdl_config'" == "") { next; } + if ($0 == "SDL2" && "'$sdl2_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 == "HAIKU" && "'$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; } + if ($0 == "USE_XAUDIO2" && "'$with_xaudio2'" == "0") { next; } + if ($0 == "USE_THREADS" && "'$with_threads'" == "0") { next; } + if ($0 == "USE_SSE" && "'$with_sse'" != "1") { next; } skip += 1; diff --git a/docs/admin_network.md b/docs/admin_network.md new file mode 100644 index 0000000000..ff5ea7c27a --- /dev/null +++ b/docs/admin_network.md @@ -0,0 +1,235 @@ +# OpenTTD's admin network + +Last updated: 2011-01-20 + + +## Table of contents + +- 1.0) [Preface](#10-preface) +- 2.0) [Joining the network](#20-joining-the-network) +- 3.0) [Asking for updates](#30-asking-for-updates) + - 3.1) [Polling manually](#31-polling-manually) +- 4.0) [Sending rcon commands](#40-sending-rcon-commands) +- 5.0) [Sending chat](#50-sending-chat) + - 5.1) [Receiving chat](#51-receiving-chat) +- 6.0) [Disconnecting](#60-disconnecting) +- 7.0) [Certain packet information](#70-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](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/compiling_lang_files.md b/docs/compiling_lang_files.md new file mode 100644 index 0000000000..234fcf2a65 --- /dev/null +++ b/docs/compiling_lang_files.md @@ -0,0 +1,69 @@ +# How to compile lang files (OpenTTD and strgen) + +Last updated: 2009-06-30 + +## strgen usage + +This guide is only interesting for people who want to alter something +themselves without access to [translator.openttd.org](https://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](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. + +## 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 `english.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. + +## 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/desync.md b/docs/desync.md new file mode 100644 index 0000000000..20003c9810 --- /dev/null +++ b/docs/desync.md @@ -0,0 +1,267 @@ +# Some explanations about Desyncs + +Last updated: 2014-02-23 + +## Table of contents + +- 1.0) Desync theory + - 1.1) [OpenTTD multiplayer architecture](#11-openttd-multiplayer-architecture) + - 1.2) [What is a Desync and how is it detected](#12-what-is-a-desync-and-how-is-it-detected) + - 1.3) [Typical causes of Desyncs](#13-typical-causes-of-desyncs) +- 2.0) What to do in case of a Desync + - 2.1) [Cache debugging](#21-cache-debugging) + - 2.2) [Desync recording](#22-desync-recording) +- 3.0) Evaluating the Desync records + - 3.1) [Replaying](#31-replaying) + - 3.2) [Evaluation of the replay](#32-evaluation-of-the-replay) + - 3.3) [Comparing savegames](#33-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 transferring 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 no one 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 happened, 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 improper 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 of 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.3) 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/landscape.html b/docs/landscape.html index d4d8f7efeb..4eac0926e7 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -16,7 +16,7 @@ Landscape grid page.

Nine attributes (counting "type" and - "height") hold the informations about a tile.
+ "height") hold the information about a tile.
These attributes are referred to as "type", "height", @@ -61,7 +61,7 @@ Bits 1..0: - + @@ -98,6 +98,32 @@ +
  • m4:
    + + Road roadtype. Used for all tiles with road (road, station, tunnelbridge). +
      +
    • + Bits 5..0: Road roadtype, 0x3F for no road. +
    • +
    +
  • +
  • m8:
    + + Tram roadtype. Used for all tiles with road (road, station, tunnelbridge). +
      +
    • + Bits 11..6: Tram roadtype, 0x3F for no tram. +
    • +
    +
  • +
  • m8:
    +
      +
    • + + Bits 5..0: Railtype. Used for all tiles with rail (road, rail, station, tunnelbridge). +
    • +
    +
  • m7:
    Animation frame/state. Used for houses, industries, objects and stations.
  • @@ -108,7 +134,7 @@
    Only meaningfull in tropic climate. It contains the definition of the available zones
    Only meaningful in tropic climate. It contains the definition of the available zones
    00normal
    01desert
    02rain forest
    - + @@ -223,6 +249,7 @@
    ClassMeaning & details of encodingMeaning & details of encoding
    0  
      +
    • m1 bit 7: Ship docking tile status (for half-tile with water)
    • m1 bits 4..0: owner of the tile
    • m2: see signals
    • m3 bits 7..4: see signals
    • @@ -535,21 +562,10 @@
    • 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) +
    • m4 bits 5..0: Roadtype
    • +
    • m7 bit 5 set = on snow or desert
    • +
    • m8 bits 11..6: Tramtype
    • m5 bits 7 clear: road or level-crossing
      • m6 bits 5..3: @@ -744,7 +760,7 @@
    - Newhouses is the name englobing a newGRF feature developped by TTDPatch devs (mainly Csaboka).
    + Newhouses is the name englobing a newGRF feature developed 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
    @@ -856,12 +872,14 @@
     
      +
    • m1 bit 7: Ship docking tile status (for buoys)
    • 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
    • +
    • m4: Roadtype for road stops
    • m5: graphics index (range from 0..255 for each station type): @@ -977,8 +995,8 @@
    • 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 11..6: Tramtype
    • m8 bits 5..0: track type for railway stations/waypoints
    • @@ -992,6 +1010,7 @@ diff --git a/docs/landscape_grid.html b/docs/landscape_grid.html index 4948366e65..d4a88d0bb5 100644 --- a/docs/landscape_grid.html +++ b/docs/landscape_grid.html @@ -100,7 +100,7 @@ the array so you can quickly see what is used and what is not. - + @@ -143,11 +143,11 @@ the array so you can quickly see what is used and what is not. - + - - + + @@ -159,8 +159,8 @@ the array so you can quickly see what is used and what is not. - - + + @@ -169,11 +169,11 @@ the array so you can quickly see what is used and what is not. - + - - + + @@ -208,7 +208,7 @@ the array so you can quickly see what is used and what is not. - + @@ -237,11 +237,11 @@ the array so you can quickly see what is used and what is not. - + - - + + @@ -300,7 +300,7 @@ the array so you can quickly see what is used and what is not. - + @@ -354,14 +354,14 @@ the array so you can quickly see what is used and what is not. - + - + - - + + @@ -370,7 +370,7 @@ the array so you can quickly see what is used and what is not. - + diff --git a/docs/linkgraph.md b/docs/linkgraph.md new file mode 100644 index 0000000000..1480bd9145 --- /dev/null +++ b/docs/linkgraph.md @@ -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.md b/docs/multiplayer.md new file mode 100644 index 0000000000..89a490602e --- /dev/null +++ b/docs/multiplayer.md @@ -0,0 +1,213 @@ +# Multiplayer manual for OpenTTD + +Last updated: 2011-02-16 + + +## Table of contents + +- 1.0) [Starting a server](#10-starting-a-server) +- 2.0) [Connecting to a server](#20-connecting-to-a-server) + - 2.1) [Connecting to a server over the console](#21-connecting-to-a-server-over-the-console) +- 3.0) [Playing internet games](#30-playing-internet-games) +- 4.0) [Tips for servers](#40-tips-for-servers) + - 4.1)[Imposing landscaping limits](#41-imposing-landscaping-limits) +- 5.0) [Some useful things](#50-some-useful-things) +- 6.0) [Troubleshooting](#60-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/findversion.sh b/findversion.sh index 95a041bac0..0da382476a 100755 --- a/findversion.sh +++ b/findversion.sh @@ -59,7 +59,7 @@ 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 +if [ -d "$ROOT_DIR/.git" ] || [ -f "$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 diff --git a/known-bugs.txt b/known-bugs.txt index 342e75305d..2053a6ad37 100644 --- a/known-bugs.txt +++ b/known-bugs.txt @@ -1,6 +1,6 @@ OpenTTD's known bugs -Last updated: 2019-09-16 -Release version: 1.9.3 +Last updated: 2019-10-29 +Release version: 1.10.0-beta1 ------------------------------------------------------------------------ @@ -220,7 +220,7 @@ Entry- and exit signals are not dragged [#4378]: 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 + due to compatibility 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 @@ -404,7 +404,7 @@ Some houses and industries are not affected by transparency [#5817]: 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 + interrupted if one of the players stops competing for the resources 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 diff --git a/media/baseset/orig_win.obm b/media/baseset/orig_win.obm index b5d4b024ed..2171417830 100644 --- a/media/baseset/orig_win.obm +++ b/media/baseset/orig_win.obm @@ -90,7 +90,7 @@ 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. +; MIDI timecodes where the playback should attempt 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] diff --git a/media/extra_grf/openttdgui.nfo b/media/extra_grf/openttdgui.nfo index d0fbba0e70..b01a70f795 100644 --- a/media/extra_grf/openttdgui.nfo +++ b/media/extra_grf/openttdgui.nfo @@ -7,7 +7,7 @@ // See the GNU 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 * 3 05 15 \b 184 // 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 @@ -187,3 +187,8 @@ -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 + -1 sprites/openttdgui_build_tram.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_convert_road.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_convert_road.png 8bpp 24 0 32 32 0 0 normal + -1 sprites/openttdgui_convert_tram.png 8bpp 0 0 20 20 0 0 normal + -1 sprites/openttdgui_convert_tram.png 8bpp 24 0 32 32 0 0 normal diff --git a/media/extra_grf/openttdgui_build_tram.png b/media/extra_grf/openttdgui_build_tram.png new file mode 100644 index 0000000000000000000000000000000000000000..d9af8effe2d2ccb820df1d8a24251e13aae68f9e GIT binary patch literal 1017 zcmeAS@N?(olHy`uVBq!ia0y~yU=RUe4rT@hhF#%r?HL%D83KGlTp1Yt3kV1(C@2^h z7&tgM1Ox=6q@cI-HD;>3*`H(tDW@#oJU6B`c~pO}b*f}E0; zmYx}N7OdH@kDV>^bn~0>hsdHh=y! z_-HUB*l?6Y$aIug%;^Z&Fem58mJSyQh6Ej!1{aPw2?9GRB(BU+c(Fs^&lQG0KN|l0 zIiSG8;2^>gA|sHaBhz4^F~!4TMU2mmoQNY0Iaj7MaF{R%I4~##uoxt;I27=Nw1{L( zk!e_=BV!_=J zof8TY3>GpB9vUnWCOjDq5;Y+@Jvj~w8X|l&1QJXnN?bHLLM)afIP540IMa}DWlF(= z6%B9pObL)-Nzo9gu+Zr7aafR&u%n|xMZ?9wB*eiXB_N*J$sZGwKPeG^Ce-}dvEa{*6Mw$E z@enD9(dj90S<#bnWJSk=6B~Y9*zy0xg+De73^5E04Gatm7#NN)Fg##j_`|^PCxGEk z4#S@ghCfRf{v2TVbBE#2ABHm>98V^&{F%e>XM@3?BPoAw%;1oS;8DpCF{zPp>CuQ; zVo|ZjW5$h?H4kFunB;75s5#*?;X%xUFMm$F`LX5Bo0dH{B4(`l!tmuQ!`E*N-@Y?^ z|H1I%C&SNQ48MLe{Qkr6=P$$Ge+>WrGyM0F;KGcXt!FgQ3c1Ozbr|IeV{QlR2dqTy4a6HsFi(%_LYA*E%- zjW2%^8kV>u^!)$-|8%(bLIwr~#w2fd7lsa2Sq}yV2F?PH$YKTtZeb8+WSBKaf`Ng7 zy~NYkmHjcJ90RYZ(f)#e3=9nQo-U3d5|>jaUgSDzz~Q|5qF43*|Mlyy_P%`PZSX|k zg5j|RX3A|GKNuH1Iy6V`<4u>tM{<>XIUT*d{5K`3zYF>>_lKUvIkkx)dC#QT!yf5< z*|Pq~^~-*VSu+mlRz6&MS7>`!N~iP|b^g4y8EST~9V^uAPCL#}uNKk!K5_s1AI$5y XSwd6=VwW>8Ffe$!`njxgN@xNAPcyeV literal 0 HcmV?d00001 diff --git a/media/extra_grf/openttdgui_convert_road.png b/media/extra_grf/openttdgui_convert_road.png new file mode 100644 index 0000000000000000000000000000000000000000..9218e770544b2533ff736e0c10336307b91a0dbb GIT binary patch literal 1274 zcmeAS@N?(olHy`uVBq!ia0y~yV6b3dU{K&-W?*0_xa)n3fq|JJz$e6&f#JV^fPjL6 zf`Ng7gM&jrKtM`LN=ZpcOH0d?DN|OgSg~WrjuR(N+_-V$#fukz{`@hq@o@2piAX5O zDQRixnK5Uo`A{-$y0y#P|4Hg~|I0Z&Ma zNX8VIh7~$8CK5U>3N{f20U0(KH9iefVrFc}*>a{vz(hj9L&qY)!>1%7p(CeaNym%> zD|XyDp&-FvA;aLI!4hG@li?sy6Qa|TfXe#+ok-U%oPY{l@U^ zJHz)M3_pG{{QSl6>o>#iKMa5VGW`9=@b5pve;)~s936=X9wr-dLM~0J`(wlKCxqco z2E(5khCfpn{;Xm6bA-Wxf#E*`gMk5qg9AfA0K@oJ{39vH3lIK9w`%2 zT2|cn@+YBTiAzGy|Ns9_hkGw%U|?WO@^*J&=wOxgU|?Y2EbxddW?-hwjL)?OML!;jF|JPgo%$oP~LeEhVgW^SR`-F>b@JLB2S6t40UFdl4 zl4G*b@!NTKW%tOLInA}a)%1JY&C3Ukon#kWs^3`~FTdl7Y*UWk4~3STo4coN(B)kC z*yD}pebI%JX0}K??hi{;J8qFa<<|4_)t=n}ns=saG=H9X#6e^B*&`7X+Ly9C?D>5% z)wEz!$`YQs=RFHq%#})N8;dXJn(51P@zfV#uO>}z;?#R1EPGDk+}x@e zyF&M^n#~q>ol7o^C;Hsc+eh=J8XNWO{@HLye@3ac!~WGGkMp@Trk1aaE_AawF8EkX zz3v#p)a-zpYkw@<`Ap!9Mo`A{-$y0y#P|4Hg~|I0Z&Ma zNX8VIh7~$8CK5U>3N{f20U0(KH9iefVrFc}*>a{vz(hj9L&qY)!>1%7p(CeaNym%> zD|XyDp&-FvA;aLI!4hG@li?sy6Qa|TfXe#+ok-U%oPY{l@U^ zJHz)M3_pG{{QSl6>o>#iKMa5VGW`9=@b5pve;)~s936=X9wr-dLM~0J`(wlKCxqco z2E(5khCfpn{;Xm6bA-Wxf#E*`gMk5qg9AfA0K@oJ{39vH3lIK9w`%2 zT2|cn@+YBTiAzGy|Ns9_hkGw%U|?WO@^*J&=wOxgU|?Y2EbxddW?M_Y5}9Zi;3FXzx`MA zx)nk)DvUkrj_B|BaK^;+lXK+ttCrq|Y=tv-eVoH3=J)mP$3-&x8uCsCUMRi&xFXn3 zazSxx^SIY(REZ2rCNXL!SUp4_Hm|DJ#Q`|*kD`w1!Khn5Q@X}{arR;$_K zCh%|W`>6{fxjYN?P;CuX+! zO}n=E{ZzM;pFRjlwC%fK8Dmtox}jvYhme4WoLota;V#Y7SJtlfW(p8;ohFwkW|M4H zF8T24+E-!ep7~zd{9VVMie8@9Y!&-1tf_d8z)#U_%-Sm+HMwpV3fZ$<<9X!#$6*DA z7h~_9GUj?98F*R$jF9UbLq}n$kaBJN3>U`&g$*m4%xvOHw|A*e(cf?9{o>lwduti$ ztvm}#*XHp$q(|SCYPhy-mnlPL`1`w3GcWE4+kPxzadh&Ai)#-`=HHDvmXP6hbL|D0 zuad{?b@%=GCDT|U_@{Hx+rJzqPeyzEV_Liapvc|HZ@3v47#KWV{an^LB{Ts5x6(ZJ literal 0 HcmV?d00001 diff --git a/media/extra_grf/tramtracks.nfo b/media/extra_grf/tramtracks.nfo index 5a078194b9..89c3e5c6ea 100644 --- a/media/extra_grf/tramtracks.nfo +++ b/media/extra_grf/tramtracks.nfo @@ -7,7 +7,7 @@ // See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . // -1 * 0 0C "Tram track graphics by PikkaBird" - -1 * 3 05 0B 71 + -1 * 3 05 0B 77 -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 @@ -121,3 +121,9 @@ -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 + -1 sprites/tramtracks_bare_depot.png 8bpp 0 0 64 31 -31 0 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 80 0 62 64 2 -49 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 158 0 64 31 -31 0 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 238 0 62 64 -62 -49 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 318 0 62 64 -62 -49 normal + -1 sprites/tramtracks_bare_depot.png 8bpp 398 0 62 64 2 -49 normal diff --git a/media/extra_grf/tramtracks_bare_depot.png b/media/extra_grf/tramtracks_bare_depot.png new file mode 100644 index 0000000000000000000000000000000000000000..d45bcff41e0b222dcadaaec032620405cff2ea21 GIT binary patch literal 3661 zcmeAS@N?(olHy`uVBq!ia0y~yU_8UXz~I2a%)r2~fMNS$1_ow^0G|+728RCv0s;yO z3I+xS4h{|h0Rbr~DJ3N(EiElmrc7C}V#SUfJ5HQ9apT5~7cXA?`SZub#>2%YCL*CA zr=+E&XU3cbYc}jSa^}Jv105Cz8=e3kk%SnTiVBA*Q&Ki;XgPCcg@+DHgpEi>fKE+@ z$BdSk9SbV1?3wcA&IShtmIxMs0s(~%1(O99K6^rP&SccwX_@e5&XPZS4*a>m@aKii zpFa&g8Vm_G93>Gl9VHfXIs!J#$vLv6!$pE2L5HQmg=0>Fz>W%uD{~ZH>=5{Kh2hVS zhChD}D6lX%h;W3+2;}I+<1w0`w zA{kR;8dm7Ym`LcjDA+_81Z3D`)c7<^iJ7q>XUmxy0TT%Y4;_mH51*2VgpQnwB^@&k ztk`kqgn|Tvg$#p-21|qqPlkg;O^8lUj>Ce62p5MG$dS^ zQt)6!!<#)*0%TZHG(;*aG1b(LvS!VJD_0(9 zh!i;JOo(t;li_ouBH}?$#-9ZpfA*~S!yu8vpwhx%vVg&32SdUYiHbWG6JA8D_|S0V z&z=W=1RN410&+AGDohGm0(usdtT`~}%$+kI{;V-Exng4S$He4MO2nTDHGg(2_;cgL zpD%AbL<(YbdJ0@t^rReF(edEKh94Jp{C{!bj|~Gu3N$C0i|NrT5?}ZEu+#H@Rjv*Dd-p=tYx@{rc#`&m!!IRWgdp^2_TDGjN zV5nQ7x8Uxb=FJ^mmUmS8&YQ%WI|Th<W_9W^7c$ws<7kZ$Nc9X zJuY55_wM2&)_8;c33Uhm^dIWE;@-6Kiujp>B}%HvqO~G3xHgBz8?1flq9s(M{`x@pZ&a1xQn&UGQmx$@Acnvih}hs zBBwns4y-yj=d$HzKie|wOyJV(%8L{_9$>Qk>^XPK$0pXZ)&|!s-?@`< z+4i%abGNy^vpYNMub#xa$cMGF&gMH>zBaL*v^MyUVzIF6_5&v2)wlOZTDV{4%)GnF zLB?-y;=Q&@!fK_duSM?X<)xfy*{bQ=qy*WKE<;>26 zp28o$#C{$U=>?g1sAy%y_WSesgl>sr2nI2NO$9_(RMqK%-h+?dg#HAhD!BCd;Rz1uZ0-Q zc|qMuWSuc^QqopXz8=lwq569w}A(x*)!kDBx1 zMV1L>F*6B%>M-C`yq1$bCr$d#Y3Q+c(6_F*xM6t2VIG zYJr3P`t|2qTs|froMNbW{#(x8gl}igKFw(`aH-t+FsCc89CYiR0f@d+|kq zQ)66f$0Ei1rRpy31uJrkO{a9@$esk`Ur`&-M;m=rGs@{6ce zFxTCE89bk41fF)h-^F}p8NZA1p{SetejVI0OS-Z#uT%Eh%S`p1{5}lFLrb?_eRgtf z`m!etUtG%7r=;I0&*cl=_IaYANlfM0YvRkU-r-nMd2rPfoAW=uRM?y~*!d}|e)jei zF>{O$aNPeIcmJWtuWO%UpUgAxymPw!Q}(v1v?4p%Wq0p5)Xw#uQh9LMG3LAf^tz^m zhyT94hxO^9-+s%CB;S+@zPs_Vz^iIs_m3phbwh|CdfbZnQ9(8g~!>T{}Suwo^(@lljdJWp_Ybm-g`e~ z?U{ePdgJX^kxci#T{v!V<26ss#GCO|>mRQS`yg+7U-aQ?%j+%wVt-y-;Z^bI#huf~ z=cKXj4ilVFY7w@{@Z;)=w0mV|dnfFPoO-Sz_v-?y?nPf%rj+O0%Z}bFnsDgYVUa^w z^`3K_W~pXdtJ^$WDeyjL!}IjX7sL!4E7vHU@csI^k+ZeT>p|n=bior^$-0QGG?Fi{H@2uWU{Kbc1CHa zTae+s)9%YPKcpVc7H$0Xp+8Y#$D_=ZlJ93oudir+_439od6VSrSEFO>EH1fTc#~OP zpE*nSc}k5q&&pL+iu11~&bpblYEq$%_O{vuX*bs@X?-ZuP+V8xbpH0bogX{Rm&tuI zzh>&UXyv^}pO$*g3@ERE_$|v){qgRE&Na8>>`-=Y8hQpU#UHB zrBCmdth_yscvq*V?d+3{>lHp89J==2BZH66@8tgOPTu}t&&xSR4ktDEofp-&UOTq= zhrkcnY5aWt=Qf4eDe#uK(?4F&pBrK z@Gnd6B#9~Y+Zul^?-YI>`;z(RhaBTe>18u^+>uh33p^9pdcMnimE0Ttw7v+5wITdl zj5RikCOD~i20i%Q<+e(APVm$-_G#%8?H~RYGhnWmrRVqd$%YKKRUB0tMANq3QS&p= zFn+xAiu32iz6Gs9^S-U++Ro-vQyw;Q{z`fsvf{~L|%O*fBQ2Dz>ftvUT>>dm;k-r~GH zFJFa*-sISRh;hZMUpw})eG`A;lr`mHwFFD_;Wv-BgioC4l|A(~zr)<8*DRhNoxMaZ z)AUC6js(&9EBRBF{ar5h{ED0BvH0qE?lk`8rQ2r8O_SXD#$fm9wFT$8%zgJtrCQ(N z$`vaQNpjn9Qr+{`@70-Z_c~wS6@Pv3&7&=6%r-wQ{(RfcSogGU;kiz8*S)XTylII( zn*K_YZ?96TZrF>rS8Zm`jAl8~R+K$McFr`dRp0gso_lAkd)ibm{YdfZ@Ow%dTB8>m z`L6a5`dq0pBW~4xAEz&`v`Z>o5FW~q*!p*!c{)~+wt1??4-SJ&}wx!L$M$>n{8-q%-= zncUm`X8V2(Q8kB+H-!*C_3}y`PGzXuQNmr|Ng*ipJ}iw=6{8GOZ4;f zhBFJTE~@AJEp*(K`NIE;*0F$l{L2n<-u^e^s@2o$N)lJJ3Utc-_S}4UtugZ5dXu$w zzgJozz5UM}Yrj$m};46VoE& zqPAy(4813I-uTWfgVl+7YQNlP%-kvG^_S0#GcAAT_G6#9w%eUq@aZb&KA{gkaNEY%s~73m7gJt*_&sYzw5cnvN`Tu&_}h_+kDFk{ak;YFt~i^&iXipw4HaJKJw+* uuIl5FVKa62VIHn{khiAyJm(SrBR{Qh&F4yKGZO{|1_n=8KbLh*2~7alF%m`q literal 0 HcmV?d00001 diff --git a/os/debian/changelog b/os/debian/changelog index 67b0e802c1..a523172234 100644 --- a/os/debian/changelog +++ b/os/debian/changelog @@ -1,3 +1,9 @@ +openttd (1.10.0~beta1-0) unstable; urgency=low + + * New upstream release 1.10.0-beta1 + + -- OpenTTD Tue, 29 Oct 2019 00:00:00 +0000 + openttd (1.9.3-0) unstable; urgency=low * New upstream release 1.9.3 @@ -7,7 +13,6 @@ openttd (1.9.3-0) unstable; urgency=low 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 @@ -1057,7 +1062,7 @@ openttd (0.4.0-1) unstable; urgency=low openttd (0.3.6-1) unstable; urgency=low * New upstream release - * Modifed Makefile to install xpm icon and scenarios in /usr/share/games/openttd/ + * Modified 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 diff --git a/os/debian/control b/os/debian/control index 54e14ce5d4..01b66cc494 100644 --- a/os/debian/control +++ b/os/debian/control @@ -3,7 +3,7 @@ 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 +Build-Depends: debhelper (>= 7.0.50), libsdl2-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 diff --git a/os/debian/rules b/os/debian/rules index dfd39253ef..b5d67670bd 100755 --- a/os/debian/rules +++ b/os/debian/rules @@ -29,7 +29,7 @@ include /usr/share/dpkg/buildflags.mk # 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)" + ./configure $(CROSS) --prefix-dir=/usr --install-dir=debian/openttd --without-allegro --with-zlib --with-sdl --with-png --with-freetype --with-fontconfig --with-icu-sort --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: diff --git a/os/os2/installer/make_installer.cmd b/os/os2/installer/make_installer.cmd index 07ee359dd8..3addeca1ae 100644 --- a/os/os2/installer/make_installer.cmd +++ b/os/os2/installer/make_installer.cmd @@ -1,6 +1,6 @@ @echo off -set OPENTTD_VERSION=1.9.3 +set OPENTTD_VERSION=1.10.0 set OPENSFX_VERSION=0.8.0 set NOSOUND_VERSION=0.8.0 set OPENGFX_VERSION=1.2.0 diff --git a/os/os2/installer/openttd.wis b/os/os2/installer/openttd.wis index e580e565cf..4b761ed83c 100644 --- a/os/os2/installer/openttd.wis +++ b/os/os2/installer/openttd.wis @@ -71,7 +71,7 @@ ~Next -README.TXT +README.md 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. @@ -80,7 +80,7 @@ Select "Next" to continue, or "Cancel" to abort installation. ~Next -COPYING +COPYING.md OpenTTD is licenced under the GNU General Public License. The text of the licence is below. Select "Next" if you agree to this licence. diff --git a/os/rpm/openttd.changes b/os/rpm/openttd.changes index b0a64dfe18..351f260799 100644 --- a/os/rpm/openttd.changes +++ b/os/rpm/openttd.changes @@ -46,7 +46,7 @@ Sat May 1 15:59:32 UTC 2010 - Marcel Gmür Thu Apr 1 08:53:54 UTC 2010 - Marcel Gmür - upstream update 1.0.0 (finally!) - * completely independend game but still working also + * completely independent game but still working also with ttd original gaphics, sounds and music - Add: Recommends openmsx - requires lzo2 @@ -54,7 +54,7 @@ Thu Apr 1 08:53:54 UTC 2010 - Marcel Gmür ------------------------------------------------------------------- Fri Dec 18 2009 Marcel Gmür - 0.7.4 -- support for differen branches +- support for different branches - easy support for dedicated branch - let openttd build system make the dektop file - split the package to data and gui diff --git a/os/rpm/openttd.spec b/os/rpm/openttd.spec index 1c0f55f46c..4ba8c00672 100644 --- a/os/rpm/openttd.spec +++ b/os/rpm/openttd.spec @@ -17,9 +17,9 @@ # Name: openttd -Version: 1.9.3 +Version: 1.10.beta1 Release: 0 -%define srcver 1.9.3 +%define srcver 1.10.0-beta1 Summary: An open source reimplementation of Chris Sawyer's Transport Tycoon Deluxe License: GPL-2.0 Group: Amusements/Games/Strategy/Other @@ -61,7 +61,7 @@ BuildRequires: kernel BuildRequires: pkg-config %endif -# bulding openttd.grf is not required as it is a) part of source and +# building 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 @@ -81,7 +81,7 @@ 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 +information, see the file 'COPYING.md' included with every release and source download of the game. %package gui @@ -91,7 +91,7 @@ Group: Amusements/Games/Strategy/Other Requires: %{name} Conflicts: %{name}-dedicated -BuildRequires: SDL-devel +BuildRequires: SDL2-devel BuildRequires: fontconfig-devel %if 0%{?rhel_version} != 600 diff --git a/os/windows/installer/install.nsi b/os/windows/installer/install.nsi index 54c739ad94..a4dd610d93 100644 --- a/os/windows/installer/install.nsi +++ b/os/windows/installer/install.nsi @@ -1,9 +1,9 @@ # Version numbers to update !define APPV_MAJOR 1 -!define APPV_MINOR 9 -!define APPV_MAINT 3 +!define APPV_MINOR 10 +!define APPV_MAINT 0 !define APPV_BUILD 0 -!define APPV_EXTRA "" +!define APPV_EXTRA "-beta1" !define APPNAME "OpenTTD" ; Define application name !define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version @@ -63,7 +63,7 @@ Var CDDRIVE !define MUI_ABORTWARNING !define MUI_WELCOMEPAGE_TITLE_3LINES !insertmacro MUI_PAGE_WELCOME -!insertmacro MUI_PAGE_LICENSE "..\..\..\COPYING" +!insertmacro MUI_PAGE_LICENSE "..\..\..\COPYING.md" !define MUI_COMPONENTSPAGE_SMALLDESC !insertmacro MUI_PAGE_COMPONENTS @@ -143,10 +143,10 @@ Section "!OpenTTD" Section1 Push "$INSTDIR\scripts\README.md" Call unix2dos - ; Copy some documention files + ; Copy some documentation files SetOutPath "$INSTDIR\docs\" - File ${PATH_ROOT}docs\multiplayer.txt - Push "$INSTDIR\docs\multiplayer.txt" + File ${PATH_ROOT}docs\multiplayer.md + Push "$INSTDIR\docs\multiplayer.md" Call unix2dos ; Copy the rest of the stuff @@ -156,8 +156,8 @@ Section "!OpenTTD" Section1 File ${PATH_ROOT}changelog.txt Push "$INSTDIR\changelog.txt" Call unix2dos - File ${PATH_ROOT}COPYING - Push "$INSTDIR\COPYING" + File ${PATH_ROOT}COPYING.md + Push "$INSTDIR\COPYING.md" Call unix2dos File ${PATH_ROOT}README.md Push "$INSTDIR\README.md" @@ -218,7 +218,7 @@ Section "!OpenTTD" Section1 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" + CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Docs\Multiplayer.lnk" "$INSTDIR\docs\multiplayer.md" CreateDirectory "$SMPROGRAMS\$SHORTCUTS\Scripts" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Scripts\Readme.lnk" "$INSTDIR\scripts\README.md" !insertmacro MUI_STARTMENU_WRITE_END @@ -392,7 +392,7 @@ Section "Uninstall" Delete "$INSTDIR\README.md" Delete "$INSTDIR\known-bugs.txt" Delete "$INSTDIR\openttd.exe" - Delete "$INSTDIR\COPYING" + Delete "$INSTDIR\COPYING.md" Delete "$INSTDIR\INSTALL.LOG" Delete "$INSTDIR\crash.log" Delete "$INSTDIR\crash.dmp" diff --git a/projects/generate b/projects/generate index cfedc8b32d..2ab89e8f1b 100755 --- a/projects/generate +++ b/projects/generate @@ -132,14 +132,14 @@ load_main_data() { 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 == "HAIKU" && "'$os'" != "HAIKU") { 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; } + if ($0 == "USE_XAUDIO2" && "'$with_xaudio2'" == "0") { next; } + if ($0 == "USE_THREADS" && "'$with_threads'" == "0") { next; } skip += 1; diff --git a/projects/generate.vbs b/projects/generate.vbs index aa91bd3164..06e037c4cd 100755 --- a/projects/generate.vbs +++ b/projects/generate.vbs @@ -179,8 +179,9 @@ Sub load_main_data(filename, ByRef vcxproj, ByRef filters, ByRef files) line = "MSVC" Or _ line = "DIRECTMUSIC" Or _ line = "AI" Or _ - line = "SSE" Or _ - line = "HAVE_THREAD" _ + line = "USE_SSE" Or _ + line = "USE_XAUDIO2" Or _ + line = "USE_THREADS" _ ) Then skip = skip + 1 deep = deep + 1 Case "#" diff --git a/projects/generate_vs142.vcxproj b/projects/generate_vs142.vcxproj index 3e55d7a1d4..7230676cb5 100644 --- a/projects/generate_vs142.vcxproj +++ b/projects/generate_vs142.vcxproj @@ -10,7 +10,6 @@ generate {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34} generate - 8.1 diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj index 93414161e3..a1e86d9d21 100644 --- a/projects/openttd_vs140.vcxproj +++ b/projects/openttd_vs140.vcxproj @@ -107,7 +107,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -172,7 +172,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -230,7 +230,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -293,7 +293,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -449,6 +449,7 @@ + @@ -585,6 +586,7 @@ + @@ -615,6 +617,7 @@ + @@ -626,6 +629,7 @@ + @@ -647,6 +651,7 @@ + @@ -681,6 +686,7 @@ + @@ -697,6 +703,7 @@ + @@ -727,6 +734,7 @@ + @@ -741,7 +749,6 @@ - @@ -963,6 +970,7 @@ + @@ -1101,6 +1109,7 @@ + @@ -1167,6 +1176,7 @@ + @@ -1241,6 +1251,7 @@ + @@ -1303,8 +1314,6 @@ - - @@ -1335,6 +1344,7 @@ + @@ -1342,14 +1352,14 @@ + - - + diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters index d2b31be452..87701d523a 100644 --- a/projects/openttd_vs140.vcxproj.filters +++ b/projects/openttd_vs140.vcxproj.filters @@ -438,6 +438,9 @@ Header Files + + Header Files + Header Files @@ -846,6 +849,9 @@ Header Files + + Header Files + Header Files @@ -936,6 +942,9 @@ Header Files + + Header Files + Header Files @@ -969,6 +978,9 @@ Header Files + + Header Files + Header Files @@ -1032,6 +1044,9 @@ Header Files + + Header Files + Header Files @@ -1134,6 +1149,9 @@ Header Files + + Header Files + Header Files @@ -1182,6 +1200,9 @@ Header Files + + Header Files + Header Files @@ -1272,6 +1293,9 @@ Core Source Code + + Core Source Code + Core Source Code @@ -1314,9 +1338,6 @@ Core Source Code - - Core Source Code - Core Source Code @@ -1980,6 +2001,9 @@ Tables + + Tables + Tables @@ -2394,6 +2418,9 @@ Script API + + Script API + Script API @@ -2592,6 +2619,9 @@ Script API Implementation + + Script API Implementation + Script API Implementation @@ -2814,6 +2844,9 @@ NewGRF + + NewGRF + NewGRF @@ -3000,12 +3033,6 @@ Pathfinder - - Pathfinder - - - Pathfinder - Pathfinder @@ -3096,6 +3123,9 @@ Video + + Video + Video @@ -3117,6 +3147,9 @@ Sound + + Sound + Sound @@ -3135,12 +3168,9 @@ Windows files - + Threading - - Threading - diff --git a/projects/openttd_vs140.vcxproj.in b/projects/openttd_vs140.vcxproj.in index 8a9b9a8f97..b5628a23d3 100644 --- a/projects/openttd_vs140.vcxproj.in +++ b/projects/openttd_vs140.vcxproj.in @@ -107,7 +107,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -172,7 +172,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -230,7 +230,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -293,7 +293,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj index 0515f681b3..5f5ab9a408 100644 --- a/projects/openttd_vs141.vcxproj +++ b/projects/openttd_vs141.vcxproj @@ -107,7 +107,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -172,7 +172,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -230,7 +230,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -293,7 +293,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -449,6 +449,7 @@ + @@ -585,6 +586,7 @@ + @@ -615,6 +617,7 @@ + @@ -626,6 +629,7 @@ + @@ -647,6 +651,7 @@ + @@ -681,6 +686,7 @@ + @@ -697,6 +703,7 @@ + @@ -727,6 +734,7 @@ + @@ -741,7 +749,6 @@ - @@ -963,6 +970,7 @@ + @@ -1101,6 +1109,7 @@ + @@ -1167,6 +1176,7 @@ + @@ -1241,6 +1251,7 @@ + @@ -1303,8 +1314,6 @@ - - @@ -1335,6 +1344,7 @@ + @@ -1342,14 +1352,14 @@ + - - + diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters index d2b31be452..87701d523a 100644 --- a/projects/openttd_vs141.vcxproj.filters +++ b/projects/openttd_vs141.vcxproj.filters @@ -438,6 +438,9 @@ Header Files + + Header Files + Header Files @@ -846,6 +849,9 @@ Header Files + + Header Files + Header Files @@ -936,6 +942,9 @@ Header Files + + Header Files + Header Files @@ -969,6 +978,9 @@ Header Files + + Header Files + Header Files @@ -1032,6 +1044,9 @@ Header Files + + Header Files + Header Files @@ -1134,6 +1149,9 @@ Header Files + + Header Files + Header Files @@ -1182,6 +1200,9 @@ Header Files + + Header Files + Header Files @@ -1272,6 +1293,9 @@ Core Source Code + + Core Source Code + Core Source Code @@ -1314,9 +1338,6 @@ Core Source Code - - Core Source Code - Core Source Code @@ -1980,6 +2001,9 @@ Tables + + Tables + Tables @@ -2394,6 +2418,9 @@ Script API + + Script API + Script API @@ -2592,6 +2619,9 @@ Script API Implementation + + Script API Implementation + Script API Implementation @@ -2814,6 +2844,9 @@ NewGRF + + NewGRF + NewGRF @@ -3000,12 +3033,6 @@ Pathfinder - - Pathfinder - - - Pathfinder - Pathfinder @@ -3096,6 +3123,9 @@ Video + + Video + Video @@ -3117,6 +3147,9 @@ Sound + + Sound + Sound @@ -3135,12 +3168,9 @@ Windows files - + Threading - - Threading - diff --git a/projects/openttd_vs141.vcxproj.in b/projects/openttd_vs141.vcxproj.in index 57e153fc7d..015c23d3c5 100644 --- a/projects/openttd_vs141.vcxproj.in +++ b/projects/openttd_vs141.vcxproj.in @@ -107,7 +107,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -172,7 +172,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -230,7 +230,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -293,7 +293,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj index c44950c1d5..0a79a66383 100644 --- a/projects/openttd_vs142.vcxproj +++ b/projects/openttd_vs142.vcxproj @@ -78,16 +78,16 @@ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ - AllRules.ruleset + NativeMinimumRules.ruleset - AllRules.ruleset + NativeMinimumRules.ruleset - AllRules.ruleset + NativeMinimumRules.ruleset - AllRules.ruleset + NativeMinimumRules.ruleset $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ @@ -107,7 +107,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -172,7 +172,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -230,7 +230,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -293,7 +293,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -449,6 +449,7 @@ + @@ -585,6 +586,7 @@ + @@ -615,6 +617,7 @@ + @@ -626,6 +629,7 @@ + @@ -647,6 +651,7 @@ + @@ -681,6 +686,7 @@ + @@ -697,6 +703,7 @@ + @@ -727,6 +734,7 @@ + @@ -741,7 +749,6 @@ - @@ -963,6 +970,7 @@ + @@ -1101,6 +1109,7 @@ + @@ -1167,6 +1176,7 @@ + @@ -1241,6 +1251,7 @@ + @@ -1303,8 +1314,6 @@ - - @@ -1335,6 +1344,7 @@ + @@ -1342,14 +1352,14 @@ + - - + diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters index d2b31be452..87701d523a 100644 --- a/projects/openttd_vs142.vcxproj.filters +++ b/projects/openttd_vs142.vcxproj.filters @@ -438,6 +438,9 @@ Header Files + + Header Files + Header Files @@ -846,6 +849,9 @@ Header Files + + Header Files + Header Files @@ -936,6 +942,9 @@ Header Files + + Header Files + Header Files @@ -969,6 +978,9 @@ Header Files + + Header Files + Header Files @@ -1032,6 +1044,9 @@ Header Files + + Header Files + Header Files @@ -1134,6 +1149,9 @@ Header Files + + Header Files + Header Files @@ -1182,6 +1200,9 @@ Header Files + + Header Files + Header Files @@ -1272,6 +1293,9 @@ Core Source Code + + Core Source Code + Core Source Code @@ -1314,9 +1338,6 @@ Core Source Code - - Core Source Code - Core Source Code @@ -1980,6 +2001,9 @@ Tables + + Tables + Tables @@ -2394,6 +2418,9 @@ Script API + + Script API + Script API @@ -2592,6 +2619,9 @@ Script API Implementation + + Script API Implementation + Script API Implementation @@ -2814,6 +2844,9 @@ NewGRF + + NewGRF + NewGRF @@ -3000,12 +3033,6 @@ Pathfinder - - Pathfinder - - - Pathfinder - Pathfinder @@ -3096,6 +3123,9 @@ Video + + Video + Video @@ -3117,6 +3147,9 @@ Sound + + Sound + Sound @@ -3135,12 +3168,9 @@ Windows files - + Threading - - Threading - diff --git a/projects/openttd_vs142.vcxproj.in b/projects/openttd_vs142.vcxproj.in index 7176fea58a..83befcd8d0 100644 --- a/projects/openttd_vs142.vcxproj.in +++ b/projects/openttd_vs142.vcxproj.in @@ -78,16 +78,16 @@ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ - AllRules.ruleset + NativeMinimumRules.ruleset - AllRules.ruleset + NativeMinimumRules.ruleset - AllRules.ruleset + NativeMinimumRules.ruleset - AllRules.ruleset + NativeMinimumRules.ruleset $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ @@ -107,7 +107,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -172,7 +172,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -230,7 +230,7 @@ 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) + NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;WITH_ASSERT;%(PreprocessorDefinitions) true Sync MultiThreaded @@ -293,7 +293,7 @@ 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) + _DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_XAUDIO2;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LIBLZMA;WITH_PNG;WITH_UNISCRIBE;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug diff --git a/projects/settingsgen_vs142.vcxproj b/projects/settingsgen_vs142.vcxproj index ca0418c15c..23a4e18562 100644 --- a/projects/settingsgen_vs142.vcxproj +++ b/projects/settingsgen_vs142.vcxproj @@ -10,7 +10,6 @@ settingsgen {E9548DE9-F089-49B7-93A6-30BE2CC311C7} settings - 8.1 diff --git a/projects/strgen_vs142.vcxproj b/projects/strgen_vs142.vcxproj index 5329d68daa..554109b045 100644 --- a/projects/strgen_vs142.vcxproj +++ b/projects/strgen_vs142.vcxproj @@ -10,7 +10,6 @@ strgen {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} strgen - 8.1 @@ -30,9 +29,9 @@ $(SolutionDir)..\objs\strgen\ $(SolutionDir)..\objs\strgen\ false - AllRules.ruleset - - + NativeMinimumRules.ruleset + + diff --git a/source.list b/source.list index 7bad659d44..25bf521f25 100644 --- a/source.list +++ b/source.list @@ -110,8 +110,8 @@ townname.cpp vehicle.cpp vehiclelist.cpp viewport.cpp -#if SSE -viewport_sprite_sorter_sse4.cpp +#if USE_SSE + viewport_sprite_sorter_sse4.cpp #end waypoint.cpp widget.cpp @@ -136,6 +136,7 @@ base_media_base.h base_media_func.h base_station_base.h bitstream.h +bitmap_type.h bmp.h bridge.h cargo_table_gui.h @@ -272,6 +273,7 @@ newgrf_industrytiles.h newgrf_object.h newgrf_properties.h newgrf_railtype.h +newgrf_roadtype.h newgrf_sound.h newgrf_spritegroup.h newgrf_station.h @@ -302,6 +304,7 @@ rail.h rail_gui.h rail_type.h rev.h +road.h road_cmd.h road_func.h road_gui.h @@ -313,6 +316,7 @@ safeguards.h screenshot.h sound/sdl_s.h video/sdl_v.h +video/sdl2_v.h settings_func.h settings_gui.h settings_internal.h @@ -334,6 +338,7 @@ spritecache.h station_base.h station_func.h station_gui.h +station_kdtree.h station_type.h statusbar_gui.h stdafx.h @@ -368,6 +373,7 @@ timetable.h toolbar_gui.h town.h town_type.h +town_kdtree.h townname_func.h townname_type.h track_func.h @@ -384,6 +390,7 @@ vehicle_gui_base.h vehicle_type.h vehiclelist.h viewport_func.h +viewport_kdtree.h viewport_sprite_sorter.h viewport_type.h watch_gui.h @@ -404,20 +411,19 @@ 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 + music/bemidi.h + music/cocoa_m.h + music/extmidi.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 @@ -433,6 +439,7 @@ core/enum_type.hpp core/geometry_func.cpp core/geometry_func.hpp core/geometry_type.hpp +core/kdtree.hpp core/math_func.cpp core/math_func.hpp core/mem_func.hpp @@ -447,7 +454,6 @@ 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 @@ -681,6 +687,7 @@ table/pricebase.h table/railtypes.h table/road_land.h table/roadveh_movement.h +table/roadtypes.h ../objs/settings/table/settings.h table/sprites.h table/station_land.h @@ -837,6 +844,7 @@ script/api/script_order.hpp script/api/script_rail.hpp script/api/script_railtypelist.hpp script/api/script_road.hpp +script/api/script_roadtypelist.hpp script/api/script_sign.hpp script/api/script_signlist.hpp script/api/script_station.hpp @@ -905,6 +913,7 @@ script/api/script_order.cpp script/api/script_rail.cpp script/api/script_railtypelist.cpp script/api/script_road.cpp +script/api/script_roadtypelist.cpp script/api/script_sign.cpp script/api/script_signlist.cpp script/api/script_station.cpp @@ -931,36 +940,36 @@ 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 + blitter/32bpp_anim.cpp + blitter/32bpp_anim.hpp + #if USE_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 USE_SSE + blitter/32bpp_sse_func.hpp + blitter/32bpp_sse_type.h + blitter/32bpp_sse2.cpp + blitter/32bpp_sse2.hpp + blitter/32bpp_sse4.cpp + blitter/32bpp_sse4.hpp + blitter/32bpp_ssse3.cpp + blitter/32bpp_ssse3.hpp + #end + blitter/8bpp_base.cpp + blitter/8bpp_base.hpp + blitter/8bpp_optimized.cpp + blitter/8bpp_optimized.hpp + blitter/8bpp_simple.cpp + blitter/8bpp_simple.hpp #end blitter/base.cpp blitter/base.hpp @@ -994,6 +1003,7 @@ newgrf_industries.cpp newgrf_industrytiles.cpp newgrf_object.cpp newgrf_railtype.cpp +newgrf_roadtype.cpp newgrf_sound.cpp newgrf_spritegroup.cpp newgrf_station.cpp @@ -1064,8 +1074,6 @@ 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 @@ -1103,67 +1111,66 @@ video/dedicated_v.cpp video/null_v.cpp #if DEDICATED #else -#if ALLEGRO - video/allegro_v.cpp -#end -#if SDL - video/sdl_v.cpp -#end -#if WIN32 - video/win32_v.cpp -#end + #if ALLEGRO + video/allegro_v.cpp + #end + #if SDL + video/sdl_v.cpp + #end + #if SDL2 + video/sdl2_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 + #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 + #if WIN32 + music/win32_m.cpp #else - #if MORPHOS - #else - music/extmidi.cpp - #end + music/extmidi.cpp + #end + #if HAIKU + music/bemidi.cpp + #end + #if FLUIDSYNTH + music/fluidsynth.cpp #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 + #if ALLEGRO + sound/allegro_s.cpp + #end + #if SDL + sound/sdl_s.cpp + #end + #if SDL2 + sound/sdl2_s.cpp + #end + #if WIN32 + sound/win32_s.cpp + #if USE_XAUDIO2 + sound/xaudio2_s.cpp + #end + #end #end #if OSX @@ -1197,21 +1204,4 @@ sound/null_s.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 +thread.h diff --git a/src/3rdparty/squirrel/squirrel/sqcompiler.cpp b/src/3rdparty/squirrel/squirrel/sqcompiler.cpp index ace9d201e9..854d080d2b 100644 --- a/src/3rdparty/squirrel/squirrel/sqcompiler.cpp +++ b/src/3rdparty/squirrel/squirrel/sqcompiler.cpp @@ -142,7 +142,7 @@ public: break; } Lex(); - return ret; + return std::move(ret); } bool IsEndOfStatement() { return ((_lex._prevtoken == '\n') || (_token == SQUIRREL_EOB) || (_token == '}') || (_token == ';')); } void OptionalSemicolon() diff --git a/src/3rdparty/squirrel/squirrel/sqfuncproto.h b/src/3rdparty/squirrel/squirrel/sqfuncproto.h index e58ccd2994..2966d06544 100644 --- a/src/3rdparty/squirrel/squirrel/sqfuncproto.h +++ b/src/3rdparty/squirrel/squirrel/sqfuncproto.h @@ -20,12 +20,6 @@ struct SQOuterVar _src=src; _type=t; } - SQOuterVar(const SQOuterVar &ov) - { - _type=ov._type; - _src=ov._src; - _name=ov._name; - } SQOuterType _type; SQObjectPtr _name; SQObjectPtr _src; @@ -34,13 +28,6 @@ struct SQOuterVar 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; diff --git a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp index 5415b566e8..c8548bac36 100644 --- a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp +++ b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp @@ -502,14 +502,14 @@ SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) { SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); _table(_strings)->NewSlot(ns,(SQInteger)1); - return ns; + return std::move(ns); } SQObject SQFuncState::CreateTable() { SQObjectPtr nt(SQTable::Create(_sharedstate,0)); _table(_strings)->NewSlot(nt,(SQInteger)1); - return nt; + return std::move(nt); } SQFunctionProto *SQFuncState::BuildProto() diff --git a/src/3rdparty/squirrel/squirrel/sqmem.cpp b/src/3rdparty/squirrel/squirrel/sqmem.cpp index 5c1b3966aa..f4fa6309ed 100644 --- a/src/3rdparty/squirrel/squirrel/sqmem.cpp +++ b/src/3rdparty/squirrel/squirrel/sqmem.cpp @@ -9,8 +9,10 @@ #include "../../../core/alloc_func.hpp" #include "../../../safeguards.h" -void *sq_vm_malloc(SQUnsignedInteger size){ return MallocT((size_t)size); } +#ifdef SQUIRREL_DEFAULT_ALLOCATOR +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_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); } +void sq_vm_free(void *p, SQUnsignedInteger size) { free(p); } +#endif diff --git a/src/3rdparty/squirrel/squirrel/sqvm.h b/src/3rdparty/squirrel/squirrel/sqvm.h index 89a592e136..97557b1332 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.h +++ b/src/3rdparty/squirrel/squirrel/sqvm.h @@ -12,9 +12,8 @@ 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; } + SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target) + : _stackbase(stackbase), _stacksize(ss), _ip(ip), _extarget(ex_target) {} SQInteger _stackbase; SQInteger _stacksize; SQInstruction *_ip; diff --git a/src/ai/ai.hpp b/src/ai/ai.hpp index 065367d03b..bd9544b9f3 100644 --- a/src/ai/ai.hpp +++ b/src/ai/ai.hpp @@ -32,7 +32,7 @@ public: 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_MIN = 0, START_NEXT_MAX = 3600, START_NEXT_DEVIATION = 60, }; @@ -164,11 +164,9 @@ public: /** 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 diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp index ea26f32679..93db571586 100644 --- a/src/ai/ai_config.cpp +++ b/src/ai/ai_config.cpp @@ -31,7 +31,7 @@ ScriptConfigItem _start_date_config = { AI::START_NEXT_DEVIATION, 30, SCRIPTCONFIG_NONE, - NULL, + nullptr, false }; @@ -52,7 +52,7 @@ AIConfig::AIConfig(const AIConfig *config) : ScriptConfig(config) } else { config = &_settings_game.ai_config[company]; } - if (*config == NULL) *config = new AIConfig(); + if (*config == nullptr) *config = new AIConfig(); return *config; } @@ -69,7 +69,7 @@ ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_m 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; + return this->info != nullptr; } void AIConfig::PushExtraConfigList() @@ -90,7 +90,7 @@ void AIConfig::ClearConfigList() int AIConfig::GetSetting(const char *name) const { - if (this->info == NULL) { + if (this->info == nullptr) { SettingValueList::const_iterator it = this->settings.find(name); if (it == this->settings.end()) { assert(strcmp("start_date", name) == 0); @@ -111,7 +111,7 @@ int AIConfig::GetSetting(const char *name) const void AIConfig::SetSetting(const char *name, int value) { - if (this->info == NULL) { + if (this->info == nullptr) { if (strcmp("start_date", name) != 0) return; value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX); @@ -127,3 +127,14 @@ void AIConfig::SetSetting(const char *name, int value) ScriptConfig::SetSetting(name, value); } + +void AIConfig::AddRandomDeviation() +{ + int start_date = this->GetSetting("start_date"); + + ScriptConfig::AddRandomDeviation(); + + /* start_date = 0 is a special case, where random deviation does not occur. + * If start_date was not already 0, then a minimum value of 1 must apply. */ + this->SetSetting("start_date", start_date != 0 ? max(1, this->GetSetting("start_date")) : 0); +} diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp index 12cc02a497..9f667a6127 100644 --- a/src/ai/ai_config.hpp +++ b/src/ai/ai_config.hpp @@ -30,8 +30,9 @@ public: class AIInfo *GetInfo() const; - /* virtual */ int GetSetting(const char *name) const; - /* virtual */ void SetSetting(const char *name, int value); + int GetSetting(const char *name) const override; + void SetSetting(const char *name, int value) override; + void AddRandomDeviation() override; /** * When ever the AI Scanner is reloaded, all infos become invalid. This @@ -44,9 +45,9 @@ public: 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); + void PushExtraConfigList() override; + void ClearConfigList() override; + ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override; }; #endif /* AI_CONFIG_HPP */ diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index 51522edaff..23ee16c83f 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -26,8 +26,8 @@ #include "../safeguards.h" /* static */ uint AI::frame_counter = 0; -/* static */ AIScannerInfo *AI::scanner_info = NULL; -/* static */ AIScannerLibrary *AI::scanner_library = NULL; +/* static */ AIScannerInfo *AI::scanner_info = nullptr; +/* static */ AIScannerLibrary *AI::scanner_library = nullptr; /* static */ bool AI::CanStartNew() { @@ -44,19 +44,19 @@ AIConfig *config = AIConfig::GetConfig(company, AIConfig::SSS_FORCE_GAME); AIInfo *info = config->GetInfo(); - if (info == NULL || (rerandomise_ai && config->IsRandom())) { + if (info == nullptr || (rerandomise_ai && config->IsRandom())) { info = AI::scanner_info->SelectRandomAI(); - assert(info != NULL); + assert(info != nullptr); /* 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); + Backup cur_company(_current_company, company, FILE_LINE); Company *c = Company::Get(company); c->ai_info = info; - assert(c->ai_instance == NULL); + assert(c->ai_instance == nullptr); c->ai_instance = new AIInstance(); c->ai_instance->Initialize(info); @@ -76,7 +76,7 @@ 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); + Backup cur_company(_current_company, FILE_LINE); const Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai) { @@ -107,12 +107,12 @@ if (_networking && !_network_server) return; PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + company)); - Backup cur_company(_current_company, company, FILE_LINE); + 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; + c->ai_instance = nullptr; + c->ai_info = nullptr; cur_company.Restore(); @@ -127,7 +127,7 @@ * for the server owner to unpause the script again. */ if (_network_dedicated) return; - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); Company::Get(company)->ai_instance->Pause(); cur_company.Restore(); @@ -135,7 +135,7 @@ /* static */ void AI::Unpause(CompanyID company) { - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); Company::Get(company)->ai_instance->Unpause(); cur_company.Restore(); @@ -143,7 +143,7 @@ /* static */ bool AI::IsPaused(CompanyID company) { - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); bool paused = Company::Get(company)->ai_instance->IsPaused(); cur_company.Restore(); @@ -164,10 +164,10 @@ /* static */ void AI::Initialize() { - if (AI::scanner_info != NULL) AI::Uninitialize(true); + if (AI::scanner_info != nullptr) AI::Uninitialize(true); AI::frame_counter = 0; - if (AI::scanner_info == NULL) { + if (AI::scanner_info == nullptr) { TarScanner::DoScan(TarScanner::AI); AI::scanner_info = new AIScannerInfo(); AI::scanner_info->Initialize(); @@ -187,17 +187,17 @@ } else { delete AI::scanner_info; delete AI::scanner_library; - AI::scanner_info = NULL; - AI::scanner_library = NULL; + AI::scanner_info = nullptr; + AI::scanner_library = nullptr; for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - if (_settings_game.ai_config[c] != NULL) { + if (_settings_game.ai_config[c] != nullptr) { delete _settings_game.ai_config[c]; - _settings_game.ai_config[c] = NULL; + _settings_game.ai_config[c] = nullptr; } - if (_settings_newgame.ai_config[c] != NULL) { + if (_settings_newgame.ai_config[c] != nullptr) { delete _settings_newgame.ai_config[c]; - _settings_newgame.ai_config[c] = NULL; + _settings_newgame.ai_config[c] = nullptr; } } } @@ -209,10 +209,10 @@ * 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] != nullptr && _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); + _settings_game.ai_config[c]->Change(nullptr); 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 @@ -226,10 +226,10 @@ 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] != nullptr && _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); + _settings_newgame.ai_config[c]->Change(nullptr); } } } @@ -253,7 +253,7 @@ } /* Queue the event */ - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); Company::Get(_current_company)->ai_instance->InsertEvent(event); cur_company.Restore(); @@ -283,9 +283,9 @@ { if (!_networking || _network_server) { Company *c = Company::GetIfValid(company); - assert(c != NULL && c->ai_instance != NULL); + assert(c != nullptr && c->ai_instance != nullptr); - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); c->ai_instance->Save(); cur_company.Restore(); } else { @@ -297,9 +297,9 @@ { if (!_networking || _network_server) { Company *c = Company::GetIfValid(company); - assert(c != NULL && c->ai_instance != NULL); + assert(c != nullptr && c->ai_instance != nullptr); - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); c->ai_instance->Load(version); cur_company.Restore(); } else { @@ -362,8 +362,6 @@ 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) @@ -380,8 +378,6 @@ return AI::scanner_library->HasScript(ci, md5sum); } -#endif /* defined(ENABLE_NETWORK) */ - /* static */ AIScannerInfo *AI::GetScannerInfo() { return AI::scanner_info; diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index bc79d943bc..91f8969046 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -98,7 +98,7 @@ struct AIListWindow : public Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_AIL_CAPTION: @@ -107,7 +107,7 @@ struct AIListWindow : public Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_AIL_LIST) { this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; @@ -118,7 +118,7 @@ struct AIListWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_AIL_LIST: { @@ -139,13 +139,13 @@ struct AIListWindow : public Window { break; } case WID_AIL_INFO_BG: { - AIInfo *selected_info = NULL; + AIInfo *selected_info = nullptr; ScriptInfoList::const_iterator it = this->info_list->begin(); - for (int i = 1; selected_info == NULL && it != this->info_list->end(); i++, it++) { + for (int i = 1; selected_info == nullptr && 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) { + if (selected_info != nullptr) { 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); @@ -153,7 +153,7 @@ struct AIListWindow : public Window { 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) { + if (selected_info->GetURL() != nullptr) { 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; @@ -172,7 +172,7 @@ struct AIListWindow : public Window { void ChangeAI() { if (this->selected == -1) { - GetConfig(slot)->Change(NULL); + GetConfig(slot)->Change(nullptr); } else { ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 0; i < this->selected; i++) it++; @@ -183,7 +183,7 @@ struct AIListWindow : public Window { DeleteWindowByClass(WC_QUERY_STRING); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_AIL_LIST: { // Select one of the AIs @@ -211,7 +211,7 @@ struct AIListWindow : public Window { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_AIL_LIST); } @@ -221,7 +221,7 @@ struct AIListWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) { delete this; @@ -317,7 +317,7 @@ struct AISettingsWindow : public Window { this->RebuildVisibleSettings(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_AIS_CAPTION: @@ -346,7 +346,7 @@ struct AISettingsWindow : public Window { this->vscroll->SetCount((int)this->visible_settings.size()); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_AIS_BACKGROUND) { this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; @@ -357,7 +357,7 @@ struct AISettingsWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_AIS_BACKGROUND) return; @@ -407,7 +407,7 @@ struct AISettingsWindow : public Window { } 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)) { + if (config_item.labels != nullptr && config_item.labels->Contains(current_value)) { SetDParam(idx++, STR_JUST_RAW_STRING); SetDParamStr(idx++, config_item.labels->Find(current_value)->second); } else { @@ -421,7 +421,7 @@ struct AISettingsWindow : public Window { } } - virtual void OnPaint() + void OnPaint() override { if (this->closing_dropdown) { this->closing_dropdown = false; @@ -430,7 +430,7 @@ struct AISettingsWindow : public Window { this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_AIS_BACKGROUND: { @@ -479,12 +479,12 @@ struct AISettingsWindow : public Window { this->clicked_dropdown = true; this->closing_dropdown = false; - DropDownList *list = new DropDownList(); + DropDownList list; 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); + list.emplace_back(new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false)); } - ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true); + ShowDropDownListAt(this, std::move(list), old_val, -1, wi_rect, COLOUR_ORANGE, true); } } } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { @@ -530,7 +530,7 @@ struct AISettingsWindow : public Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (StrEmpty(str)) return; VisibleSettingsList::const_iterator it = this->visible_settings.begin(); @@ -542,7 +542,7 @@ struct AISettingsWindow : public Window { this->SetDirty(); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { assert(this->clicked_dropdown); VisibleSettingsList::const_iterator it = this->visible_settings.begin(); @@ -553,7 +553,7 @@ struct AISettingsWindow : public Window { this->SetDirty(); } - virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) + void OnDropdownClose(Point pt, int widget, int index, bool instant_close) override { /* 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. @@ -564,12 +564,12 @@ struct AISettingsWindow : public Window { this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_AIS_BACKGROUND); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (this->timeout.Elapsed(delta_ms)) { this->clicked_button = -1; @@ -582,7 +582,7 @@ struct AISettingsWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { this->RebuildVisibleSettings(); HideDropDownMenu(this); @@ -646,7 +646,7 @@ struct ScriptTextfileWindow : public TextfileWindow { this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR); } - /* virtual */ void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_TF_CAPTION) { SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI); @@ -743,7 +743,7 @@ struct AIConfigWindow : public Window { DeleteWindowByClass(WC_AI_SETTINGS); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_AIC_NUMBER: @@ -767,7 +767,7 @@ struct AIConfigWindow : public Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_AIC_GAMELIST: @@ -805,12 +805,12 @@ struct AIConfigWindow : public Window { */ static bool IsEditable(CompanyID slot) { - if (slot == OWNER_DEITY) return _game_mode != GM_NORMAL || Game::GetInstance() != NULL; + if (slot == OWNER_DEITY) return _game_mode != GM_NORMAL || Game::GetInstance() != nullptr; if (_game_mode != GM_NORMAL) { return slot > 0 && slot <= GetGameSettings().difficulty.max_no_competitors; } - if (Company::IsValidID(slot) || slot < 0) return false; + if (Company::IsValidID(slot)) return false; int max_slot = GetGameSettings().difficulty.max_no_competitors; for (CompanyID cid = COMPANY_FIRST; cid < (CompanyID)max_slot && cid < MAX_COMPANIES; cid++) { @@ -819,13 +819,13 @@ struct AIConfigWindow : public Window { return slot < max_slot; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_AIC_GAMELIST: { StringID text = STR_AI_CONFIG_NONE; - if (GameConfig::GetConfig()->GetInfo() != NULL) { + if (GameConfig::GetConfig()->GetInfo() != nullptr) { SetDParamStr(0, GameConfig::GetConfig()->GetInfo()->GetName()); text = STR_JUST_RAW_STRING; } @@ -843,7 +843,7 @@ struct AIConfigWindow : public Window { 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) { + } else if (AIConfig::GetConfig((CompanyID)i)->GetInfo() != nullptr) { SetDParamStr(0, AIConfig::GetConfig((CompanyID)i)->GetInfo()->GetName()); text = STR_JUST_RAW_STRING; } else { @@ -858,10 +858,10 @@ struct AIConfigWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) { - if (this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot) == NULL) return; + if (this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot) == nullptr) return; ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot); return; @@ -928,9 +928,7 @@ struct AIConfigWindow : public Window { 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 + ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_AI, CONTENT_TYPE_GAME); } break; } @@ -941,7 +939,7 @@ struct AIConfigWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!IsEditable(this->selected_slot)) { this->selected_slot = INVALID_COMPANY; @@ -957,7 +955,7 @@ struct AIConfigWindow : public Window { 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)); + this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || (GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot) == nullptr)); } } }; @@ -1026,7 +1024,7 @@ struct AIDebugWindow : public Window { { if (ai_debug_company == OWNER_DEITY) { GameInstance *game = Game::GetInstance(); - return game == NULL || game->IsDead(); + return game == nullptr || game->IsDead(); } return !Company::IsValidAiID(ai_debug_company) || Company::Get(ai_debug_company)->ai_instance->IsDead(); } @@ -1040,7 +1038,7 @@ struct AIDebugWindow : public Window { { switch (company) { case INVALID_COMPANY: return false; - case OWNER_DEITY: return Game::GetInstance() != NULL; + case OWNER_DEITY: return Game::GetInstance() != nullptr; default: return Company::IsValidAiID(company); } } @@ -1065,7 +1063,7 @@ struct AIDebugWindow : public Window { } /* If no AI is available, see if there is a game script. */ - if (Game::GetInstance() != NULL) ChangeToAI(OWNER_DEITY); + if (Game::GetInstance() != nullptr) ChangeToAI(OWNER_DEITY); } /** @@ -1098,7 +1096,7 @@ struct AIDebugWindow : public Window { this->InvalidateData(-1); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_AID_LOG_PANEL) { resize->height = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; @@ -1106,7 +1104,7 @@ struct AIDebugWindow : public Window { } } - virtual void OnPaint() + void OnPaint() override { this->SelectValidDebugCompany(); @@ -1142,7 +1140,7 @@ struct AIDebugWindow : public Window { /* Set button colour for Game Script. */ GameInstance *game = Game::GetInstance(); - bool valid = game != NULL; + bool valid = game != nullptr; bool dead = valid && game->IsDead(); bool paused = valid && game->IsPaused(); @@ -1156,7 +1154,7 @@ struct AIDebugWindow : public Window { ScriptLog::LogData *log = this->GetLogPointer(); - int scroll_count = (log == NULL) ? 0 : log->used; + int scroll_count = (log == nullptr) ? 0 : log->used; if (this->vscroll->GetCount() != scroll_count) { this->vscroll->SetCount(scroll_count); @@ -1164,7 +1162,7 @@ struct AIDebugWindow : public Window { this->SetWidgetDirty(WID_AID_SCROLLBAR); } - if (log == NULL) return; + if (log == nullptr) return; /* Detect when the user scrolls the window. Enable autoscroll when the * bottom-most line becomes visible. */ @@ -1184,13 +1182,13 @@ struct AIDebugWindow : public Window { this->last_vscroll_pos = this->vscroll->GetPosition(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_AID_NAME_TEXT: if (ai_debug_company == OWNER_DEITY) { const GameInfo *info = Game::GetInfo(); - assert(info != NULL); + assert(info != nullptr); SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION); SetDParamStr(1, info->GetName()); SetDParam(2, info->GetVersion()); @@ -1198,7 +1196,7 @@ struct AIDebugWindow : public Window { SetDParam(0, STR_EMPTY); } else { const AIInfo *info = Company::Get(ai_debug_company)->ai_info; - assert(info != NULL); + assert(info != nullptr); SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION); SetDParamStr(1, info->GetName()); SetDParam(2, info->GetVersion()); @@ -1207,19 +1205,19 @@ struct AIDebugWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (ai_debug_company == INVALID_COMPANY) return; switch (widget) { case WID_AID_LOG_PANEL: { ScriptLog::LogData *log = this->GetLogPointer(); - if (log == NULL) return; + if (log == nullptr) 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; + if (log->lines[pos] == nullptr) break; TextColour colour; switch (log->type[pos]) { @@ -1266,7 +1264,7 @@ struct AIDebugWindow : public Window { this->last_vscroll_pos = this->vscroll->GetPosition(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { /* Also called for hotkeys, so check for disabledness */ if (this->IsWidgetDisabled(widget)) return; @@ -1336,7 +1334,7 @@ struct AIDebugWindow : public Window { } } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { 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. */ @@ -1351,7 +1349,7 @@ struct AIDebugWindow : public Window { * 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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { /* 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. */ @@ -1359,7 +1357,7 @@ struct AIDebugWindow : public Window { /* Get the log instance of the active company */ ScriptLog::LogData *log = this->GetLogPointer(); - if (log != NULL) { + if (log != nullptr) { this->break_string_filter.ResetState(); this->break_string_filter.AddLine(log->lines[log->pos]); if (this->break_string_filter.GetState()) { @@ -1387,8 +1385,8 @@ struct AIDebugWindow : public Window { this->SelectValidDebugCompany(); - ScriptLog::LogData *log = ai_debug_company != INVALID_COMPANY ? this->GetLogPointer() : NULL; - this->vscroll->SetCount((log == NULL) ? 0 : log->used); + ScriptLog::LogData *log = ai_debug_company != INVALID_COMPANY ? this->GetLogPointer() : nullptr; + this->vscroll->SetCount((log == nullptr) ? 0 : log->used); /* Update company buttons */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { @@ -1396,7 +1394,7 @@ struct AIDebugWindow : public Window { this->SetWidgetLoweredState(i + WID_AID_COMPANY_BUTTON_START, ai_debug_company == i); } - this->SetWidgetDisabledState(WID_AID_SCRIPT_GAME, Game::GetGameInstance() == NULL); + this->SetWidgetDisabledState(WID_AID_SCRIPT_GAME, Game::GetGameInstance() == nullptr); this->SetWidgetLoweredState(WID_AID_SCRIPT_GAME, ai_debug_company == OWNER_DEITY); this->SetWidgetLoweredState(WID_AID_BREAK_STR_ON_OFF_BTN, this->break_check_enabled); @@ -1408,7 +1406,7 @@ struct AIDebugWindow : public Window { (ai_debug_company == OWNER_DEITY ? !Game::IsPaused() : !AI::IsPaused(ai_debug_company))); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_AID_LOG_PANEL); } @@ -1439,7 +1437,7 @@ 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; + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -1532,14 +1530,14 @@ 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 (w == nullptr) 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; + return nullptr; } /** @@ -1565,7 +1563,7 @@ void ShowAIDebugWindowIfAIError() } GameInstance *g = Game::GetGameInstance(); - if (g != NULL && g->IsDead()) { + if (g != nullptr && g->IsDead()) { ShowAIDebugWindow(OWNER_DEITY); } } diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp index 43a4345460..af7ae57299 100644 --- a/src/ai/ai_info.cpp +++ b/src/ai/ai_info.cpp @@ -29,7 +29,7 @@ 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; + strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0; } #if defined(_WIN32) @@ -65,8 +65,8 @@ template <> const char *GetClassName() { return "AIInfo"; } /* 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"); + SQUserPointer instance = nullptr; + if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == nullptr) 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); @@ -100,7 +100,7 @@ template <> const char *GetClassName() { return "AIInfo"; } } /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ - sq_setinstanceup(vm, 2, NULL); + sq_setinstanceup(vm, 2, nullptr); /* Register the AI to the base system */ info->GetScanner()->RegisterScript(info); return 0; @@ -112,7 +112,7 @@ template <> const char *GetClassName() { return "AIInfo"; } SQUserPointer instance; sq_getinstanceup(vm, 2, &instance, 0); AIInfo *info = (AIInfo *)instance; - info->api_version = NULL; + info->api_version = nullptr; SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; @@ -122,7 +122,7 @@ template <> const char *GetClassName() { return "AIInfo"; } info->api_version = stredup(buf); /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ - sq_setinstanceup(vm, 2, NULL); + sq_setinstanceup(vm, 2, nullptr); /* Register the AI to the base system */ static_cast(info->GetScanner())->SetDummyAI(info); return 0; @@ -131,7 +131,7 @@ template <> const char *GetClassName() { return "AIInfo"; } AIInfo::AIInfo() : min_loadable_version(0), use_as_random(false), - api_version(NULL) + api_version(nullptr) { } diff --git a/src/ai/ai_info.hpp b/src/ai/ai_info.hpp index 51cfb7d8a0..ddf1edc6cd 100644 --- a/src/ai/ai_info.hpp +++ b/src/ai/ai_info.hpp @@ -59,7 +59,7 @@ private: /** All static information from an AI library like name, version, etc. */ class AILibrary : public ScriptInfo { public: - AILibrary() : ScriptInfo(), category(NULL) {}; + AILibrary() : ScriptInfo(), category(nullptr) {}; ~AILibrary(); /** diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 76e8efd27c..44e84325b7 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -62,6 +62,7 @@ #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_roadtypelist.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" @@ -145,6 +146,7 @@ void AIInstance::RegisterAPI() SQAIEventSubsidyOffer_Register(this->engine); SQAIEventSubsidyOfferExpired_Register(this->engine); SQAIEventTownFounded_Register(this->engine); + SQAIEventVehicleAutoReplaced_Register(this->engine); SQAIEventVehicleCrashed_Register(this->engine); SQAIEventVehicleLost_Register(this->engine); SQAIEventVehicleUnprofitable_Register(this->engine); @@ -167,6 +169,7 @@ void AIInstance::RegisterAPI() SQAIRail_Register(this->engine); SQAIRailTypeList_Register(this->engine); SQAIRoad_Register(this->engine); + SQAIRoadTypeList_Register(this->engine); SQAISign_Register(this->engine); SQAISignList_Register(this->engine); SQAIStation_Register(this->engine); @@ -216,10 +219,10 @@ void AIInstance::Died() ShowAIDebugWindow(_current_company); const AIInfo *info = AIConfig::GetConfig(_current_company, AIConfig::SSS_FORCE_GAME)->GetInfo(); - if (info != NULL) { + if (info != nullptr) { ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); - if (info->GetURL() != NULL) { + if (info->GetURL() != nullptr) { ScriptLog::Info("Please report the error to the following URL:"); ScriptLog::Info(info->GetURL()); } @@ -228,6 +231,7 @@ void AIInstance::Died() void AIInstance::LoadDummyScript() { + ScriptAllocatorScope alloc_scope(this->engine); extern void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type); Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI"); } @@ -259,7 +263,7 @@ void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint3 * when the company does not exist anymore. */ const Company *c = Company::GetIfValid(_current_company); - if (c == NULL || c->ai_instance == NULL) return; + if (c == nullptr || c->ai_instance == nullptr) return; if (c->ai_instance->DoCommandCallback(result, tile, p1, p2, cmd)) { c->ai_instance->Continue(); diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp index 204bf9712a..06998558b3 100644 --- a/src/ai/ai_instance.hpp +++ b/src/ai/ai_instance.hpp @@ -25,14 +25,14 @@ public: */ void Initialize(class AIInfo *info); - /* virtual */ int GetSetting(const char *name); - /* virtual */ ScriptInfo *FindLibrary(const char *library, int version); + int GetSetting(const char *name) override; + ScriptInfo *FindLibrary(const char *library, int version) override; private: - /* virtual */ void RegisterAPI(); - /* virtual */ void Died(); - /* virtual */ CommandCallback *GetDoCommandCallback(); - /* virtual */ void LoadDummyScript(); + void RegisterAPI() override; + void Died() override; + CommandCallback *GetDoCommandCallback() override; + void LoadDummyScript() override; }; #endif /* AI_INSTANCE_HPP */ diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp index 5f16de3f91..8bd3a43853 100644 --- a/src/ai/ai_scanner.cpp +++ b/src/ai/ai_scanner.cpp @@ -23,7 +23,7 @@ AIScannerInfo::AIScannerInfo() : ScriptScanner(), - info_dummy(NULL) + info_dummy(nullptr) { } @@ -31,6 +31,8 @@ void AIScannerInfo::Initialize() { ScriptScanner::Initialize("AIScanner"); + ScriptAllocatorScope alloc_scope(this->engine); + /* Create the dummy AI */ free(this->main_script); this->main_script = stredup("%_dummy"); @@ -94,14 +96,14 @@ AIInfo *AIScannerInfo::SelectRandomAI() const 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; + if (this->info_list.size() == 0) return nullptr; + if (nameParam == nullptr) return nullptr; char ai_name[1024]; strecpy(ai_name, nameParam, lastof(ai_name)); strtolower(ai_name); - AIInfo *info = NULL; + AIInfo *info = nullptr; int version = -1; if (versionParam == -1) { @@ -110,7 +112,7 @@ AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool fo /* If we didn't find a match AI, maybe the user included a version */ char *e = strrchr(ai_name, '.'); - if (e == NULL) return NULL; + if (e == nullptr) return nullptr; *e = '\0'; e++; versionParam = atoi(e); @@ -165,7 +167,7 @@ AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version) /* Check if the library + version exists */ ScriptInfoList::iterator iter = this->info_list.find(library_name); - if (iter == this->info_list.end()) return NULL; + if (iter == this->info_list.end()) return nullptr; return static_cast((*iter).second); } diff --git a/src/ai/ai_scanner.hpp b/src/ai/ai_scanner.hpp index d8e8a6993d..2e0532d00d 100644 --- a/src/ai/ai_scanner.hpp +++ b/src/ai/ai_scanner.hpp @@ -19,7 +19,7 @@ public: AIScannerInfo(); ~AIScannerInfo(); - /* virtual */ void Initialize(); + void Initialize() override; /** * Select a random AI. @@ -32,7 +32,7 @@ public: * @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. + * @return nullptr if no match found, otherwise the AI that matched. */ class AIInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match); @@ -42,11 +42,11 @@ public: 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); + void GetScriptName(ScriptInfo *info, char *name, const char *last) override; + const char *GetFileName() const override { return PATHSEP "info.nut"; } + Subdirectory GetDirectory() const override { return AI_DIR; } + const char *GetScannerName() const override { return "AIs"; } + void RegisterAPI(class Squirrel *engine) override; private: AIInfo *info_dummy; ///< The dummy AI. @@ -54,22 +54,22 @@ private: class AIScannerLibrary : public ScriptScanner { public: - /* virtual */ void Initialize(); + void Initialize() override; /** * 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. + * @return The library if found, nullptr 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); + void GetScriptName(ScriptInfo *info, char *name, const char *last) override; + const char *GetFileName() const override { return PATHSEP "library.nut"; } + Subdirectory GetDirectory() const override { return AI_LIBRARY_DIR; } + const char *GetScannerName() const override { return "AI Libraries"; } + void RegisterAPI(class Squirrel *engine) override; }; #endif /* AI_SCANNER_HPP */ diff --git a/src/aircraft.h b/src/aircraft.h index f4fce09be1..3abb86b4f0 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -79,7 +79,7 @@ struct Aircraft FINAL : public SpecializedVehicle { 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; + Direction 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 diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index ff97be524f..e885fb29f5 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -143,7 +143,7 @@ static StationID FindNearestHangar(const Aircraft *v) 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 (cur_dest != nullptr && DistanceSquare(st->airport.tile, cur_dest->airport.tile) > v->acache.cached_max_range_sqr) continue; } if (distance < best || index == INVALID_STATION) { best = distance; @@ -295,7 +295,7 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine * v->cargo_type = e->GetDefaultCargoType(); u->cargo_type = CT_MAIL; - v->name = NULL; + v->name = nullptr; v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; @@ -379,7 +379,7 @@ bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, { 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()) { + if (st == nullptr || !CanVehicleUseStation(this, st) || !st->airport.HasHangar()) { /* the aircraft has to search for a hangar on its own */ StationID station = FindNearestHangar(this); @@ -388,8 +388,8 @@ bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, st = Station::Get(station); } - if (location != NULL) *location = st->xy; - if (destination != NULL) *destination = st->index; + if (location != nullptr) *location = st->xy; + if (destination != nullptr) *destination = st->index; return true; } @@ -408,7 +408,7 @@ static void CheckIfAircraftNeedsService(Aircraft *v) const Station *st = Station::Get(v->current_order.GetDestination()); - assert(st != NULL); + assert(st != nullptr); /* only goto depot if the target airport has a depot */ if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) { @@ -531,7 +531,7 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z) u->UpdatePositionAndViewport(); u = u->Next(); - if (u != NULL) { + if (u != nullptr) { u->x_pos = x; u->y_pos = y; u->z_pos = z + ROTOR_Z_OFFSET; @@ -552,7 +552,7 @@ void HandleAircraftEnterHangar(Aircraft *v) Aircraft *u = v->Next(); u->vehstatus |= VS_HIDDEN; u = u->Next(); - if (u != NULL) { + if (u != nullptr) { u->vehstatus |= VS_HIDDEN; u->cur_speed = 0; } @@ -725,8 +725,8 @@ void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_lev /* 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; + if (min_level != nullptr) *min_level = base_altitude + AIRCRAFT_MIN_FLYING_ALTITUDE; + if (max_level != nullptr) *max_level = base_altitude + AIRCRAFT_MAX_FLYING_ALTITUDE; } /** @@ -801,8 +801,8 @@ template int GetAircraftFlightLevel(Aircraft *v, bool takeoff); */ static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation) { - assert(v != NULL); - assert(apc != NULL); + assert(v != nullptr); + assert(apc != nullptr); /* 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 @@ -810,7 +810,7 @@ static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, TileIndex tile = 0; const Station *st = Station::GetIfValid(v->targetairport); - if (st != NULL) { + if (st != nullptr) { /* 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; } @@ -844,13 +844,13 @@ static bool AircraftController(Aircraft *v) { int count; - /* NULL if station is invalid */ + /* nullptr 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 != nullptr) { if (st->airport.tile != INVALID_TILE) { tile = st->airport.tile; rotation = st->airport.rotation; @@ -864,7 +864,7 @@ static bool AircraftController(Aircraft *v) 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) { + if (st == nullptr || 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); @@ -904,7 +904,7 @@ static bool AircraftController(Aircraft *v) v->tile = 0; int z_dest; - GetAircraftFlightLevelBounds(v, &z_dest, NULL); + GetAircraftFlightLevelBounds(v, &z_dest, nullptr); /* Reached altitude? */ if (v->z_pos >= z_dest) { @@ -921,7 +921,7 @@ static bool AircraftController(Aircraft *v) if (amd.flag & AMED_HELI_LOWER) { SetBit(v->flags, VAF_HELI_DIRECT_DESCENT); - if (st == NULL) { + if (st == nullptr) { /* 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 */ @@ -1127,7 +1127,7 @@ static bool HandleCrashedAircraft(Aircraft *v) Station *st = GetTargetAirportIfValid(v); /* make aircraft crash down to the ground */ - if (v->crashed_counter < 500 && st == NULL && ((v->crashed_counter % 3) == 0) ) { + if (v->crashed_counter < 500 && st == nullptr && ((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) { @@ -1158,7 +1158,7 @@ static bool HandleCrashedAircraft(Aircraft *v) /* 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) { + if (st != nullptr) { 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 @@ -1232,8 +1232,8 @@ void HandleMissingAircraftOrders(Aircraft *v) * actually stops. */ const Station *st = GetTargetAirportIfValid(v); - if (st == NULL) { - Backup cur_company(_current_company, v->owner, FILE_LINE); + if (st == nullptr) { + 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(); @@ -1288,17 +1288,17 @@ static void CrashAirplane(Aircraft *v) v->Next()->cargo.Truncate(); const Station *st = GetTargetAirportIfValid(v); StringID newsitem; - if (st == NULL) { + if (st == nullptr) { 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)); + AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING)); + Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING)); - AddVehicleNewsItem(newsitem, NT_ACCIDENT, v->index, st != NULL ? st->index : INVALID_STATION); + AddVehicleNewsItem(newsitem, NT_ACCIDENT, v->index, st != nullptr ? st->index : INVALID_STATION); ModifyStationRatingAround(v->tile, v->owner, -160, 30); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); @@ -1310,18 +1310,17 @@ static void CrashAirplane(Aircraft *v) */ 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); + uint32 prob; if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) && (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) { - prob /= 20; + prob = 3276; } else { - prob /= 1500; + if (_settings_game.vehicle.plane_crashes == 0) return; + prob = (0x4000 << _settings_game.vehicle.plane_crashes) / 1500; } if (GB(Random(), 0, 22) > prob) return; @@ -1393,8 +1392,8 @@ void AircraftNextAirportPos_and_Order(Aircraft *v) } 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; + const AirportFTAClass *apc = st == nullptr ? GetAirport(AT_DUMMY) : st->airport.GetFTA(); + Direction rotation = st == nullptr ? DIR_N : st->airport.rotation; v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc, rotation); } @@ -1419,7 +1418,7 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir) /* Rotor blades */ u = u->Next(); - if (u != NULL) { + if (u != nullptr) { u->vehstatus &= ~VS_HIDDEN; u->cur_speed = 80; } @@ -1589,7 +1588,7 @@ static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass /* Send the helicopter to a hangar if needed for replacement */ if (v->NeedsAutomaticServicing()) { - Backup cur_company(_current_company, v->owner, FILE_LINE); + 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(); } @@ -1606,7 +1605,7 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc) * 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) { + while (current != nullptr) { 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 @@ -1640,7 +1639,7 @@ static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc /* 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); + 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(); } @@ -1762,7 +1761,7 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc) v->previous_pos = v->pos; // save previous location /* there is only one choice to move to */ - if (current->next == NULL) { + if (current->next == nullptr) { if (AirportSetBlocks(v, current, apc)) { v->pos = current->next_position; UpdateAircraftCache(v); @@ -1781,7 +1780,7 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc) return false; } current = current->next; - } while (current != NULL); + } while (current != nullptr); DEBUG(misc, 0, "[Ap] cannot move further on Airport! (pos %d state %d) for vehicle %d", v->pos, v->state, v->index); NOT_REACHED(); @@ -1816,7 +1815,7 @@ static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const Ai * "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 + * @param apc airport on which block is requested 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) @@ -1831,7 +1830,7 @@ static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const A * this means more blocks should be checked/set */ const AirportFTA *current = current_pos; if (current == reference) current = current->next; - while (current != NULL) { + while (current != nullptr) { if (current->heading == current_pos->heading && current->block != 0) { airport_flags |= current->block; break; @@ -1926,8 +1925,8 @@ static uint GetNumTerminals(const AirportFTAClass *apc) 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: + * {0,HANGAR,NOTHING_block,1}, {0,TERMGROUP,TERM_GROUP1_block,0}, {0,TERMGROUP,TERM_GROUP2_ENTER_block,1}, {0,0,N,1}, + * Heading TERMGROUP 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 @@ -1939,8 +1938,8 @@ static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc) const Station *st = Station::Get(v->targetairport); const AirportFTA *temp = apc->layout[v->pos].next; - while (temp != NULL) { - if (temp->heading == 255) { + while (temp != nullptr) { + if (temp->heading == TERMGROUP) { if (!(st->airport.flags & temp->block)) { /* read which group do we want to go to? * (the first free group) */ @@ -2038,9 +2037,9 @@ static bool AircraftEventHandler(Aircraft *v, int loop) /* 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; + Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : nullptr; - if (cur_st != NULL && cur_st->airport.tile != INVALID_TILE && next_st != NULL && next_st->airport.tile != INVALID_TILE) { + if (cur_st != nullptr && cur_st->airport.tile != INVALID_TILE && next_st != nullptr && 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); } @@ -2078,16 +2077,16 @@ bool Aircraft::Tick() * 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 + * @return pointer to target station, nullptr if invalid */ Station *GetTargetAirportIfValid(const Aircraft *v) { assert(v->type == VEH_AIRCRAFT); Station *st = Station::GetIfValid(v->targetairport); - if (st == NULL) return NULL; + if (st == nullptr) return nullptr; - return st->airport.tile == INVALID_TILE ? NULL : st; + return st->airport.tile == INVALID_TILE ? nullptr : st; } /** diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp index 6693b1f8ad..76121a5dd9 100644 --- a/src/aircraft_gui.cpp +++ b/src/aircraft_gui.cpp @@ -36,7 +36,7 @@ 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()) { + for (const Aircraft *u = v; u != nullptr; u = u->Next()) { if (u->IsNormalAircraft()) { SetDParam(0, u->engine_type); SetDParam(1, u->build_year); diff --git a/src/airport.cpp b/src/airport.cpp index 7985e017aa..15e18035f0 100644 --- a/src/airport.cpp +++ b/src/airport.cpp @@ -46,7 +46,7 @@ * @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_GENERIC(name, nullptr, num_helipads, AirportFTAClass::HELICOPTERS, delta_z) AIRPORT(country, 0, true) AIRPORT(city, 0, false) @@ -58,7 +58,7 @@ HELIPORT(helidepot, 1, 0) AIRPORT(intercontinental, 2, false) HELIPORT(helistation, 3, 0) HELIPORT(oilrig, 1, 54) -AIRPORT_GENERIC(dummy, NULL, 0, AirportFTAClass::ALL, 0) +AIRPORT_GENERIC(dummy, nullptr, 0, AirportFTAClass::ALL, 0) #undef HELIPORT #undef AIRPORT @@ -135,7 +135,7 @@ AirportFTAClass::~AirportFTAClass() { for (uint i = 0; i < nofelements; i++) { AirportFTA *current = layout[i].next; - while (current != NULL) { + while (current != nullptr) { AirportFTA *next = current->next; free(current); current = next; @@ -195,7 +195,7 @@ static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildu current = current->next; internalcounter++; } - current->next = NULL; + current->next = nullptr; internalcounter++; } return FAutomata; diff --git a/src/airport.h b/src/airport.h index 31c68ef002..079268f665 100644 --- a/src/airport.h +++ b/src/airport.h @@ -60,29 +60,30 @@ enum AirportMovingDataFlags { /** 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. + 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. + TERMGROUP = 255, ///< Aircraft is looking for a free terminal in a terminalgroup. }; /** Movement Blocks on Airports blocks (eg_airport_flags). */ @@ -130,10 +131,10 @@ static const uint64 /** 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. + int16 x; ///< x-coordinate of the destination. + int16 y; ///< y-coordinate of the destination. + uint16 flag; ///< special flags when moving towards the destination. + Direction 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); diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 71b3b50133..ecf9147a99 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -79,6 +79,7 @@ struct BuildAirToolbarWindow : Window { ~BuildAirToolbarWindow() { + if (this->IsWidgetLowered(WID_AT_AIRPORT)) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -87,14 +88,14 @@ struct BuildAirToolbarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (!CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) delete this; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_AT_AIRPORT: @@ -114,7 +115,7 @@ struct BuildAirToolbarWindow : Window { } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { switch (this->last_user_action) { case WID_AT_AIRPORT: @@ -129,20 +130,22 @@ struct BuildAirToolbarWindow : Window { } } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) { GUIPlaceProcDragXY(select_proc, start_tile, end_tile); } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { + if (this->IsWidgetLowered(WID_AT_AIRPORT)) SetViewportCatchmentStation(nullptr, true); + this->RaiseButtons(); DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); @@ -161,7 +164,7 @@ 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; + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -198,11 +201,11 @@ static WindowDesc _air_toolbar_desc( * * 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. + * @return newly opened airport toolbar, or nullptr if the toolbar could not be opened. */ Window *ShowBuildAirToolbar() { - if (!Company::IsValidID(_local_company)) return NULL; + if (!Company::IsValidID(_local_company)) return nullptr; DeleteWindowByClass(WC_BUILD_TOOLBAR); return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); @@ -214,12 +217,12 @@ class BuildAirportWindow : public PickerWindowBase { Scrollbar *vscroll; /** Build a dropdown list of available airport classes */ - static DropDownList *BuildAirportClassDropDown() + static DropDownList BuildAirportClassDropDown() { - DropDownList *list = new DropDownList(); + DropDownList list; for (uint i = 0; i < AirportClass::GetClassCount(); i++) { - *list->Append() = new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false); + list.emplace_back(new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false)); } return list; @@ -268,7 +271,7 @@ public: DeleteWindowById(WC_SELECT_STATION, 0); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_AP_CLASS_DROPDOWN: @@ -293,7 +296,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_AP_CLASS_DROPDOWN: { @@ -357,7 +360,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_AP_AIRPORT_LIST: { @@ -394,7 +397,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { this->DrawWidgets(); @@ -462,7 +465,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_AP_CLASS_DROPDOWN: @@ -535,7 +538,7 @@ public: this->SelectOtherAirport(-1); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { assert(widget == WID_AP_CLASS_DROPDOWN); _selected_airport_class = (AirportClassID)index; @@ -543,7 +546,7 @@ public: this->SelectFirstAvailableAirport(false); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { CheckRedrawStationCoverage(this); } diff --git a/src/animated_tile.cpp b/src/animated_tile.cpp index 2a4cd89583..24543529df 100644 --- a/src/animated_tile.cpp +++ b/src/animated_tile.cpp @@ -19,7 +19,7 @@ #include "safeguards.h" /** The table/list with animated tiles. */ -SmallVector _animated_tiles; +std::vector _animated_tiles; /** * Removes the given tile from the animated tile table. @@ -27,10 +27,10 @@ SmallVector _animated_tiles; */ void DeleteAnimatedTile(TileIndex tile) { - TileIndex *to_remove = _animated_tiles.Find(tile); - if (to_remove != _animated_tiles.End()) { + auto to_remove = std::find(_animated_tiles.begin(), _animated_tiles.end(), 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); + _animated_tiles.erase(to_remove); MarkTileDirtyByTile(tile); } } @@ -43,7 +43,7 @@ void DeleteAnimatedTile(TileIndex tile) void AddAnimatedTile(TileIndex tile) { MarkTileDirtyByTile(tile); - _animated_tiles.Include(tile); + include(_animated_tiles, tile); } /** @@ -53,8 +53,8 @@ void AnimateAnimatedTiles() { PerformanceAccumulator framerate(PFE_GL_LANDSCAPE); - const TileIndex *ti = _animated_tiles.Begin(); - while (ti < _animated_tiles.End()) { + const TileIndex *ti = _animated_tiles.data(); + while (ti < _animated_tiles.data() + _animated_tiles.size()) { const TileIndex curr = *ti; AnimateTile(curr); /* During the AnimateTile call, DeleteAnimatedTile could have been called, @@ -75,5 +75,5 @@ void AnimateAnimatedTiles() */ void InitializeAnimatedTiles() { - _animated_tiles.Clear(); + _animated_tiles.clear(); } diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp index 44ad587895..e7956f5390 100644 --- a/src/articulated_vehicles.cpp +++ b/src/articulated_vehicles.cpp @@ -31,9 +31,9 @@ static const uint MAX_ARTICULATED_PARTS = 100; ///< Maximum of articulated parts * @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) +static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front = nullptr, bool *mirrored = nullptr) { - assert(front == NULL || front->engine_type == front_type); + assert(front == nullptr || front->engine_type == front_type); const Engine *front_engine = Engine::Get(front_type); @@ -44,12 +44,12 @@ static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle /* 8 bits, bit 7 for mirroring */ callback = GB(callback, 0, 8); if (callback == 0xFF) return INVALID_ENGINE; - if (mirrored != NULL) *mirrored = HasBit(callback, 7); + if (mirrored != nullptr) *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); + if (mirrored != nullptr) *mirrored = HasBit(callback, 14); callback = GB(callback, 0, 14); } @@ -80,7 +80,7 @@ uint CountArticulatedParts(EngineID engine_type, bool purchase_window) * either, so it doesn't matter how many articulated parts there are. */ if (!Vehicle::CanAllocateItem()) return 0; - Vehicle *v = NULL; + Vehicle *v = nullptr; if (!purchase_window) { v = new Vehicle(); v->engine_type = engine_type; @@ -108,7 +108,7 @@ static inline uint16 GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_t { const Engine *e = Engine::Get(engine); CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID); - if (cargo_type != NULL) *cargo_type = cargo; + if (cargo_type != nullptr) *cargo_type = cargo; if (cargo == CT_INVALID) return 0; return e->GetDisplayDefaultCapacity(); } @@ -168,16 +168,16 @@ CargoArray GetCapacityOfArticulatedParts(EngineID engine) * @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. + * @param cargo_type Selected refitted cargo type + * @param cargo_capacity Capacity of selected refitted cargo type */ -void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits) +void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint16 cargo_capacity) { 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); @@ -290,15 +290,15 @@ bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *car 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; + if (cargo_type != nullptr) *cargo_type = CT_INVALID; return true; } } - v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL; - } while (v != NULL); + v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr; + } while (v != nullptr); - if (cargo_type != NULL) *cargo_type = first_cargo; + if (cargo_type != nullptr) *cargo_type = first_cargo; return false; } @@ -330,8 +330,8 @@ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v) assert(v->cargo_type < NUM_CARGO); real_default_capacity[v->cargo_type] += v->cargo_cap; - v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL; - } while (v != NULL); + v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr; + } while (v != nullptr); /* Check whether the vehicle carries more cargoes than expected */ bool carries_more = false; diff --git a/src/autoreplace.cpp b/src/autoreplace.cpp index 3b7f739726..968bfe91cb 100644 --- a/src/autoreplace.cpp +++ b/src/autoreplace.cpp @@ -29,11 +29,11 @@ static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine, G { EngineRenew *er = (EngineRenew *)erl; - while (er != NULL) { + while (er != nullptr) { if (er->from == engine && GroupIsInGroup(group, er->group_id)) return er; er = er->next; } - return NULL; + return nullptr; } /** @@ -46,12 +46,12 @@ void RemoveAllEngineReplacement(EngineRenewList *erl) EngineRenew *er = (EngineRenew *)(*erl); EngineRenew *next; - while (er != NULL) { + while (er != nullptr) { next = er->next; delete er; er = next; } - *erl = NULL; // Empty list + *erl = nullptr; // Empty list } /** @@ -66,12 +66,12 @@ void RemoveAllEngineReplacement(EngineRenewList *erl) 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))) { + if (er == nullptr && (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; + if (replace_when_old != nullptr) *replace_when_old = er == nullptr ? false : er->replace_when_old; + return er == nullptr ? INVALID_ENGINE : er->to; } /** @@ -88,7 +88,7 @@ CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, Engi { /* Check if the old vehicle is already in the list */ EngineRenew *er = GetEngineReplacement(*erl, old_engine, group); - if (er != NULL) { + if (er != nullptr) { if (flags & DC_EXEC) { er->to = new_engine; er->replace_when_old = replace_when_old; @@ -122,12 +122,12 @@ CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, Engi CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, DoCommandFlag flags) { EngineRenew *er = (EngineRenew *)(*erl); - EngineRenew *prev = NULL; + EngineRenew *prev = nullptr; - while (er != NULL) { + while (er != nullptr) { if (er->from == engine && er->group_id == group) { if (flags & DC_EXEC) { - if (prev == NULL) { // First element + if (prev == nullptr) { // First element /* The second becomes the new first element */ *erl = (EngineRenewList)er->next; } else { diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 95568e3811..27149010be 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -20,6 +20,8 @@ #include "articulated_vehicles.h" #include "core/random_func.hpp" #include "vehiclelist.h" +#include "road.h" +#include "ai/ai.hpp" #include "table/strings.h" @@ -74,6 +76,9 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company) } case VEH_ROAD: + /* make sure the roadtypes are compatible */ + if ((GetRoadTypeInfo(e_from->u.road.roadtype)->powered_roadtypes & GetRoadTypeInfo(e_to->u.road.roadtype)->powered_roadtypes) == ROADTYPES_NONE) return false; + /* 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; @@ -98,9 +103,9 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company) */ void CheckCargoCapacity(Vehicle *v) { - assert(v == NULL || v->First() == v); + assert(v == nullptr || v->First() == v); - for (Vehicle *src = v; src != NULL; src = src->Next()) { + for (Vehicle *src = v; src != nullptr; src = src->Next()) { assert(src->cargo.TotalCount() == src->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); /* Do we need to more cargo away? */ @@ -108,7 +113,7 @@ void CheckCargoCapacity(Vehicle *v) /* 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()) { + for (Vehicle *dest = v; dest != nullptr && 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; @@ -135,7 +140,7 @@ static void TransferCargo(Vehicle *old_veh, Vehicle *new_head, bool part_of_chai { assert(!part_of_chain || new_head->IsPrimaryVehicle()); /* Loop through source parts */ - for (Vehicle *src = old_veh; src != NULL; src = src->Next()) { + for (Vehicle *src = old_veh; src != nullptr; 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 */ @@ -145,7 +150,7 @@ static void TransferCargo(Vehicle *old_veh, Vehicle *new_head, bool part_of_chai 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()) { + for (Vehicle *dest = new_head; dest != nullptr && 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 */ @@ -216,7 +221,7 @@ static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool /* 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()) { + for (v = v->First(); v != nullptr; 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; @@ -280,7 +285,7 @@ static CommandCost GetNewEngineType(const Vehicle *v, const Company *c, bool alw */ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehicle, bool part_of_chain) { - *new_vehicle = NULL; + *new_vehicle = nullptr; /* Shall the vehicle be replaced? */ const Company *c = Company::Get(_current_company); @@ -294,7 +299,7 @@ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehic 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)); + cost = DoCommand(old_veh->tile, e | (CT_INVALID << 24), 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh)); if (cost.Failed()) return cost; Vehicle *new_veh = Vehicle::Get(_new_vehicle_id); @@ -330,14 +335,14 @@ static inline CommandCost CmdStartStopVehicle(const Vehicle *v, bool evaluate_ca /** * 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 after The vehicle to insert 'v' after, or nullptr 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); + return DoCommand(0, v->index | (whole_chain ? 1 : 0) << 20, after != nullptr ? after->index : INVALID_VEHICLE, flags | DC_NO_CARGO_CAP_CHECK, CMD_MOVE_RAIL_VEHICLE); } /** @@ -395,11 +400,11 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, b CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); /* Build and refit replacement vehicle */ - Vehicle *new_v = NULL; + Vehicle *new_v = nullptr; cost.AddCost(BuildReplacementVehicle(old_v, &new_v, false)); /* Was a new vehicle constructed? */ - if (cost.Succeeded() && new_v != NULL) { + if (cost.Succeeded() && new_v != nullptr) { *nothing_to_do = false; if ((flags & DC_EXEC) != 0) { @@ -415,6 +420,8 @@ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, b TransferCargo(old_v, new_v, false); *single_unit = new_v; + + AI::NewEvent(old_v->owner, new ScriptEventVehicleAutoReplaced(old_v->index, new_v->index)); } /* Sell the old vehicle */ @@ -449,17 +456,17 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon 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++; + for (Train *w = Train::From(old_head); w != nullptr; 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 + Train **new_vehs = CallocT(num_units); ///< New vehicles corresponding to old_vehs or nullptr 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++) { + for (w = Train::From(old_head), i = 0; w != nullptr; w = w->GetNextUnit(), i++) { assert(i < num_units); old_vehs[i] = w; @@ -468,41 +475,41 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon if (cost.Failed()) break; new_costs[i] = ret.GetCost(); - if (new_vehs[i] != NULL) *nothing_to_do = false; + if (new_vehs[i] != nullptr) *nothing_to_do = false; } - Train *new_head = (new_vehs[0] != NULL ? new_vehs[0] : old_vehs[0]); + Train *new_head = (new_vehs[0] != nullptr ? 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)); + if (second != nullptr) cost.AddCost(CmdMoveVehicle(second, nullptr, DC_EXEC | DC_AUTOREPLACE, true)); - assert(Train::From(new_head)->GetNextUnit() == NULL); + assert(Train::From(new_head)->GetNextUnit() == nullptr); /* 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 + Train *last_engine = nullptr; ///< 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]); + Train *append = (new_vehs[i] != nullptr ? new_vehs[i] : old_vehs[i]); if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) continue; - if (new_vehs[i] != NULL) { + if (new_vehs[i] != nullptr) { /* 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); + CmdMoveVehicle(old_vehs[i], nullptr, DC_EXEC | DC_AUTOREPLACE, false); } - if (last_engine == NULL) last_engine = append; + if (last_engine == nullptr) last_engine = append; cost.AddCost(CmdMoveVehicle(append, new_head, DC_EXEC, false)); if (cost.Failed()) break; } - if (last_engine == NULL) last_engine = new_head; + if (last_engine == nullptr) 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 */ @@ -513,8 +520,8 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon */ 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]); + assert(last_engine != nullptr); + Vehicle *append = (new_vehs[i] != nullptr ? new_vehs[i] : old_vehs[i]); if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) { /* Insert wagon after 'last_engine' */ @@ -524,7 +531,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon * 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); + CmdMoveVehicle(append, nullptr, DC_EXEC | DC_AUTOREPLACE, false); break; } @@ -543,7 +550,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon 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 == nullptr) continue; if (wagon->First() == new_head) break; assert(RailVehInfo(wagon->engine_type)->railveh_type == RAILVEH_WAGON); @@ -551,7 +558,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon /* Sell wagon */ CommandCost ret = DoCommand(0, wagon->index, 0, DC_EXEC, GetCmdSellVeh(wagon)); assert(ret.Succeeded()); - new_vehs[i] = NULL; + new_vehs[i] = nullptr; /* Revert the money subtraction when the vehicle was built. * This value is different from the sell value, esp. because of refitting */ @@ -572,18 +579,21 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon 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 */ + * Note: We cannot test 'new_vehs[i] != nullptr' 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 + * Note: This might temporarily 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; + old_vehs[i] = nullptr; + if (i == 0) { + AI::NewEvent(old_head->owner, new ScriptEventVehicleAutoReplaced(old_head->index, new_head->index)); + old_head = nullptr; + } } } @@ -596,9 +606,9 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon 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); + if (second != nullptr) CmdMoveVehicle(second, nullptr, DC_EXEC | DC_AUTOREPLACE, true); - assert(Train::From(old_head)->GetNextUnit() == NULL); + assert(Train::From(old_head)->GetNextUnit() == nullptr); for (int i = num_units - 1; i > 0; i--) { CommandCost ret = CmdMoveVehicle(old_vehs[i], old_head, DC_EXEC | DC_AUTOREPLACE, false); @@ -610,9 +620,9 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon /* 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) { + if (new_vehs[i] != nullptr) { DoCommand(0, new_vehs[i]->index, 0, DC_EXEC, GetCmdSellVeh(new_vehs[i])); - new_vehs[i] = NULL; + new_vehs[i] = nullptr; } } } @@ -622,11 +632,11 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon free(new_costs); } else { /* Build and refit replacement vehicle */ - Vehicle *new_head = NULL; + Vehicle *new_head = nullptr; cost.AddCost(BuildReplacementVehicle(old_head, &new_head, true)); /* Was a new vehicle constructed? */ - if (cost.Succeeded() && new_head != NULL) { + if (cost.Succeeded() && new_head != nullptr) { *nothing_to_do = false; /* The new vehicle is constructed, now take over orders and everything... */ @@ -637,6 +647,8 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon if ((flags & DC_EXEC) != 0) { TransferCargo(old_head, new_head, true); *chain = new_head; + + AI::NewEvent(old_head->owner, new ScriptEventVehicleAutoReplaced(old_head->index, new_head->index)); } /* Sell the old vehicle */ @@ -666,7 +678,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL) return CMD_ERROR; + if (v == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -690,12 +702,12 @@ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1 /* 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) { + while (w != nullptr) { 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); + w = (!free_wagon && w->type == VEH_TRAIN ? Train::From(w)->GetNextUnit() : nullptr); } CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); @@ -756,7 +768,7 @@ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1 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; + if (c == nullptr) return CMD_ERROR; EngineID old_engine_type = GB(p2, 0, 16); EngineID new_engine_type = GB(p2, 16, 16); diff --git a/src/autoreplace_func.h b/src/autoreplace_func.h index 3a6fc83a81..22287cd8c0 100644 --- a/src/autoreplace_func.h +++ b/src/autoreplace_func.h @@ -16,7 +16,7 @@ #include "company_base.h" void RemoveAllEngineReplacement(EngineRenewList *erl); -EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old = NULL); +EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old = nullptr); 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); @@ -38,7 +38,7 @@ static inline void RemoveAllEngineReplacementForCompany(Company *c) * @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) +static inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old = nullptr) { return EngineReplacement(c->engine_renew_list, engine, group, replace_when_old); } diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index eae0a378eb..a1a152cf69 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -14,6 +14,7 @@ #include "vehicle_gui.h" #include "newgrf_engine.h" #include "rail.h" +#include "road.h" #include "strings_func.h" #include "window_func.h" #include "autoreplace_func.h" @@ -24,6 +25,7 @@ #include "settings_func.h" #include "core/geometry_func.hpp" #include "rail_gui.h" +#include "road_gui.h" #include "widgets/dropdown_func.h" #include "widgets/autoreplace_widget.h" @@ -32,11 +34,9 @@ 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) +static bool EngineNumberSorter(const EngineID &a, const EngineID &b) { - int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; - - return r; + return Engine::Get(a)->list_position < Engine::Get(b)->list_position; } /** @@ -88,6 +88,7 @@ class ReplaceVehicleWindow : public Window { 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. + RoadType sel_roadtype; ///< Type of road selected. #INVALID_ROADTYPE to show all. Scrollbar *vscroll[2]; /** @@ -123,13 +124,27 @@ class ReplaceVehicleWindow : public Window { byte side = draw_left ? 0 : 1; GUIEngineList *list = &this->engines[side]; - list->Clear(); + 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 + switch (type) { + case VEH_TRAIN: + if (!this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains + break; + + case VEH_ROAD: + if (draw_left && this->sel_roadtype != INVALID_ROADTYPE) { + /* Ensure that the roadtype is specific to the selected one */ + if (e->u.road.roadtype != this->sel_roadtype) continue; + } + break; + + default: + break; + } if (draw_left) { const uint num_engines = GetGroupNumEngines(_local_company, this->sel_group, eid); @@ -140,7 +155,7 @@ class ReplaceVehicleWindow : public Window { if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue; } - *list->Append() = eid; + list->push_back(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) @@ -160,8 +175,8 @@ class ReplaceVehicleWindow : public Window { 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->vscroll[0]->SetCount((uint)this->engines[0].size()); + if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].size() != 0) { this->sel_engine[0] = this->engines[0][0]; } } @@ -170,7 +185,7 @@ class ReplaceVehicleWindow : public Window { /* 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->engines[1].clear(); this->sel_engine[1] = INVALID_ENGINE; } else { if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) { @@ -180,11 +195,11 @@ class ReplaceVehicleWindow : public Window { } /* 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()); + this->vscroll[1]->SetCount((uint)this->engines[1].size()); 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; + for (EngineID &eid : this->engines[1]) { + if (eid == this->sel_engine[1]) break; ++position; } this->vscroll[1]->ScrollTowards(position); @@ -212,6 +227,7 @@ public: ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc) { this->sel_railtype = INVALID_RAILTYPE; + this->sel_roadtype = INVALID_ROADTYPE; this->replace_engines = true; // start with locomotives (all other vehicles will not read this bool) this->engines[0].ForceRebuild(); this->engines[1].ForceRebuild(); @@ -231,13 +247,18 @@ public: widget->SetLowered(this->show_hidden_engines); this->FinishInitNested(vehicletype); + if (vehicletype == VEH_TRAIN || vehicletype == VEH_ROAD) { + widget = this->GetWidget(WID_RV_RAIL_ROAD_TYPE_DROPDOWN); + widget->tool_tip = STR_REPLACE_HELP_RAILTYPE + 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) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_RV_SORT_ASCENDING_DESCENDING: { @@ -289,13 +310,28 @@ public: break; } - case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { + case WID_RV_RAIL_ROAD_TYPE_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)); + switch (this->window_number) { + case VEH_TRAIN: + 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)); + } + break; + + case VEH_ROAD: + for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + /* Skip road type if it has no label */ + if (rti->label == 0) continue; + d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); + } + break; + + default: NOT_REACHED(); } d.width += padding.width; d.height += padding.height; @@ -316,7 +352,7 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_RV_CAPTION: @@ -353,7 +389,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_RV_SORT_ASCENDING_DESCENDING: @@ -384,7 +420,7 @@ public: 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()); + EngineID end = min(this->vscroll[side]->GetCapacity() + start, (uint)this->engines[side].size()); /* Do the actual drawing */ DrawEngineList((VehicleType)this->window_number, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, @@ -394,7 +430,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists(); @@ -411,9 +447,18 @@ public: * 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; + switch (this->window_number) { + case VEH_TRAIN: + /* Show the selected railtype in the pulldown menu */ + this->GetWidget(WID_RV_RAIL_ROAD_TYPE_DROPDOWN)->widget_data = sel_railtype == INVALID_RAILTYPE ? STR_REPLACE_ALL_RAILTYPE : GetRailTypeInfo(sel_railtype)->strings.replace_text; + break; + + case VEH_ROAD: + /* Show the selected roadtype in the pulldown menu */ + this->GetWidget(WID_RV_RAIL_ROAD_TYPE_DROPDOWN)->widget_data = sel_roadtype == INVALID_ROADTYPE ? STR_REPLACE_ALL_ROADTYPE : GetRoadTypeInfo(sel_roadtype)->strings.replace_text; + break; + + default: break; } this->DrawWidgets(); @@ -423,9 +468,16 @@ public: /* Draw details panels. */ for (int side = 0; side < 2; side++) { if (this->sel_engine[side] != INVALID_ENGINE) { + /* Use default engine details without refitting */ + const Engine *e = Engine::Get(this->sel_engine[side]); + TestedEngineDetails ted; + ted.cost = 0; + ted.cargo = e->GetDefaultCargoType(); + ted.capacity = e->GetDisplayDefaultCapacity(&ted.mail_capacity); + 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]); + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side], ted); needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); } } @@ -437,7 +489,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_RV_SORT_ASCENDING_DESCENDING: @@ -460,15 +512,23 @@ public: 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); + DropDownList list; + list.emplace_back(new DropDownListStringItem(STR_REPLACE_ENGINES, 1, false)); + list.emplace_back(new DropDownListStringItem(STR_REPLACE_WAGONS, 0, false)); + ShowDropDownList(this, std::move(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); + case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: // Rail/roadtype selection dropdown menu + switch (this->window_number) { + case VEH_TRAIN: + ShowDropDownList(this, GetRailTypeDropDownList(true, true), sel_railtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN); + break; + + case VEH_ROAD: + ShowDropDownList(this, GetRoadTypeDropDownList(RTTB_ROAD | RTTB_TRAM, true, true), sel_roadtype, WID_RV_RAIL_ROAD_TYPE_DROPDOWN); + break; + } break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length @@ -501,7 +561,7 @@ public: click_side = 1; } uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); - size_t engine_count = this->engines[click_side].Length(); + size_t engine_count = this->engines[click_side].size(); 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 @@ -516,7 +576,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_RV_SORT_DROPDOWN: @@ -528,10 +588,25 @@ public: } 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; + case WID_RV_RAIL_ROAD_TYPE_DROPDOWN: + switch (this->window_number) { + case VEH_TRAIN: { + RailType temp = (RailType)index; + if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything + sel_railtype = temp; + break; + } + + case VEH_ROAD: { + RoadType temp = (RoadType)index; + if (temp == sel_roadtype) return; // we didn't select a new one. No need to change anything + sel_roadtype = temp; + break; + } + + default: NOT_REACHED(); + } + /* Reset scrollbar positions */ this->vscroll[0]->SetPosition(0); this->vscroll[1]->SetPosition(0); @@ -541,7 +616,6 @@ public: this->reset_sel_engine = true; this->SetDirty(); break; - } case WID_RV_TRAIN_ENGINEWAGON_DROPDOWN: { this->replace_engines = index != 0; @@ -557,7 +631,7 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX); this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX); @@ -568,7 +642,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data != 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ @@ -598,7 +672,7 @@ static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { 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_RAIL_ROAD_TYPE_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(), @@ -643,6 +717,64 @@ static WindowDesc _replace_rail_vehicle_desc( _nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets) ); +static const NWidgetPart _nested_replace_road_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(WWT_DROPDOWN, COLOUR_GREY, WID_RV_RAIL_ROAD_TYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetFill(1, 0), SetResize(1, 0), + 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(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), + NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), + EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), +}; + +static WindowDesc _replace_road_vehicle_desc( + WDP_AUTO, "replace_vehicle_road", 500, 140, + WC_REPLACE_VEHICLE, WC_NONE, + WDF_CONSTRUCTION, + _nested_replace_road_vehicle_widgets, lengthof(_nested_replace_road_vehicle_widgets) +); + static const NWidgetPart _nested_replace_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), @@ -705,5 +837,11 @@ static WindowDesc _replace_vehicle_desc( 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); + WindowDesc *desc; + switch (vehicletype) { + case VEH_TRAIN: desc = &_replace_rail_vehicle_desc; break; + case VEH_ROAD: desc = &_replace_road_vehicle_desc; break; + default: desc = &_replace_vehicle_desc; break; + } + new ReplaceVehicleWindow(desc, vehicletype, id_g); } diff --git a/src/base_consist.cpp b/src/base_consist.cpp index 200512786c..7abb083f74 100644 --- a/src/base_consist.cpp +++ b/src/base_consist.cpp @@ -30,7 +30,7 @@ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src) if (this == src) return; free(this->name); - this->name = src->name != NULL ? stredup(src->name) : NULL; + this->name = src->name != nullptr ? stredup(src->name) : nullptr; this->current_order_time = src->current_order_time; this->lateness_counter = src->lateness_counter; diff --git a/src/base_consist.h b/src/base_consist.h index 3679afd351..8e1bc93e75 100644 --- a/src/base_consist.h +++ b/src/base_consist.h @@ -31,7 +31,7 @@ struct BaseConsist { uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) - BaseConsist() : name(NULL) {} + BaseConsist() : name(nullptr) {} virtual ~BaseConsist(); void CopyConsistPropertiesFrom(const BaseConsist *src); diff --git a/src/base_media_base.h b/src/base_media_base.h index b040abcf9d..1e251b36a7 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -76,9 +76,9 @@ struct BaseSet { { free(this->name); - for (TranslatedStrings::iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { - free(iter->first); - free(iter->second); + for (auto &pair : this->description) { + free(pair.first); + free(pair.second); } for (uint i = 0; i < NUM_FILES; i++) { @@ -118,20 +118,20 @@ struct BaseSet { * @param isocode the isocode to search for * @return the description */ - const char *GetDescription(const char *isocode = NULL) const + const char *GetDescription(const char *isocode = nullptr) const { - if (isocode != NULL) { + if (isocode != nullptr) { /* 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; + for (const auto &pair : this->description) { + if (strcmp(pair.first, isocode) == 0) return pair.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; + for (const auto &pair : this->description) { + if (strncmp(pair.first, isocode, 2) == 0) return pair.second; } } /* Then fall back */ - return this->description.Begin()->second; + return this->description.front().second; } /** @@ -151,17 +151,17 @@ struct BaseSet { /** * 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. + * @return The filename for the textfile, \c nullptr 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) { + if (textfile != nullptr) { return textfile; } } - return NULL; + return nullptr; } }; @@ -176,7 +176,7 @@ protected: 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); + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; /** * Get the extension that is used to identify this set. @@ -231,7 +231,7 @@ template /* static */ Tbase_set *BaseMedia::duplica * @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. + * @return The filename of the first file of the base set, or \c nullptr if there is no match. */ template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s); diff --git a/src/base_media_func.h b/src/base_media_func.h index f7afca0edb..98f8552173 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -23,7 +23,7 @@ */ #define fetch_metadata(name) \ item = metadata->GetItem(name, false); \ - if (item == NULL || StrEmpty(item->value)) { \ + if (item == nullptr || 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; \ @@ -50,7 +50,7 @@ bool BaseSet::FillSetDetails(IniFile *ini, const this->description[stredup("")] = stredup(item->value); /* Add the translations of the descriptions too. */ - for (const IniItem *item = metadata->item; item != NULL; item = item->next) { + for (const IniItem *item = metadata->item; item != nullptr; item = item->next) { if (strncmp("description.", item->name, 12) != 0) continue; this->description[stredup(item->name + 12)] = stredup(item->value); @@ -65,7 +65,7 @@ bool BaseSet::FillSetDetails(IniFile *ini, const this->version = atoi(item->value); item = metadata->GetItem("fallback", false); - this->fallback = (item != NULL && strcmp(item->value, "0") != 0 && strcmp(item->value, "false") != 0); + this->fallback = (item != nullptr && 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"); @@ -75,14 +75,14 @@ bool BaseSet::FillSetDetails(IniFile *ini, const 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)) { + if (item == nullptr || (item->value == nullptr && !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 (filename == nullptr) { + file->filename = nullptr; /* If we list no file, that file must be valid */ this->valid_files++; this->found_files++; @@ -93,7 +93,7 @@ bool BaseSet::FillSetDetails(IniFile *ini, const /* Then find the MD5 checksum */ item = md5s->GetItem(filename, false); - if (item == NULL || item->value == NULL) { + if (item == nullptr || item->value == nullptr) { DEBUG(grf, 0, "No MD5 checksum specified for: %s (in %s)", filename, full_filename); return false; } @@ -119,8 +119,8 @@ bool BaseSet::FillSetDetails(IniFile *ini, const /* 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) { + if (item == nullptr) item = origin->GetItem("default", false); + if (item == nullptr) { DEBUG(grf, 1, "No origin warning message specified for: %s", filename); file->missing_warning = stredup(""); } else { @@ -159,25 +159,25 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, Tbase_set *set = new Tbase_set(); IniFile *ini = new IniFile(); - ini->LoadFromDisk(filename, BASESET_DIR); - char *path = stredup(filename + basepath_length); + ini->LoadFromDisk(path, BASESET_DIR); + char *psep = strrchr(path, PATHSEPCHAR); - if (psep != NULL) { + if (psep != nullptr) { 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) { + Tbase_set *duplicate = nullptr; + for (Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { if (strcmp(c->name, set->name) == 0 || c->shortname == set->shortname) { duplicate = c; break; } } - if (duplicate != NULL) { + if (duplicate != nullptr) { /* 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) { @@ -205,7 +205,7 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, } } else { Tbase_set **last = &BaseMedia::available_sets; - while (*last != NULL) last = &(*last)->next; + while (*last != nullptr) last = &(*last)->next; *last = set; ret = true; @@ -238,7 +238,7 @@ template return true; } - for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { if (strcmp(name, s->name) == 0) { BaseMedia::used_set = s; CheckExternalFiles(); @@ -258,7 +258,7 @@ 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) { + for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { p += seprintf(p, last, "%18s: %s", s->name, s->GetDescription()); int invalid = s->GetNumInvalid(); if (invalid != 0) { @@ -277,12 +277,11 @@ template 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) { + for (; s != nullptr; s = s->next) { if (s->GetNumMissing() != 0) continue; if (s->shortname != ci->unique_id) continue; @@ -297,32 +296,16 @@ template const char *TryGetBaseSetFile(const ContentInfo *ci, } if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename; } - return NULL; + return nullptr; } 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); + return (TryGetBaseSetFile(ci, md5sum, BaseMedia::available_sets) != nullptr) || + (TryGetBaseSetFile(ci, md5sum, BaseMedia::duplicate_sets) != nullptr); } -#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 @@ -331,7 +314,7 @@ template /* static */ int BaseMedia::GetNumSets() { int n = 0; - for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; n++; } @@ -346,7 +329,7 @@ template /* static */ int BaseMedia::GetIndexOfUsedSet() { int n = 0; - for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { if (s == BaseMedia::used_set) return n; if (s->GetNumMissing() != 0) continue; n++; @@ -361,7 +344,7 @@ template template /* static */ const Tbase_set *BaseMedia::GetSet(int index) { - for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { + for (const Tbase_set *s = BaseMedia::available_sets; s != nullptr; s = s->next) { if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; if (index == 0) return s; index--; diff --git a/src/base_station_base.h b/src/base_station_base.h index cd512c5177..eaeb246ef1 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -60,8 +60,8 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { 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 + Owner owner; ///< The owner of this station + StationFacility 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 @@ -110,6 +110,12 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { */ virtual void UpdateVirtCoord() = 0; + virtual void MoveSign(TileIndex new_xy) + { + this->xy = new_xy; + this->UpdateVirtCoord(); + } + /** * Get the tile area for a given station type. * @param ta tile area to fill. @@ -214,7 +220,7 @@ struct SpecializedStation : public BaseStation { */ static inline T *GetIfValid(size_t index) { - return IsValidID(index) ? Get(index) : NULL; + return IsValidID(index) ? Get(index) : nullptr; } /** diff --git a/src/bitmap_type.h b/src/bitmap_type.h new file mode 100644 index 0000000000..655c8f3baa --- /dev/null +++ b/src/bitmap_type.h @@ -0,0 +1,137 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 bitmap_type.hpp Bitmap functions. */ + +#ifndef BITMAP_TYPE_HPP +#define BITMAP_TYPE_HPP + +#include + +/** Represents a tile area containing containing individually set tiles. + * Each tile must be contained within the preallocated area. + * A std::vector is used to mark which tiles are contained. + */ +class BitmapTileArea : public TileArea { +protected: + std::vector data; + + inline uint Index(uint x, uint y) const { return y * this->w + x; } + + inline uint Index(TileIndex tile) const { return Index(TileX(tile) - TileX(this->tile), TileY(tile) - TileY(this->tile)); } + +public: + BitmapTileArea() + { + this->tile = INVALID_TILE; + this->w = 0; + this->h = 0; + } + + BitmapTileArea(const TileArea &ta) + { + this->tile = ta.tile; + this->w = ta.w; + this->h = ta.h; + this->data.resize(Index(this->w, this->h)); + } + + /** + * Reset and clear the BitmapTileArea. + */ + void Reset() + { + this->tile = INVALID_TILE; + this->w = 0; + this->h = 0; + this->data.clear(); + } + + /** + * Initialize the BitmapTileArea with the specified Rect. + * @param rect Rect to use. + */ + void Initialize(const Rect &r) + { + this->tile = TileXY(r.left, r.top); + this->w = r.right - r.left + 1; + this->h = r.bottom - r.top + 1; + this->data.clear(); + this->data.resize(Index(w, h)); + } + + void Initialize(const TileArea &ta) + { + this->tile = ta.tile; + this->w = ta.w; + this->h = ta.h; + this->data.clear(); + this->data.resize(Index(w, h)); + } + + /** + * Add a tile as part of the tile area. + * @param tile Tile to add. + */ + inline void SetTile(TileIndex tile) + { + assert(this->Contains(tile)); + this->data[Index(tile)] = true; + } + + /** + * Clear a tile from the tile area. + * @param tile Tile to clear + */ + inline void ClrTile(TileIndex tile) + { + assert(this->Contains(tile)); + this->data[Index(tile)] = false; + } + + /** + * Test if a tile is part of the tile area. + * @param tile Tile to check + */ + inline bool HasTile(TileIndex tile) const + { + return this->Contains(tile) && this->data[Index(tile)]; + } +}; + +/** Iterator to iterate over all tiles belonging to a bitmaptilearea. */ +class BitmapTileIterator : public OrthogonalTileIterator { +protected: + const BitmapTileArea *bitmap; +public: + /** + * Construct the iterator. + * @param bitmap BitmapTileArea to iterate. + */ + BitmapTileIterator(const BitmapTileArea &bitmap) : OrthogonalTileIterator(bitmap), bitmap(&bitmap) + { + if (!this->bitmap->HasTile(TileIndex(this->tile))) ++(*this); + } + + inline TileIterator& operator ++() + { + (*this).OrthogonalTileIterator::operator++(); + while (this->tile != INVALID_TILE && !this->bitmap->HasTile(TileIndex(this->tile))) { + (*this).OrthogonalTileIterator::operator++(); + } + return *this; + } + + virtual TileIterator *Clone() const + { + return new BitmapTileIterator(*this); + } +}; + +#endif /* BITMAP_TYPE_HPP */ diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp index 27b1fbd5b8..af2755cd74 100644 --- a/src/blitter/32bpp_anim.cpp +++ b/src/blitter/32bpp_anim.cpp @@ -42,7 +42,7 @@ inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel 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 + const byte *remap = bp->remap; // store so we don't have to access it via bp every time for (int y = 0; y < bp->height; y++) { Colour *dst_ln = dst + bp->pitch; @@ -414,7 +414,7 @@ void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, in uint32 *udst = (uint32 *)dst; const uint32 *src = (const uint32 *)video; - if (this->anim_buf == NULL) return; + if (this->anim_buf == nullptr) return; const uint16 *anim_line = this->ScreenToAnimOffset((const uint32 *)video) + this->anim_buf; diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp index ecf6dcfca0..ea66234939 100644 --- a/src/blitter/32bpp_anim.hpp +++ b/src/blitter/32bpp_anim.hpp @@ -26,8 +26,8 @@ protected: public: Blitter_32bppAnim() : - anim_buf(NULL), - anim_alloc(NULL), + anim_buf(nullptr), + anim_alloc(nullptr), anim_buf_width(0), anim_buf_height(0), anim_buf_pitch(0) @@ -37,21 +37,21 @@ public: ~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(); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; + void SetPixel(void *video, int x, int y, uint8 colour) override; + void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override; + void DrawRect(void *video, int width, int height, uint8 colour) override; + void CopyFromBuffer(void *video, const void *src, int width, int height) override; + void CopyToBuffer(const void *video, void *dst, int width, int height) override; + void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override; + int BufferSize(int width, int height) override; + void PaletteAnimate(const Palette &palette) override; + Blitter::PaletteAnimation UsePaletteAnimation() override; - /* virtual */ const char *GetName() { return "32bpp-anim"; } - /* virtual */ int GetBytesPerPixel() { return 6; } - /* virtual */ void PostResize(); + const char *GetName() override { return "32bpp-anim"; } + int GetBytesPerPixel() override { return 6; } + void PostResize() override; /** * Look up the colour in the current palette. @@ -77,7 +77,7 @@ public: class FBlitter_32bppAnim : public BlitterFactory { public: FBlitter_32bppAnim() : BlitterFactory("32bpp-anim", "32bpp Animation Blitter (palette animation)") {} - /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppAnim(); } + Blitter *CreateInstance() override { return new Blitter_32bppAnim(); } }; #endif /* BLITTER_32BPP_ANIM_HPP */ diff --git a/src/blitter/32bpp_anim_sse2.hpp b/src/blitter/32bpp_anim_sse2.hpp index 0d4a5f1e65..aed11026c0 100644 --- a/src/blitter/32bpp_anim_sse2.hpp +++ b/src/blitter/32bpp_anim_sse2.hpp @@ -28,15 +28,15 @@ /** 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"; } + void PaletteAnimate(const Palette &palette) override; + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_32bppSSE2_Anim(); } }; #endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_anim_sse4.hpp b/src/blitter/32bpp_anim_sse4.hpp index ee678bc164..1a39a26fb6 100644 --- a/src/blitter/32bpp_anim_sse4.hpp +++ b/src/blitter/32bpp_anim_sse4.hpp @@ -35,19 +35,19 @@ 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) { + void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override { return Blitter_32bppSSE_Base::Encode(sprite, allocator); } - /* virtual */ const char *GetName() { return "32bpp-sse4-anim"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_32bppSSE4_Anim(); } }; #endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_base.hpp b/src/blitter/32bpp_base.hpp index 697593da6a..e481c15ccb 100644 --- a/src/blitter/32bpp_base.hpp +++ b/src/blitter/32bpp_base.hpp @@ -20,19 +20,19 @@ /** 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; } + uint8 GetScreenDepth() override { return 32; } + void *MoveTo(void *video, int x, int y) override; + void SetPixel(void *video, int x, int y, uint8 colour) override; + void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override; + void DrawRect(void *video, int width, int height, uint8 colour) override; + void CopyFromBuffer(void *video, const void *src, int width, int height) override; + void CopyToBuffer(const void *video, void *dst, int width, int height) override; + void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override; + void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override; + int BufferSize(int width, int height) override; + void PaletteAnimate(const Palette &palette) override; + Blitter::PaletteAnimation UsePaletteAnimation() override; + int GetBytesPerPixel() override { return 4; } /** * Look up the colour in the current palette. diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp index cc056f5b59..c6fa762e5a 100644 --- a/src/blitter/32bpp_optimized.cpp +++ b/src/blitter/32bpp_optimized.cpp @@ -48,7 +48,7 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL /* 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) */ + /* store so we don't have to access it via bp every time (compiler assumes pointer aliasing) */ const byte *remap = bp->remap; for (int y = 0; y < bp->height; y++) { @@ -66,7 +66,7 @@ inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomL /* 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 */ + /* number of pixels with the same alpha channel class */ uint n; while (dst < dst_end) { diff --git a/src/blitter/32bpp_optimized.hpp b/src/blitter/32bpp_optimized.hpp index c261aa33d6..fc8a406537 100644 --- a/src/blitter/32bpp_optimized.hpp +++ b/src/blitter/32bpp_optimized.hpp @@ -23,10 +23,10 @@ public: byte data[]; ///< Data, all zoomlevels. }; - /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); - /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override; - /* virtual */ const char *GetName() { return "32bpp-optimized"; } + const char *GetName() override { return "32bpp-optimized"; } template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); }; @@ -35,7 +35,7 @@ public: class FBlitter_32bppOptimized : public BlitterFactory { public: FBlitter_32bppOptimized() : BlitterFactory("32bpp-optimized", "32bpp Optimized Blitter (no palette animation)") {} - /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppOptimized(); } + Blitter *CreateInstance() override { return new Blitter_32bppOptimized(); } }; #endif /* BLITTER_32BPP_OPTIMIZED_HPP */ diff --git a/src/blitter/32bpp_simple.hpp b/src/blitter/32bpp_simple.hpp index 0751f6f753..3d43971e9e 100644 --- a/src/blitter/32bpp_simple.hpp +++ b/src/blitter/32bpp_simple.hpp @@ -26,18 +26,18 @@ class Blitter_32bppSimple : public Blitter_32bppBase { 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); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override; - /* virtual */ const char *GetName() { return "32bpp-simple"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_32bppSimple(); } }; #endif /* BLITTER_32BPP_SIMPLE_HPP */ diff --git a/src/blitter/32bpp_sse2.hpp b/src/blitter/32bpp_sse2.hpp index d6b17f679c..1628f1fa26 100644 --- a/src/blitter/32bpp_sse2.hpp +++ b/src/blitter/32bpp_sse2.hpp @@ -82,22 +82,22 @@ 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); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); - /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override { return Blitter_32bppSSE_Base::Encode(sprite, allocator); } - /* virtual */ const char *GetName() { return "32bpp-sse2"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_32bppSSE2(); } }; #endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_sse4.hpp b/src/blitter/32bpp_sse4.hpp index 9c59d253f5..36b5b16d4c 100644 --- a/src/blitter/32bpp_sse4.hpp +++ b/src/blitter/32bpp_sse4.hpp @@ -27,17 +27,17 @@ /** 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); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); - /* virtual */ const char *GetName() { return "32bpp-sse4"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_32bppSSE4(); } }; #endif /* WITH_SSE */ diff --git a/src/blitter/32bpp_ssse3.hpp b/src/blitter/32bpp_ssse3.hpp index e9cac8ff0b..3d6152e9e7 100644 --- a/src/blitter/32bpp_ssse3.hpp +++ b/src/blitter/32bpp_ssse3.hpp @@ -27,17 +27,17 @@ /** 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); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); - /* virtual */ const char *GetName() { return "32bpp-ssse3"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_32bppSSSE3(); } }; #endif /* WITH_SSE */ diff --git a/src/blitter/8bpp_base.hpp b/src/blitter/8bpp_base.hpp index 8f75dda5d3..7ab3f6378a 100644 --- a/src/blitter/8bpp_base.hpp +++ b/src/blitter/8bpp_base.hpp @@ -17,20 +17,20 @@ /** 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; } + uint8 GetScreenDepth() override { return 8; } + void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; + void *MoveTo(void *video, int x, int y) override; + void SetPixel(void *video, int x, int y, uint8 colour) override; + void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override; + void DrawRect(void *video, int width, int height, uint8 colour) override; + void CopyFromBuffer(void *video, const void *src, int width, int height) override; + void CopyToBuffer(const void *video, void *dst, int width, int height) override; + void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override; + void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override; + int BufferSize(int width, int height) override; + void PaletteAnimate(const Palette &palette) override; + Blitter::PaletteAnimation UsePaletteAnimation() override; + int GetBytesPerPixel() override { return 1; } }; #endif /* BLITTER_8BPP_BASE_HPP */ diff --git a/src/blitter/8bpp_optimized.cpp b/src/blitter/8bpp_optimized.cpp index 0f07e7c7bb..21bca67e17 100644 --- a/src/blitter/8bpp_optimized.cpp +++ b/src/blitter/8bpp_optimized.cpp @@ -167,7 +167,7 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloca uint trans = 0; uint pixels = 0; uint last_colour = 0; - byte *count_dst = NULL; + byte *count_dst = nullptr; /* Store the scaled image */ const SpriteLoader::CommonPixel *src = &sprite[i].data[y * sprite[i].width]; @@ -176,11 +176,11 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloca uint colour = src++->m; if (last_colour == 0 || colour == 0 || pixels == 255) { - if (count_dst != NULL) { + if (count_dst != nullptr) { /* Write how many non-transparent bytes we get */ *count_dst = pixels; pixels = 0; - count_dst = NULL; + count_dst = nullptr; } /* As long as we find transparency bytes, keep counting */ if (colour == 0 && trans != 255) { @@ -206,7 +206,7 @@ Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite *sprite, Alloca } } - if (count_dst != NULL) *count_dst = pixels; + if (count_dst != nullptr) *count_dst = pixels; /* Write line-ending */ *dst = 0; dst++; diff --git a/src/blitter/8bpp_optimized.hpp b/src/blitter/8bpp_optimized.hpp index b5b5324b91..509edb8c40 100644 --- a/src/blitter/8bpp_optimized.hpp +++ b/src/blitter/8bpp_optimized.hpp @@ -24,17 +24,17 @@ public: byte data[]; ///< Data, all zoomlevels. }; - /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); - /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override; - /* virtual */ const char *GetName() { return "8bpp-optimized"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_8bppOptimized(); } }; #endif /* BLITTER_8BPP_OPTIMIZED_HPP */ diff --git a/src/blitter/8bpp_simple.hpp b/src/blitter/8bpp_simple.hpp index c00c75ac04..e48bc37585 100644 --- a/src/blitter/8bpp_simple.hpp +++ b/src/blitter/8bpp_simple.hpp @@ -18,17 +18,17 @@ /** 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); + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override; - /* virtual */ const char *GetName() { return "8bpp-simple"; } + const char *GetName() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_8bppSimple(); } }; #endif /* BLITTER_8BPP_SIMPLE_HPP */ diff --git a/src/blitter/factory.hpp b/src/blitter/factory.hpp index 01faca68fd..5def16ea53 100644 --- a/src/blitter/factory.hpp +++ b/src/blitter/factory.hpp @@ -48,7 +48,7 @@ private: */ static Blitter **GetActiveBlitter() { - static Blitter *s_blitter = NULL; + static Blitter *s_blitter = nullptr; return &s_blitter; } @@ -58,8 +58,8 @@ protected: * @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 name != nullptr. + * @pre description != nullptr. * @pre There is no blitter registered with this name. */ BlitterFactory(const char *name, const char *description, bool usable = true) : @@ -96,7 +96,7 @@ public: static Blitter *SelectBlitter(const char *name) { BlitterFactory *b = GetBlitterFactory(name); - if (b == NULL) return NULL; + if (b == nullptr) return nullptr; Blitter *newb = b->CreateInstance(); delete *GetActiveBlitter(); @@ -109,7 +109,7 @@ public: /** * 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. + * @return The blitter factory, or nullptr when there isn't one with the wanted name. */ static BlitterFactory *GetBlitterFactory(const char *name) { @@ -128,7 +128,7 @@ public: } #endif /* defined(WITH_COCOA) */ #endif /* defined(DEDICATED) */ - if (GetBlitters().size() == 0) return NULL; + if (GetBlitters().size() == 0) return nullptr; const char *bname = (StrEmpty(name)) ? default_blitter : name; Blitters::iterator it = GetBlitters().begin(); @@ -138,7 +138,7 @@ public: return b; } } - return NULL; + return nullptr; } /** diff --git a/src/blitter/null.hpp b/src/blitter/null.hpp index a6fed2ebca..dff4992ccf 100644 --- a/src/blitter/null.hpp +++ b/src/blitter/null.hpp @@ -17,31 +17,31 @@ /** 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; }; + uint8 GetScreenDepth() override { return 0; } + void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override {}; + void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override {}; + Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) override; + void *MoveTo(void *video, int x, int y) override { return nullptr; }; + void SetPixel(void *video, int x, int y, uint8 colour) override {}; + void DrawRect(void *video, int width, int height, uint8 colour) override {}; + void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) override {}; + void CopyFromBuffer(void *video, const void *src, int width, int height) override {}; + void CopyToBuffer(const void *video, void *dst, int width, int height) override {}; + void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) override {}; + void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) override {}; + int BufferSize(int width, int height) override { return 0; }; + void PaletteAnimate(const Palette &palette) override { }; + Blitter::PaletteAnimation UsePaletteAnimation() override { return Blitter::PALETTE_ANIMATION_NONE; }; - /* virtual */ const char *GetName() { return "null"; } - /* virtual */ int GetBytesPerPixel() { return 0; } + const char *GetName() override { return "null"; } + int GetBytesPerPixel() override { 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(); } + Blitter *CreateInstance() override { return new Blitter_Null(); } }; #endif /* BLITTER_NULL_HPP */ diff --git a/src/bmp.cpp b/src/bmp.cpp index 1033d89f11..a121782be7 100644 --- a/src/bmp.cpp +++ b/src/bmp.cpp @@ -319,7 +319,7 @@ static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data) bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data) { uint32 header_size; - assert(info != NULL); + assert(info != nullptr); MemSetT(info, 0); /* Reading BMP header */ @@ -390,7 +390,7 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data) */ bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data) { - assert(info != NULL && data != NULL); + assert(info != nullptr && data != nullptr); data->bitmap = CallocT(info->width * info->height * ((info->bpp == 24) ? 3 : 1)); @@ -413,7 +413,7 @@ bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data) void BmpDestroyData(BmpData *data) { - assert(data != NULL); + assert(data != nullptr); free(data->palette); free(data->bitmap); } diff --git a/src/bmp.h b/src/bmp.h index cf2b538f39..adfbfa5fef 100644 --- a/src/bmp.h +++ b/src/bmp.h @@ -15,7 +15,7 @@ #include "gfx_type.h" struct BmpInfo { - uint32 offset; ///< offset of bitmap data from .bmp file begining + uint32 offset; ///< offset of bitmap data from .bmp file beginning uint32 width; ///< bitmap width uint32 height; ///< bitmap height bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp index 3fb52a1f9e..d62a2266f4 100644 --- a/src/bootstrap_gui.cpp +++ b/src/bootstrap_gui.cpp @@ -13,7 +13,7 @@ #include "base_media_base.h" #include "blitter/factory.hpp" -#if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) +#if defined(WITH_FREETYPE) #include "core/geometry_func.hpp" #include "fontcache.h" @@ -40,7 +40,7 @@ static const struct NWidgetPart _background_widgets[] = { * Window description for the background window to prevent smearing. */ static WindowDesc _background_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_BOOTSTRAP, WC_NONE, 0, _background_widgets, lengthof(_background_widgets) @@ -56,7 +56,7 @@ public: ResizeWindow(this, _screen.width, _screen.height); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE); GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER); @@ -73,7 +73,7 @@ static const NWidgetPart _nested_boostrap_download_status_window_widgets[] = { /** Window description for the download window */ static WindowDesc _bootstrap_download_status_window_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_boostrap_download_status_window_widgets, lengthof(_nested_boostrap_download_status_window_widgets) @@ -88,7 +88,7 @@ public: { } - virtual void OnDownloadComplete(ContentID cid) + void OnDownloadComplete(ContentID cid) override { /* We have completed downloading. We can trigger finding the right set now. */ BaseGraphics::FindSets(); @@ -118,7 +118,7 @@ static const NWidgetPart _bootstrap_query_widgets[] = { /** The window description for the query. */ static WindowDesc _bootstrap_query_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, 0, _bootstrap_query_widgets, lengthof(_bootstrap_query_widgets) @@ -142,7 +142,7 @@ public: _network_content_client.RemoveCallback(this); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { /* We cache the button size. This is safe as no reinit can happen here. */ if (this->button_size.width == 0) { @@ -165,14 +165,14 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { 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) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BAFD_YES: @@ -189,13 +189,13 @@ public: } } - virtual void OnConnect(bool success) + void OnConnect(bool success) override { /* Once connected, request the metadata. */ _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); } - virtual void OnReceiveContentInfo(const ContentInfo *ci) + void OnReceiveContentInfo(const ContentInfo *ci) override { /* And once the meta data is received, start downloading it. */ _network_content_client.Select(ci->id); @@ -204,7 +204,7 @@ public: } }; -#endif /* defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) */ +#endif /* defined(WITH_FREETYPE) */ /** * Handle all procedures for bootstrapping OpenTTD without a base graphics set. @@ -214,13 +214,13 @@ public: */ bool HandleBootstrap() { - if (BaseGraphics::GetUsedSet() != NULL) return true; + if (BaseGraphics::GetUsedSet() != nullptr) 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 defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(_WIN32) || defined(__APPLE__)) if (!_network_available) goto failure; /* First tell the game we're bootstrapping. */ @@ -255,7 +255,7 @@ bool HandleBootstrap() if (_exit_game) return false; /* Try to probe the graphics. Should work this time. */ - if (!BaseGraphics::SetSet(NULL)) goto failure; + if (!BaseGraphics::SetSet(nullptr)) goto failure; /* Finally we can continue heading for the menu. */ _game_mode = GM_MENU; diff --git a/src/bridge_gui.cpp b/src/bridge_gui.cpp index c5add52159..916016fdf8 100644 --- a/src/bridge_gui.cpp +++ b/src/bridge_gui.cpp @@ -13,6 +13,7 @@ #include "error.h" #include "command_func.h" #include "rail.h" +#include "road.h" #include "strings_func.h" #include "window_func.h" #include "sound_func.h" @@ -97,31 +98,31 @@ private: Scrollbar *vscroll; /** Sort the bridges by their index */ - static int CDECL BridgeIndexSorter(const BuildBridgeData *a, const BuildBridgeData *b) + static bool BridgeIndexSorter(const BuildBridgeData &a, const BuildBridgeData &b) { - return a->index - b->index; + return a.index < b.index; } /** Sort the bridges by their price */ - static int CDECL BridgePriceSorter(const BuildBridgeData *a, const BuildBridgeData *b) + static bool BridgePriceSorter(const BuildBridgeData &a, const BuildBridgeData &b) { - return a->cost - b->cost; + return a.cost < b.cost; } /** Sort the bridges by their maximum speed */ - static int CDECL BridgeSpeedSorter(const BuildBridgeData *a, const BuildBridgeData *b) + static bool BridgeSpeedSorter(const BuildBridgeData &a, const BuildBridgeData &b) { - return a->spec->speed - b->spec->speed; + 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; + case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->at(i).index; break; + case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->at(i).index; break; default: break; } - DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index, + DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->at(i).index, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); } @@ -157,7 +158,7 @@ public: this->bridges->NeedResort(); this->SortBridgeList(); - this->vscroll->SetCount(bl->Length()); + this->vscroll->SetCount((uint)bl->size()); } ~BuildBridgeWindow() @@ -167,7 +168,7 @@ public: delete bridges; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BBS_DROPDOWN_ORDER: { @@ -190,11 +191,11 @@ public: 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; + for (int i = 0; i < (int)this->bridges->size(); i++) { + const BridgeSpec *b = this->bridges->at(i).spec; sprite_dim = maxdim(sprite_dim, GetSpriteSize(b->sprite)); - SetDParam(2, this->bridges->Get(i)->cost); + SetDParam(2, this->bridges->at(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)); @@ -211,7 +212,7 @@ public: } } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { /* Position the window so hopefully the first bridge from the list is under the mouse pointer. */ NWidgetBase *list = this->GetWidget(WID_BBS_BRIDGE_LIST); @@ -221,7 +222,7 @@ public: return corner; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_BBS_DROPDOWN_ORDER: @@ -230,10 +231,10 @@ public: 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; + for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges->size(); i++) { + const BridgeSpec *b = this->bridges->at(i).spec; - SetDParam(2, this->bridges->Get(i)->cost); + SetDParam(2, this->bridges->at(i).cost); SetDParam(1, b->speed); SetDParam(0, b->material); @@ -247,10 +248,10 @@ public: } } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { const uint8 i = keycode - '1'; - if (i < 9 && i < this->bridges->Length()) { + if (i < 9 && i < this->bridges->size()) { /* Build the requested bridge */ this->BuildBridge(i); delete this; @@ -259,13 +260,13 @@ public: return ES_NOT_HANDLED; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { 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()) { + if (i < this->bridges->size()) { this->BuildBridge(i); delete this; } @@ -283,7 +284,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges->SortType() != index) { this->bridges->SetSortType(index); @@ -292,7 +293,7 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_BBS_BRIDGE_LIST); } @@ -396,7 +397,7 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo 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; + GUIBridgeList *bl = nullptr; if (ret.Failed()) { errmsg = ret.GetErrorMessage(); } else { @@ -407,11 +408,25 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo Money infra_cost = 0; switch (transport_type) { - case TRANSPORT_ROAD: - infra_cost = (bridge_len + 2) * _price[PR_BUILD_ROAD] * 2; + case TRANSPORT_ROAD: { /* 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); + RoadType road_rt = INVALID_ROADTYPE; + RoadType tram_rt = INVALID_ROADTYPE; + if (IsBridgeTile(start)) { + road_rt = GetRoadTypeRoad(start); + tram_rt = GetRoadTypeTram(start); + } + if (RoadTypeIsRoad((RoadType)road_rail_type)) { + road_rt = (RoadType)road_rail_type; + } else { + tram_rt = (RoadType)road_rail_type; + } + + if (road_rt != INVALID_ROADTYPE) infra_cost += (bridge_len + 2) * 2 * RoadBuildCost(road_rt); + if (tram_rt != INVALID_ROADTYPE) infra_cost += (bridge_len + 2) * 2 * RoadBuildCost(tram_rt); + break; + } case TRANSPORT_RAIL: infra_cost = (bridge_len + 2) * RailBuildCost((RailType)road_rail_type); break; default: break; } @@ -420,17 +435,18 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo 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); + /*C++17: BuildBridgeData &item = */ bl->emplace_back(); + BuildBridgeData &item = bl->back(); + 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; + item.cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price[PR_BUILD_BRIDGE] * item.spec->price) >> 8) + infra_cost; } } } - if (bl != NULL && bl->Length() != 0) { + if (bl != nullptr && bl->size() != 0) { new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl); } else { delete bl; diff --git a/src/bridge_map.h b/src/bridge_map.h index 75b20498d1..be37dfd71c 100644 --- a/src/bridge_map.h +++ b/src/bridge_map.h @@ -12,8 +12,10 @@ #ifndef BRIDGE_MAP_H #define BRIDGE_MAP_H +#include "rail_map.h" #include "road_map.h" #include "bridge.h" +#include "water_map.h" /** * Checks if this is a bridge, instead of a tunnel @@ -123,20 +125,20 @@ static inline void SetBridgeMiddle(TileIndex t, Axis a) * @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) +static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, TransportType tt) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); + SetDockingTile(t, false); _m[t].m2 = 0; _m[t].m3 = 0; - _m[t].m4 = 0; + _m[t].m4 = INVALID_ROADTYPE; _m[t].m5 = 1 << 7 | tt << 2 | d; SB(_me[t].m6, 2, 4, bridgetype); _me[t].m7 = 0; - _me[t].m8 = rt; + _me[t].m8 = INVALID_ROADTYPE << 6; } /** @@ -147,14 +149,15 @@ static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, D * @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 + * @param road_rt the road type of the bridge + * @param tram_rt the tram type of the bridge */ -static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadTypes r) +static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadType road_rt, RoadType tram_rt) { - 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); + MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD); + SetRoadOwner(t, RTT_ROAD, owner_road); + if (owner_tram != OWNER_TOWN) SetRoadOwner(t, RTT_TRAM, owner_tram); + SetRoadTypes(t, road_rt, tram_rt); } /** @@ -163,11 +166,12 @@ static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Ow * @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 + * @param rt the rail type of the bridge */ -static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r) +static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType rt) { - MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r); + MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL); + SetRailType(t, rt); } /** @@ -178,7 +182,7 @@ static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetyp */ static inline void MakeAqueductBridgeRamp(TileIndex t, Owner o, DiagDirection d) { - MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER, 0); + MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER); } #endif /* BRIDGE_MAP_H */ diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 551f254380..39c3bfa14f 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -99,57 +99,54 @@ static CargoID _engine_sort_last_cargo_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) +static bool EngineNumberSorter(const EngineID &a, const EngineID &b) { - int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; + int r = Engine::Get(a)->list_position - Engine::Get(b)->list_position; - return _engine_sort_direction ? -r : r; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b) +static bool 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 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) +static bool 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); + if (a != last_engine[0]) { + last_engine[0] = a; + SetDParam(0, a); GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); } - if (vb != last_engine[1]) { - last_engine[1] = vb; - SetDParam(0, vb); + if (b != last_engine[1]) { + last_engine[1] = b; + SetDParam(0, b); GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); } @@ -157,207 +154,221 @@ static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); - return _engine_sort_direction ? -r : r; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b) +static bool EngineReliabilitySorter(const EngineID &a, const EngineID &b) { - const int va = Engine::Get(*a)->reliability; - const int vb = Engine::Get(*b)->reliability; + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b) +static bool EngineCostSorter(const EngineID &a, const EngineID &b) { - Money va = Engine::Get(*a)->GetCost(); - Money vb = Engine::Get(*b)->GetCost(); + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b) +static bool EngineSpeedSorter(const EngineID &a, const EngineID &b) { - int va = Engine::Get(*a)->GetDisplayMaxSpeed(); - int vb = Engine::Get(*b)->GetDisplayMaxSpeed(); + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b) +static bool EnginePowerSorter(const EngineID &a, const EngineID &b) { - int va = Engine::Get(*a)->GetPower(); - int vb = Engine::Get(*b)->GetPower(); + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b) +static bool EngineTractiveEffortSorter(const EngineID &a, const EngineID &b) { - int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort(); - int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort(); + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b) +static bool EngineRunningCostSorter(const EngineID &a, const EngineID &b) { - Money va = Engine::Get(*a)->GetRunningCost(); - Money vb = Engine::Get(*b)->GetRunningCost(); + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b) +static bool 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; + const Engine *e_a = Engine::Get(a); + const Engine *e_b = Engine::Get(b); + uint p_a = e_a->GetPower(); + uint p_b = e_b->GetPower(); + Money r_a = e_a->GetRunningCost(); + Money r_b = e_b->GetRunningCost(); + /* Check if running cost is zero in one or both engines. + * If only one of them is zero then that one has higher value, + * else if both have zero cost then compare powers. */ + if (r_a == 0) { + if (r_b == 0) { + /* If it is ambiguous which to return go with their ID */ + if (p_a == p_b) return EngineNumberSorter(a, b); + return _engine_sort_direction != (p_a < p_b); + } + return !_engine_sort_direction; + } + if (r_b == 0) return _engine_sort_direction; + /* Using double for more precision when comparing close values. + * This shouldn't have any major effects in performance nor in keeping + * the game in sync between players since it's used in GUI only in client side */ + double v_a = (double)p_a / (double)r_a; + double v_b = (double)p_b / (double)r_b; + /* Use EngineID to sort if both have same power/running cost, + * since we want consistent sorting. + * Also if both have no power then sort with reverse of running cost to simulate + * previous sorting behaviour for wagons. */ + if (v_a == 0 && v_b == 0) return !EngineRunningCostSorter(a, b); + if (v_a == v_b) return EngineNumberSorter(a, b); + return _engine_sort_direction != (v_a < v_b); } /* 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b) +static bool TrainEngineCapacitySorter(const EngineID &a, const EngineID &b) { - const RailVehicleInfo *rvi_a = RailVehInfo(*a); - const RailVehicleInfo *rvi_b = RailVehInfo(*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 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) +static bool 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 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; + return _engine_sort_direction ? r > 0 : r < 0; } /* 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL RoadVehEngineCapacitySorter(const EngineID *a, const EngineID *b) +static bool RoadVehEngineCapacitySorter(const EngineID &a, const EngineID &b) { - int va = GetTotalCapacityOfArticulatedParts(*a); - int vb = GetTotalCapacityOfArticulatedParts(*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; + return _engine_sort_direction ? r > 0 : r < 0; } /* 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b) +static bool ShipEngineCapacitySorter(const EngineID &a, const EngineID &b) { - const Engine *e_a = Engine::Get(*a); - const Engine *e_b = Engine::Get(*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(); @@ -365,21 +376,21 @@ static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b) /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); - return _engine_sort_direction ? -r : r; + return _engine_sort_direction ? r > 0 : r < 0; } /* 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 + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b) +static bool AircraftEngineCargoSorter(const EngineID &a, const EngineID &b) { - const Engine *e_a = Engine::Get(*a); - const Engine *e_b = Engine::Get(*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); @@ -395,25 +406,25 @@ static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b) return EngineNumberSorter(a, b); } } - return _engine_sort_direction ? -r : r; + return _engine_sort_direction ? r > 0 : r < 0; } /** * 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. + * @param a first engine to compare + * @param b second engine to compare + * @return for descending order: returns true if a < b. Vice versa for ascending order */ -static int CDECL AircraftRangeSorter(const EngineID *a, const EngineID *b) +static bool AircraftRangeSorter(const EngineID &a, const EngineID &b) { - uint16 r_a = Engine::Get(*a)->GetRange(); - uint16 r_b = Engine::Get(*b)->GetRange(); + 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; + return _engine_sort_direction ? r > 0 : r < 0; } /** Sort functions for the vehicle sort criteria, for each vehicle type. */ @@ -532,11 +543,11 @@ static GUIEngineList::FilterFunction * const _filter_funcs[] = { &CargoFilter, }; -static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine) +static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, TestedEngineDetails &te) { CargoArray cap; CargoTypes refits; - GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits); + GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits, te.cargo, te.capacity); for (CargoID c = 0; c < NUM_CARGO; c++) { if (cap[c] == 0) continue; @@ -552,19 +563,25 @@ static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine) } /* Draw rail wagon specific details */ -static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) +static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te) { const Engine *e = Engine::Get(engine_number); /* Purchase cost */ - SetDParam(0, e->GetCost()); - DrawString(left, right, y, STR_PURCHASE_INFO_COST); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT); + } else { + 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); + uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0); SetDParam(1, cargo_weight + weight); DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); y += FONT_HEIGHT_NORMAL; @@ -590,14 +607,21 @@ static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine } /* Draw locomotive specific details */ -static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) +static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi, TestedEngineDetails &te) { 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); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + SetDParam(2, e->GetDisplayWeight()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_WEIGHT); + } else { + 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 */ @@ -632,20 +656,26 @@ static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engin } /* Draw road vehicle specific details */ -static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number) +static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te) { 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); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT); + } else { + 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); + uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(te.cargo)->weight * te.capacity / 16 : 0); SetDParam(1, cargo_weight + weight); DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); y += FONT_HEIGHT_NORMAL; @@ -662,9 +692,16 @@ static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_n 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); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + SetDParam(2, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED); + } else { + SetDParam(0, e->GetCost()); + SetDParam(1, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); + } y += FONT_HEIGHT_NORMAL; } @@ -677,7 +714,7 @@ static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_n } /* Draw ship specific details */ -static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) +static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te) { const Engine *e = Engine::Get(engine_number); @@ -686,13 +723,27 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb 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); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + SetDParam(2, ocean_speed); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED); + } else { + SetDParam(0, e->GetCost()); + 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); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT); + } else { + SetDParam(0, e->GetCost()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST); + } y += FONT_HEIGHT_NORMAL; SetDParam(0, ocean_speed); @@ -705,8 +756,8 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb } /* Cargo type + capacity */ - SetDParam(0, e->GetDefaultCargoType()); - SetDParam(1, e->GetDisplayDefaultCapacity()); + SetDParam(0, te.cargo); + SetDParam(1, te.capacity); SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); y += FONT_HEIGHT_NORMAL; @@ -728,31 +779,35 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb * @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) +static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable, TestedEngineDetails &te) { 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); + if (te.cost != 0) { + SetDParam(0, e->GetCost() + te.cost); + SetDParam(1, te.cost); + SetDParam(2, e->GetDisplayMaxSpeed()); + DrawString(left, right, y, STR_PURCHASE_INFO_COST_REFIT_SPEED); + } else { + 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); + if (te.mail_capacity > 0) { + SetDParam(0, te.cargo); + SetDParam(1, te.capacity); SetDParam(2, CT_MAIL); - SetDParam(3, mail_capacity); + SetDParam(3, te.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(0, te.cargo); + SetDParam(1, te.capacity); SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); } @@ -789,7 +844,7 @@ static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_ */ static uint ShowAdditionalText(int left, int right, int y, EngineID engine) { - uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL); + uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr); if (callback == CALLBACK_FAILED || callback == 0x400) return y; const GRFFile *grffile = Engine::Get(engine)->GetGRF(); if (callback > 0x400) { @@ -809,7 +864,7 @@ static uint ShowAdditionalText(int left, int right, int y, EngineID engine) * @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) +int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te) { const Engine *e = Engine::Get(engine_number); YearMonthDay ymd; @@ -821,30 +876,30 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number) default: NOT_REACHED(); case VEH_TRAIN: if (e->u.rail.railveh_type == RAILVEH_WAGON) { - y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail); + y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te); } else { - y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail); + y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te); } articulated_cargo = true; break; case VEH_ROAD: - y = DrawRoadVehPurchaseInfo(left, right, y, engine_number); + y = DrawRoadVehPurchaseInfo(left, right, y, engine_number, te); articulated_cargo = true; break; case VEH_SHIP: - y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable); + y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable, te); break; case VEH_AIRCRAFT: - y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable); + y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable, te); break; } if (articulated_cargo) { /* Cargo type + capacity, or N/A */ - int new_y = DrawCargoCapacityInfo(left, right, y, engine_number); + int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, te); if (new_y == y) { SetDParam(0, CT_INVALID); @@ -896,7 +951,7 @@ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList * static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; /* Obligatory sanity checks! */ - assert(max <= eng_list->Length()); + assert(max <= eng_list->size()); bool rtl = _current_text_dir == TD_RTL; int step_size = GetEngineListHeight(type); @@ -973,8 +1028,8 @@ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selecte 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. + RailType railtype; ///< Rail type to show, or #INVALID_RAILTYPE. + RoadType roadtype; ///< Road type to show, or #INVALID_ROADTYPE. } filter; ///< Filter to apply. bool descending_sort_order; ///< Sort direction, @see _engine_sort_direction byte sort_criteria; ///< Current sort criterium. @@ -988,11 +1043,29 @@ struct BuildVehicleWindow : Window { byte cargo_filter_criteria; ///< Selected cargo filter int details_height; ///< Minimal needed height of the details panels (found so far). Scrollbar *vscroll; + TestedEngineDetails te; ///< Tested cost and capacity after refit. + + void SetBuyVehicleText() + { + NWidgetCore *widget = this->GetWidget(WID_BV_BUILD); + + bool refit = this->sel_engine != INVALID_ENGINE && this->cargo_filter[this->cargo_filter_criteria] != CF_ANY && this->cargo_filter[this->cargo_filter_criteria] != CF_NONE; + if (refit) refit = Engine::Get(this->sel_engine)->GetDefaultCargoType() != this->cargo_filter[this->cargo_filter_criteria]; + + if (refit) { + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP + this->vehicle_type; + } else { + widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type; + widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + this->vehicle_type; + } + } BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) { this->vehicle_type = type; - this->window_number = tile == INVALID_TILE ? (int)type : tile; + this->listview_mode = tile == INVALID_TILE; + this->window_number = this->listview_mode ? (int)type : tile; this->sel_engine = INVALID_ENGINE; @@ -1000,19 +1073,7 @@ struct BuildVehicleWindow : Window { 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->UpdateFilterByTile(); this->CreateNestedTree(); @@ -1031,10 +1092,6 @@ struct BuildVehicleWindow : Window { 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; @@ -1053,7 +1110,41 @@ struct BuildVehicleWindow : Window { 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]; + if (this->eng_list.size() > 0) { + this->SelectEngine(this->eng_list[0]); + } else { + this->SelectEngine(INVALID_ENGINE); + } + } + + /** Set the filter type according to the depot type */ + void UpdateFilterByTile() + { + switch (this->vehicle_type) { + default: NOT_REACHED(); + case VEH_TRAIN: + if (this->listview_mode) { + this->filter.railtype = INVALID_RAILTYPE; + } else { + this->filter.railtype = GetRailType(this->window_number); + } + break; + + case VEH_ROAD: + if (this->listview_mode) { + this->filter.roadtype = INVALID_ROADTYPE; + } else { + this->filter.roadtype = GetRoadTypeRoad(this->window_number); + if (this->filter.roadtype == INVALID_ROADTYPE) { + this->filter.roadtype = GetRoadTypeTram(this->window_number); + } + } + break; + + case VEH_SHIP: + case VEH_AIRCRAFT: + break; + } } /** Populate the filter list and set the cargo filter criteria. */ @@ -1100,7 +1191,42 @@ struct BuildVehicleWindow : Window { this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); } - void OnInit() + void SelectEngine(EngineID engine) + { + CargoID cargo = this->cargo_filter[this->cargo_filter_criteria]; + if (cargo == CF_ANY) cargo = CF_NONE; + + this->sel_engine = engine; + this->SetBuyVehicleText(); + + if (this->sel_engine == INVALID_ENGINE) return; + + const Engine *e = Engine::Get(this->sel_engine); + if (!e->CanCarryCargo()) { + this->te.cost = 0; + this->te.cargo = CT_INVALID; + return; + } + + if (!this->listview_mode) { + /* Query for cost and refitted capacity */ + CommandCost ret = DoCommand(this->window_number, this->sel_engine | (cargo << 24), 0, DC_QUERY_COST, GetCmdBuildVeh(this->vehicle_type), nullptr); + if (ret.Succeeded()) { + this->te.cost = ret.GetCost() - e->GetCost(); + this->te.capacity = _returned_refit_capacity; + this->te.mail_capacity = _returned_mail_refit_capacity; + this->te.cargo = (cargo == CT_INVALID) ? e->GetDefaultCargoType() : cargo; + return; + } + } + + /* Purchase test was not possible or failed, fill in the defaults instead. */ + this->te.cost = 0; + this->te.capacity = e->GetDisplayDefaultCapacity(&this->te.mail_capacity); + this->te.cargo = e->GetDefaultCargoType(); + } + + void OnInit() override { this->SetCargoFilterArray(); } @@ -1109,10 +1235,10 @@ struct BuildVehicleWindow : Window { 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]; + if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine + this->SelectEngine(INVALID_ENGINE); + } else if (std::find(this->eng_list.begin(), this->eng_list.end(), this->sel_engine) == this->eng_list.end()) { // previously selected engine didn't pass the filter, select the first engine of the list + this->SelectEngine(this->eng_list[0]); } } @@ -1130,9 +1256,7 @@ struct BuildVehicleWindow : Window { int num_engines = 0; int num_wagons = 0; - this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number); - - this->eng_list.Clear(); + 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, @@ -1144,13 +1268,13 @@ struct BuildVehicleWindow : Window { EngineID eid = e->index; const RailVehicleInfo *rvi = &e->u.rail; - if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; + if (this->filter.railtype != INVALID_RAILTYPE && !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; + this->eng_list.push_back(eid); if (rvi->railveh_type != RAILVEH_WAGON) { num_engines++; @@ -1161,7 +1285,7 @@ struct BuildVehicleWindow : Window { if (eid == this->sel_engine) sel_id = eid; } - this->sel_engine = sel_id; + this->SelectEngine(sel_id); /* make engines first, and then wagons, sorted by selected sort_criteria */ _engine_sort_direction = false; @@ -1180,37 +1304,38 @@ struct BuildVehicleWindow : Window { { EngineID sel_id = INVALID_ENGINE; - this->eng_list.Clear(); + 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 (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue; + + this->eng_list.push_back(eid); if (eid == this->sel_engine) sel_id = eid; } - this->sel_engine = sel_id; + this->SelectEngine(sel_id); } /* Figure out what ship EngineIDs to put in the list */ void GenerateBuildShipList() { EngineID sel_id = INVALID_ENGINE; - this->eng_list.Clear(); + 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; + this->eng_list.push_back(eid); if (eid == this->sel_engine) sel_id = eid; } - this->sel_engine = sel_id; + this->SelectEngine(sel_id); } /* Figure out what aircraft EngineIDs to put in the list */ @@ -1218,9 +1343,9 @@ struct BuildVehicleWindow : Window { { EngineID sel_id = INVALID_ENGINE; - this->eng_list.Clear(); + this->eng_list.clear(); - const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number); + const Station *st = this->listview_mode ? nullptr : Station::GetByTile(this->window_number); /* Make list of all available planes. * Also check to see if the previously selected plane is still available, @@ -1234,22 +1359,26 @@ struct BuildVehicleWindow : Window { /* 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; + this->eng_list.push_back(eid); if (eid == this->sel_engine) sel_id = eid; } - this->sel_engine = sel_id; + this->SelectEngine(sel_id); } /* Generate the list of vehicles */ void GenerateBuildList() { if (!this->eng_list.NeedRebuild()) return; + + /* Update filter type in case the road/railtype of the depot got converted */ + this->UpdateFilterByTile(); + switch (this->vehicle_type) { default: NOT_REACHED(); case VEH_TRAIN: this->GenerateBuildTrainList(); - this->eng_list.Compact(); + this->eng_list.shrink_to_fit(); this->eng_list.RebuildDone(); return; // trains should not reach the last sorting case VEH_ROAD: @@ -1268,11 +1397,11 @@ struct BuildVehicleWindow : Window { _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.shrink_to_fit(); this->eng_list.RebuildDone(); } - void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BV_SORT_ASCENDING_DESCENDING: @@ -1292,8 +1421,8 @@ struct BuildVehicleWindow : Window { 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; + size_t num_items = this->eng_list.size(); + this->SelectEngine((i < num_items) ? this->eng_list[i] : INVALID_ENGINE); this->SetDirty(); if (_ctrl_pressed) { this->OnClick(pt, WID_BV_SHOW_HIDE, 1); @@ -1312,8 +1441,8 @@ struct BuildVehicleWindow : Window { break; case WID_BV_SHOW_HIDE: { - const Engine *e = (this->sel_engine == INVALID_ENGINE) ? NULL : Engine::Get(this->sel_engine); - if (e != NULL) { + const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine); + if (e != nullptr) { DoCommandP(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); } break; @@ -1323,7 +1452,9 @@ struct BuildVehicleWindow : Window { 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); + CargoID cargo = this->cargo_filter[this->cargo_filter_criteria]; + if (cargo == CF_ANY) cargo = CF_NONE; + DoCommandP(this->window_number, sel_eng | (cargo << 24), 0, GetCmdBuildVeh(this->vehicle_type), callback); } break; } @@ -1345,7 +1476,7 @@ struct BuildVehicleWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ @@ -1358,13 +1489,16 @@ struct BuildVehicleWindow : Window { this->eng_list.ForceRebuild(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { 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 if (this->vehicle_type == VEH_ROAD && !this->listview_mode) { + const RoadTypeInfo *rti = GetRoadTypeInfo(this->filter.roadtype); + 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); } @@ -1379,8 +1513,8 @@ struct BuildVehicleWindow : Window { 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)) { + const Engine *e = (this->sel_engine == INVALID_ENGINE) ? nullptr : Engine::Get(this->sel_engine); + if (e != nullptr && 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); @@ -1390,7 +1524,7 @@ struct BuildVehicleWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BV_LIST: @@ -1411,6 +1545,13 @@ struct BuildVehicleWindow : Window { break; } + case WID_BV_BUILD: + *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type); + *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type)); + size->width += padding.width; + size->height += padding.height; + 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)); @@ -1420,11 +1561,11 @@ struct BuildVehicleWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { 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); + 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(), (uint)this->eng_list.size()), this->sel_engine, false, DEFAULT_GROUP); break; case WID_BV_SORT_ASCENDING_DESCENDING: @@ -1433,10 +1574,10 @@ struct BuildVehicleWindow : Window { } } - virtual void OnPaint() + void OnPaint() override { this->GenerateBuildList(); - this->vscroll->SetCount(this->eng_list.Length()); + this->vscroll->SetCount((uint)this->eng_list.size()); this->SetWidgetsDisabledState(this->sel_engine == INVALID_ENGINE, WID_BV_SHOW_HIDE, WID_BV_BUILD, WID_BV_RENAME, WIDGET_LIST_END); @@ -1448,7 +1589,7 @@ struct BuildVehicleWindow : Window { 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); + nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine, this->te); 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. @@ -1460,14 +1601,14 @@ struct BuildVehicleWindow : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; - DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str); + DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), nullptr, str); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_BV_SORT_DROPDOWN: @@ -1485,13 +1626,14 @@ struct BuildVehicleWindow : Window { /* 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(); + this->SelectEngine(this->sel_engine); } break; } this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); } diff --git a/src/cargo_type.h b/src/cargo_type.h index 79d1c84f46..78c04ae727 100644 --- a/src/cargo_type.h +++ b/src/cargo_type.h @@ -145,12 +145,11 @@ public: /** Types of cargo source and destination */ -enum SourceType { +enum SourceType : byte { 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 diff --git a/src/cargoaction.cpp b/src/cargoaction.cpp index 96ddc3708e..73908d3390 100644 --- a/src/cargoaction.cpp +++ b/src/cargoaction.cpp @@ -121,7 +121,7 @@ bool CargoDelivery::operator()(CargoPacket *cp) bool CargoLoad::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); - if (cp_new == NULL) return false; + if (cp_new == nullptr) return false; cp_new->SetLoadPlace(this->load_place); this->source->RemoveFromCache(cp_new, cp_new->Count()); this->destination->Append(cp_new, VehicleCargoList::MTA_KEEP); @@ -136,7 +136,7 @@ bool CargoLoad::operator()(CargoPacket *cp) bool CargoReservation::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); - if (cp_new == NULL) return false; + if (cp_new == nullptr) return false; cp_new->SetLoadPlace(this->load_place); this->source->reserved_count += cp_new->Count(); this->source->RemoveFromCache(cp_new, cp_new->Count()); @@ -152,7 +152,7 @@ bool CargoReservation::operator()(CargoPacket *cp) bool CargoReturn::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); - if (cp_new == NULL) cp_new = cp; + if (cp_new == nullptr) 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(); @@ -162,13 +162,13 @@ bool CargoReturn::operator()(CargoPacket *cp) /** * Transfers some cargo from a vehicle to a station. - * @param cp Packet to be transfered. + * @param cp Packet to be transferred. * @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; + if (cp_new == nullptr) 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()); @@ -183,7 +183,7 @@ bool CargoTransfer::operator()(CargoPacket *cp) bool CargoShift::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); - if (cp_new == NULL) cp_new = cp; + if (cp_new == nullptr) 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; @@ -197,7 +197,7 @@ bool CargoShift::operator()(CargoPacket *cp) bool StationCargoReroute::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); - if (cp_new == NULL) cp_new = cp; + if (cp_new == nullptr) 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) { @@ -220,7 +220,7 @@ bool StationCargoReroute::operator()(CargoPacket *cp) bool VehicleCargoReroute::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); - if (cp_new == NULL) cp_new = cp; + if (cp_new == nullptr) 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)); } diff --git a/src/cargomonitor.cpp b/src/cargomonitor.cpp index 40a029ac53..82f8d8e4cb 100644 --- a/src/cargomonitor.cpp +++ b/src/cargomonitor.cpp @@ -151,9 +151,9 @@ void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, Sour 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); + for (Industry *ind : st->industries_near) { + if (ind->index != dest) continue; + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, ind->index); CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); if (iter != _cargo_deliveries.end()) iter->second += amount; } diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 9e699d6f42..846af4680d 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -86,11 +86,11 @@ CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, T /** * 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! + * @return Split off part, or nullptr if no packet could be allocated! */ CargoPacket *CargoPacket::Split(uint new_size) { - if (!CargoPacket::CanAllocateItem()) return NULL; + if (!CargoPacket::CanAllocateItem()) return nullptr; 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); @@ -248,12 +248,12 @@ template * @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 cp != nullptr * @pre action == MTA_LOAD || (action == MTA_KEEP && this->designation_counts[MTA_LOAD] == 0) */ void VehicleCargoList::Append(CargoPacket *cp, MoveToAction action) { - assert(cp != NULL); + assert(cp != nullptr); assert(action == MTA_LOAD || (action == MTA_KEEP && this->action_counts[MTA_LOAD] == 0)); this->AddToMeta(cp, action); @@ -395,7 +395,7 @@ void VehicleCargoList::AgeCargo() } /** - * Sets loaded_at_xy to the current station for all cargo to be transfered. + * Sets loaded_at_xy to the current station for all cargo to be transferred. * 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. @@ -689,11 +689,11 @@ uint VehicleCargoList::Reroute(uint max_move, VehicleCargoList *dest, StationID * @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 + * @pre cp != nullptr */ void StationCargoList::Append(CargoPacket *cp, StationID next) { - assert(cp != NULL); + assert(cp != nullptr); this->AddToCache(cp); StationCargoPacketMap::List &list = this->packets[next]; @@ -776,7 +776,7 @@ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_ uint prev_count = this->count; uint moved = 0; uint loop = 0; - bool do_count = cargo_per_source != NULL; + bool do_count = cargo_per_source != nullptr; while (max_move > moved) { for (Iterator it(this->packets.begin()); it != this->packets.end();) { CargoPacket *cp = *it; diff --git a/src/cargopacket.h b/src/cargopacket.h index 0ed4fd9bbc..4eda6a79ae 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -43,13 +43,13 @@ typedef uint32 TileOrStationID; */ 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). + 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. + SourceType 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. @@ -286,7 +286,7 @@ protected: 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. + uint action_counts[NUM_MOVE_TO_ACTION]; ///< Counts of cargo to be transferred, delivered, kept and loaded. template void ShiftCargo(Taction action); @@ -549,7 +549,7 @@ public: 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 Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr); uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); /** diff --git a/src/cargotype.cpp b/src/cargotype.cpp index 6cc02f63a3..4a2dd6a32d 100644 --- a/src/cargotype.cpp +++ b/src/cargotype.cpp @@ -14,7 +14,7 @@ #include "newgrf_cargo.h" #include "string_func.h" #include "strings_func.h" -#include "core/sort_func.hpp" +#include #include "table/sprites.h" #include "table/strings.h" @@ -132,56 +132,54 @@ SpriteID CargoSpec::GetCargoIcon() const 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. +std::vector _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name. +uint8 _sorted_standard_cargo_specs_size; ///< Number of standard cargo specifications stored in the _sorted_cargo_specs array. /** Sort cargo specifications by their name. */ -static int CDECL CargoSpecNameSorter(const CargoSpec * const *a, const CargoSpec * const *b) +static bool 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)); + 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); + return (res != 0) ? res < 0 : (a->bitnum < b->bitnum); } /** Sort cargo specifications by their cargo class. */ -static int CDECL CargoSpecClassSorter(const CargoSpec * const *a, const CargoSpec * const *b) +static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * const &b) { - int res = ((*b)->classes & CC_PASSENGERS) - ((*a)->classes & CC_PASSENGERS); + int res = (b->classes & CC_PASSENGERS) - (a->classes & CC_PASSENGERS); if (res == 0) { - res = ((*b)->classes & CC_MAIL) - ((*a)->classes & CC_MAIL); + res = (b->classes & CC_MAIL) - (a->classes & CC_MAIL); if (res == 0) { - res = ((*a)->classes & CC_SPECIAL) - ((*b)->classes & CC_SPECIAL); + res = (a->classes & CC_SPECIAL) - (b->classes & CC_SPECIAL); if (res == 0) { return CargoSpecNameSorter(a, b); } } } - return res; + return res < 0; } /** Initialize the list of sorted cargo specifications. */ void InitializeSortedCargoSpecs() { - _sorted_cargo_specs_size = 0; + _sorted_cargo_specs.clear(); 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++; + _sorted_cargo_specs.push_back(cargo); } /* Sort cargo specifications by cargo class and name. */ - QSortT(_sorted_cargo_specs, _sorted_cargo_specs_size, &CargoSpecClassSorter); + std::sort(_sorted_cargo_specs.begin(), _sorted_cargo_specs.end(), &CargoSpecClassSorter); _standard_cargo_mask = 0; diff --git a/src/cargotype.h b/src/cargotype.h index 71cd932bbf..aa67561d88 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -17,6 +17,7 @@ #include "gfx_type.h" #include "strings_type.h" #include "landscape_type.h" +#include /** Globally unique label of a cargo type. */ typedef uint32 CargoLabel; @@ -137,8 +138,7 @@ 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 std::vector _sorted_cargo_specs; extern uint8 _sorted_standard_cargo_specs_size; /** @@ -152,7 +152,7 @@ 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++) \ +#define FOR_ALL_CARGOSPECS_FROM(var, start) for (size_t cargospec_index = start; var = nullptr, cargospec_index < CargoSpec::GetArraySize(); cargospec_index++) \ if ((var = CargoSpec::Get(cargospec_index))->IsValid()) #define FOR_ALL_CARGOSPECS(var) FOR_ALL_CARGOSPECS_FROM(var, 0) @@ -163,7 +163,7 @@ static inline bool IsCargoInClass(CargoID c, CargoClass cc) * @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++) +#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. diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 1bbf68a868..3d338e91a6 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -186,9 +186,9 @@ struct CheatEntry { 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_EXTRA_DYNAMITE, &_cheats.magic_bulldozer.value, &_cheats.magic_bulldozer.been_used, nullptr }, + {SLE_BOOL, STR_CHEAT_CROSSINGTUNNELS, &_cheats.crossing_tunnels.value, &_cheats.crossing_tunnels.been_used, nullptr }, + {SLE_BOOL, STR_CHEAT_NO_JETCRASH, &_cheats.no_jetcrash.value, &_cheats.no_jetcrash.been_used, nullptr }, {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 }, @@ -221,7 +221,7 @@ struct CheatWindow : Window { this->InitNested(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_C_PANEL) return; @@ -283,7 +283,7 @@ struct CheatWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_C_PANEL) return; @@ -330,7 +330,7 @@ struct CheatWindow : Window { 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) + void OnClick(Point pt, int widget, int click_count) override { const NWidgetBase *wid = this->GetWidget(WID_C_PANEL); uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / this->line_height; @@ -365,7 +365,7 @@ struct CheatWindow : Window { switch (ce->type) { case SLE_BOOL: value ^= 1; - if (ce->proc != NULL) ce->proc(value, 0); + if (ce->proc != nullptr) ce->proc(value, 0); break; default: @@ -384,16 +384,16 @@ struct CheatWindow : Window { this->SetDirty(); } - virtual void OnTimeout() + void OnTimeout() override { this->clicked = 0; this->SetDirty(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { /* Was 'cancel' pressed or nothing entered? */ - if (str == NULL || StrEmpty(str)) return; + if (str == nullptr || StrEmpty(str)) return; const CheatEntry *ce = &_cheats_ui[clicked_widget]; int oldvalue = (int32)ReadValue(ce->variable, ce->type); diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp index c4aeb3a52e..bfe5c66b3c 100644 --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -389,15 +389,15 @@ 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 + nullptr, ///< 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 + nullptr, ///< click_tile_proc + nullptr, ///< animate_tile_proc TileLoop_Clear, ///< tile_loop_proc ChangeTileOwner_Clear, ///< change_tile_owner_proc - NULL, ///< add_produced_cargo_proc - NULL, ///< vehicle_enter_tile_proc + nullptr, ///< add_produced_cargo_proc + nullptr, ///< vehicle_enter_tile_proc GetFoundation_Clear, ///< get_foundation_proc TerraformTile_Clear, ///< terraform_tile_proc }; diff --git a/src/command.cpp b/src/command.cpp index ab7c444992..0d78c15c51 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -72,6 +72,8 @@ CommandProc CmdBuildRoad; CommandProc CmdBuildRoadDepot; +CommandProc CmdConvertRoad; + CommandProc CmdBuildAirport; CommandProc CmdBuildDock; @@ -218,7 +220,7 @@ static const Command _command_proc_table[] = { 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(CmdLandscapeClear, CMD_DEITY, 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 @@ -239,6 +241,7 @@ static const Command _command_proc_table[] = { 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(CmdConvertRoad, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_ROAD 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 @@ -287,7 +290,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdTurnRoadVeh, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_TURN_ROADVEH - DEF_CMD(CmdPause, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_PAUSE + DEF_CMD(CmdPause, CMD_SERVER | CMD_NO_EST, 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 @@ -311,7 +314,7 @@ static const Command _command_proc_table[] = { 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(CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID | CMD_NO_EST, 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 @@ -365,7 +368,7 @@ static const Command _command_proc_table[] = { }; /*! - * This function range-checks a cmd, and checks if the cmd is not NULL + * This function range-checks a cmd, and checks if the cmd is not nullptr * * @param cmd The integer value of a command * @return true if the command is valid (and got a CommandProc function) @@ -374,7 +377,7 @@ bool IsValidCommand(uint32 cmd) { cmd &= CMD_ID_MASK; - return cmd < lengthof(_command_proc_table) && _command_proc_table[cmd].proc != NULL; + return cmd < lengthof(_command_proc_table) && _command_proc_table[cmd].proc != nullptr; } /*! @@ -473,7 +476,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, /* 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(); + if (_docommand_recursive == 1) _cleared_object_areas.clear(); SetTownRatingTestMode(true); res = proc(tile, flags & ~DC_EXEC, p1, p2, text); SetTownRatingTestMode(false); @@ -496,7 +499,7 @@ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, /* 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(); + if (_docommand_recursive == 1) _cleared_object_areas.clear(); res = proc(tile, flags, p1, p2, text); if (res.Failed()) { error: @@ -555,14 +558,14 @@ bool DoCommandP(const CommandContainer *container, bool my_cmd) 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. + * local user presses shift while doing something. * 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 && + !(GetCommandFlags(cmd) & CMD_NO_EST) && !(cmd & CMD_NO_ESTIMATE); /* We're only sending the command, so don't do @@ -578,10 +581,8 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac 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()) { @@ -601,7 +602,7 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallbac ShowCostOrIncomeAnimation(x, y, GetSlopePixelZ(x, y), res.GetCost()); } - if (!estimate_only && !only_sending && callback != NULL) { + if (!estimate_only && !only_sending && callback != nullptr) { callback(res, tile, p1, p2, cmd); } @@ -644,17 +645,15 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, 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); + assert(proc != nullptr); /* 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); @@ -669,13 +668,13 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, return_dcpi(CMD_ERROR); } - Backup cur_company(_current_company, FILE_LINE); + 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(); + _cleared_object_areas.clear(); SetTownRatingTestMode(true); BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE); CommandCost res = proc(tile, flags, p1, p2, text); @@ -701,7 +700,6 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, 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 @@ -716,12 +714,11 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, * 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(); + _cleared_object_areas.clear(); BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND); CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND); @@ -761,7 +758,7 @@ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, /* update last build coordinate of company. */ if (tile != 0) { Company *c = Company::GetIfValid(_current_company); - if (c != NULL) c->last_build_coordinate = tile; + if (c != nullptr) c->last_build_coordinate = tile; } /* Send Tile Number to Watching Company Windows */ diff --git a/src/command_func.h b/src/command_func.h index 3369475675..7a6b6d6bbe 100644 --- a/src/command_func.h +++ b/src/command_func.h @@ -34,17 +34,15 @@ static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID); */ #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(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = nullptr); 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(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = nullptr, const char *text = nullptr, 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; diff --git a/src/command_type.h b/src/command_type.h index e0188f8723..eb92d61c60 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -36,25 +36,25 @@ 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) {} + CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(nullptr), 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) {} + explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_grffile(nullptr), 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) {} + explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(nullptr), 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) {} + CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true), textref_stack_grffile(nullptr), textref_stack_size(0) {} /** @@ -202,6 +202,7 @@ enum Commands { 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_CONVERT_ROAD, ///< convert a road type CMD_BUILD_AIRPORT, ///< build an airport @@ -396,6 +397,7 @@ enum CommandFlags { 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 + CMD_NO_EST = 0x400, ///< the command is never estimated. }; DECLARE_ENUM_AS_BIT_SET(CommandFlags) diff --git a/src/commands_gui.cpp b/src/commands_gui.cpp index a38accd96b..baed1216e1 100644 --- a/src/commands_gui.cpp +++ b/src/commands_gui.cpp @@ -1,6 +1,5 @@ /* $Id: commands_gui.cpp 21909 2011-01-26 08:14:36Z xi $ */ -#ifdef ENABLE_NETWORK #include "stdafx.h" #include #include "widgets/dropdown_type.h" //fillrect @@ -641,7 +640,6 @@ void AccountLogin(CommunityName community){ static GetHTTPContent login(uri); login.InitiateLoginSequence(); } -#endif /* ENABLE_NETWORK */ //ini login hadling void IniLoginInitiate(){ diff --git a/src/company_base.h b/src/company_base.h index 30f5520ce9..2b5a7c6304 100644 --- a/src/company_base.h +++ b/src/company_base.h @@ -45,6 +45,9 @@ struct CompanyInfrastructure { for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) total += this->rail[rt]; return total; } + + uint32 GetRoadTotal() const; + uint32 GetTramTotal() const; }; typedef Pool CompanyPool; @@ -74,7 +77,7 @@ struct CompanyProperties { 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. + Owner 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. @@ -100,7 +103,7 @@ struct CompanyProperties { // 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), + : name_2(0), name_1(0), name(nullptr), president_name_1(0), president_name_2(0), president_name(nullptr), 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), @@ -145,7 +148,7 @@ struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { static inline bool IsValidAiID(size_t index) { const Company *c = Company::GetIfValid(index); - return c != NULL && c->is_ai; + return c != nullptr && c->is_ai; } /** @@ -157,7 +160,7 @@ struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { static inline bool IsValidHumanID(size_t index) { const Company *c = Company::GetIfValid(index); - return c != NULL && !c->is_ai; + return c != nullptr && !c->is_ai; } /** diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 9e9de2a07f..e74a897c75 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -44,8 +44,8 @@ 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. +CompanyID _local_company; ///< Company controlled by the human player at this client. Can also be #COMPANY_SPECTATOR. +CompanyID _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 @@ -112,10 +112,8 @@ void SetLocalCompany(CompanyID new_company) /* 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()); @@ -203,7 +201,7 @@ bool CheckCompanyHasMoney(CommandCost &cost) { if (cost.GetCost() > 0) { const Company *c = Company::GetIfValid(_current_company); - if (c != NULL && cost.GetCost() > c->money) { + if (c != nullptr && cost.GetCost() > c->money) { SetDParam(0, cost.GetCost()); cost.MakeError(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY); return false; @@ -249,7 +247,7 @@ static void SubtractMoneyFromAnyCompany(Company *c, CommandCost cost) void SubtractMoneyFromCompany(CommandCost cost) { Company *c = Company::GetIfValid(_current_company); - if (c != NULL) SubtractMoneyFromAnyCompany(c, cost); + if (c != nullptr) SubtractMoneyFromAnyCompany(c, cost); } /** @@ -363,7 +361,7 @@ static void GenerateCompanyName(Company *c) StringID str; uint32 strp; - if (t->name == NULL && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) { + if (t->name == nullptr && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) { str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START; strp = t->townnameparts; @@ -549,7 +547,7 @@ void ResetCompanyLivery(Company *c) */ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) { - if (!Company::CanAllocateItem()) return NULL; + if (!Company::CanAllocateItem()) return nullptr; /* we have to generate colour before this company is valid */ Colours colour = GenerateCompanyColour(); @@ -558,7 +556,7 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) if (company == INVALID_COMPANY) { c = new Company(STR_SV_UNNAMED, is_ai); } else { - if (Company::IsValidID(company)) return NULL; + if (Company::IsValidID(company)) return nullptr; c = new (company) Company(STR_SV_UNNAMED, is_ai); } @@ -572,7 +570,7 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) 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->avail_roadtypes = GetCompanyRoadTypes(c->index); c->inaugurated_year = _cur_year; RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false); // create a random company manager face @@ -617,11 +615,9 @@ void StartupCompanies() } /** Start a new competitor company if possible. */ -static void MaybeStartNewCompany() +static bool MaybeStartNewCompany() { -#ifdef ENABLE_NETWORK - if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return; -#endif /* ENABLE_NETWORK */ + if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return false; Company *c; @@ -634,8 +630,10 @@ static void MaybeStartNewCompany() 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); + return DoCommandP(0, CCA_NEW_AI | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL); } + + return false; } /** Initialize the pool of companies. */ @@ -694,7 +692,7 @@ static void HandleBankruptcyTakeover(Company *c) /* Did we ask everyone for bankruptcy? If so, bail out. */ if (c->bankrupt_asked == MAX_UVALUE(CompanyMask)) return; - Company *c2, *best = NULL; + Company *c2, *best = nullptr; int32 best_performance = -1; /* Ask the company with the highest performance history first */ @@ -730,17 +728,25 @@ void OnTick_Companies() if (_game_mode == GM_EDITOR) return; Company *c = Company::GetIfValid(_cur_company_tick_index); - if (c != NULL) { + if (c != nullptr) { 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; + /* AI::GetStartNextTime() can return 0. */ + _next_competitor_start = max(1, AI::GetStartNextTime() * DAY_TICKS); } - if (AI::CanStartNew() && _game_mode != GM_MENU && --_next_competitor_start == 0) { - MaybeStartNewCompany(); + if (_game_mode != GM_MENU && AI::CanStartNew() && --_next_competitor_start == 0) { + /* Allow multiple AIs to possibly start in the same tick. */ + do { + if (!MaybeStartNewCompany()) break; + + /* In networking mode, we can only send a command to start but it + * didn't execute yet, so we cannot loop. */ + if (_networking) break; + } while (AI::GetStartNextTime() == 0); } _cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES; @@ -775,14 +781,14 @@ void CompaniesYearlyLoop() /** * Fill the CompanyNewsInformation struct with the required data. * @param c the current company. - * @param other the other company (use \c NULL if not relevant). + * @param other the other company (use \c nullptr 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) { + if (other == nullptr) { *this->other_company_name = '\0'; } else { SetDParam(0, other->index); @@ -804,9 +810,7 @@ void CompanyNewsInformation::FillData(const Company *c, const Company *other) */ void CompanyAdminUpdate(const Company *company) { -#ifdef ENABLE_NETWORK if (_network_server) NetworkAdminCompanyUpdate(company); -#endif /* ENABLE_NETWORK */ } /** @@ -816,9 +820,7 @@ void CompanyAdminUpdate(const Company *company) */ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason) { -#ifdef ENABLE_NETWORK if (_network_server) NetworkAdminCompanyRemove(company_id, (AdminCompanyRemoveReason)reason); -#endif /* ENABLE_NETWORK */ } /** @@ -843,7 +845,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /* 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(); @@ -853,8 +854,8 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /* 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(); + * So only allow a nullptr client info in that case. */ + if (ci == nullptr) return CommandCost(); #endif /* NOT DEBUG_DUMP_COMMANDS */ /* Delete multiplayer progress bar */ @@ -863,7 +864,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Company *c = DoStartupNewCompany(false); /* A new company could not be created, revert to being a spectator */ - if (c == NULL) { + if (c == nullptr) { if (_network_server) { ci->client_playas = COMPANY_SPECTATOR; NetworkUpdateClientInfo(ci->client_id); @@ -887,7 +888,6 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } NetworkServerNewCompany(c, ci); -#endif /* ENABLE_NETWORK */ break; } @@ -896,9 +896,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 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 */ + if (c != nullptr) NetworkServerNewCompany(c, nullptr); break; } @@ -907,7 +905,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (reason >= CRR_END) return CMD_ERROR; Company *c = Company::GetIfValid(company_id); - if (c == NULL) return CMD_ERROR; + if (c == nullptr) return CMD_ERROR; if (!(flags & DC_EXEC)) return CommandCost(); @@ -1079,7 +1077,7 @@ static bool IsUniqueCompanyName(const char *name) const Company *c; FOR_ALL_COMPANIES(c) { - if (c->name != NULL && strcmp(c->name, name) == 0) return false; + if (c->name != nullptr && strcmp(c->name, name) == 0) return false; } return true; @@ -1106,7 +1104,7 @@ CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { Company *c = Company::Get(_current_company); free(c->name); - c->name = reset ? NULL : stredup(text); + c->name = reset ? nullptr : stredup(text); MarkWholeScreenDirty(); InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); CompanyAdminUpdate(c); @@ -1125,7 +1123,7 @@ 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; + if (c->president_name != nullptr && strcmp(c->president_name, name) == 0) return false; } return true; @@ -1154,11 +1152,11 @@ CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, u free(c->president_name); if (reset) { - c->president_name = NULL; + c->president_name = nullptr; } else { c->president_name = stredup(text); - if (c->name_1 == STR_SV_UNNAMED && c->name == NULL) { + if (c->name_1 == STR_SV_UNNAMED && c->name == nullptr) { char buf[80]; seprintf(buf, lastof(buf), "%s Transport", text); @@ -1175,13 +1173,13 @@ CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, u /** * Get the service interval for the given company and vehicle type. - * @param c The company, or NULL for client-default settings. + * @param c The company, or nullptr 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; + const VehicleDefaultSettings *vds = (c == nullptr) ? &_settings_client.company.vehicle : &c->settings.vehicle; switch (type) { default: NOT_REACHED(); case VEH_TRAIN: return vds->servint_trains; @@ -1190,3 +1188,29 @@ int CompanyServiceInterval(const Company *c, VehicleType type) case VEH_SHIP: return vds->servint_ships; } } + +/** + * Get total sum of all owned road bits. + * @return Combined total road road bits. + */ +uint32 CompanyInfrastructure::GetRoadTotal() const +{ + uint32 total = 0; + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (RoadTypeIsRoad(rt)) total += this->road[rt]; + } + return total; +} + +/** + * Get total sum of all owned tram bits. + * @return Combined total of tram road bits. + */ +uint32 CompanyInfrastructure::GetTramTotal() const +{ + uint32 total = 0; + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (RoadTypeIsTram(rt)) total += this->road[rt]; + } + return total; +} diff --git a/src/company_func.h b/src/company_func.h index 128bd5916e..1b5d2a49fa 100644 --- a/src/company_func.h +++ b/src/company_func.h @@ -33,8 +33,8 @@ CommandCost CheckOwnership(Owner owner, TileIndex tile = 0); CommandCost CheckTileOwnership(TileIndex tile); void CargoResetPeriods(Company *c); -extern CompanyByte _local_company; -extern CompanyByte _current_company; +extern CompanyID _local_company; +extern CompanyID _current_company; extern Colours _company_colours[MAX_COMPANIES]; extern CompanyManagerFace _company_manager_face; diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 3c287d9001..304a51f184 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -30,6 +30,7 @@ #include "core/geometry_func.hpp" #include "object_type.h" #include "rail.h" +#include "road.h" #include "engine_base.h" #include "window_func.h" #include "road_func.h" @@ -284,7 +285,7 @@ struct CompanyFinancesWindow : Window { this->owner = (Owner)this->window_number; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_CF_CAPTION: @@ -303,7 +304,7 @@ struct CompanyFinancesWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { int type = _settings_client.gui.expenses_layout; switch (widget) { @@ -331,7 +332,7 @@ struct CompanyFinancesWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_CF_EXPS_CATEGORY: @@ -392,7 +393,7 @@ struct CompanyFinancesWindow : Window { this->GetWidget(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane); } - virtual void OnPaint() + void OnPaint() override { if (!this->IsShaded()) { if (!this->small) { @@ -422,7 +423,7 @@ struct CompanyFinancesWindow : Window { this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_CF_TOGGLE_SIZE: // toggle size @@ -451,7 +452,7 @@ struct CompanyFinancesWindow : Window { } } - virtual void OnHundredthTick() + void OnHundredthTick() override { const Company *c = Company::Get((CompanyID)this->window_number); if (c->money > CompanyFinancesWindow::max_money) { @@ -519,24 +520,22 @@ 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 + uint Height(uint width) const override { return max(FONT_HEIGHT_NORMAL, ScaleGUITrad(12) + 2); } - bool Selectable() const + bool Selectable() const override { return true; } - void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override { bool rtl = _current_text_dir == TD_RTL; int height = bottom - top; @@ -564,14 +563,14 @@ private: uint rows; uint line_height; GUIGroupList groups; - SmallVector indents; + std::vector indents; Scrollbar *vscroll; void ShowColourDropDownMenu(uint32 widget) { uint32 used_colours = 0; const Company *c; - const Livery *livery, *default_livery = NULL; + const Livery *livery, *default_livery = nullptr; bool primary = widget == WID_SCL_PRI_COL_DROPDOWN; byte default_col; @@ -604,49 +603,49 @@ private: } } - DropDownList *list = new DropDownList(); - if (default_livery != NULL) { + DropDownList list; + if (default_livery != nullptr) { /* 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); + list.emplace_back(new DropDownListColourItem(default_col, false)); } for (uint i = 0; i < lengthof(_colour_dropdown); i++) { - *list->Append() = new DropDownListColourItem(i, HasBit(used_colours, i)); + list.emplace_back(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); + byte sel = (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) ? (primary ? livery->colour1 : livery->colour2) : default_col; + ShowDropDownList(this, std::move(list), sel, widget); } - static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) + static bool GroupNameSorter(const Group * const &a, const Group * const &b) { - static const Group *last_group[2] = { NULL, NULL }; + static const Group *last_group[2] = { nullptr, nullptr }; static char last_name[2][64] = { "", "" }; - if (*a != last_group[0]) { - last_group[0] = *a; - SetDParam(0, (*a)->index); + 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); + 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; + if (r == 0) return a->index < b->index; + return r < 0; } 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); + for (const Group *g : *source) { + if (g->parent != parent) continue; + this->groups.push_back(g); + this->indents.push_back(indent); + AddChildren(source, g->index, indent + 1); } } @@ -654,8 +653,8 @@ private: { if (!this->groups.NeedRebuild()) return; - this->groups.Clear(); - this->indents.Clear(); + this->groups.clear(); + this->indents.clear(); if (this->livery_class >= LC_GROUP_RAIL) { GUIGroupList list; @@ -664,7 +663,7 @@ private: const Group *g; FOR_ALL_GROUPS(g) { if (g->owner == owner && g->vehicle_type == vtype) { - *list.Append() = g; + list.push_back(g); } } @@ -674,7 +673,7 @@ private: AddChildren(&list, INVALID_GROUP, 0); } - this->groups.Compact(); + this->groups.shrink_to_fit(); this->groups.RebuildDone(); } @@ -688,7 +687,7 @@ private: } } } else { - this->rows = this->groups.Length(); + this->rows = (uint)this->groups.size(); } this->vscroll->SetCount(this->rows); @@ -742,7 +741,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SCL_SPACER_DROPDOWN: { @@ -795,7 +794,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { bool local = (CompanyID)this->window_number == _local_company; @@ -809,7 +808,7 @@ public: this->DrawWidgets(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_SCL_CAPTION: @@ -849,7 +848,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_SCL_MATRIX) return; @@ -904,7 +903,7 @@ public: } } } else { - uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->groups.Length()); + uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->groups.size()); for (uint i = this->vscroll->GetPosition(); i < max; ++i) { const Group *g = this->groups[i]; SetDParam(0, g->index); @@ -913,7 +912,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { /* Livery Class buttons */ @@ -944,7 +943,7 @@ public: this->groups.ForceRebuild(); this->BuildGroupList((CompanyID)this->window_number); - if (this->groups.Length() > 0) { + if (this->groups.size() > 0) { this->sel = this->groups[0]->index; } } @@ -987,12 +986,12 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { bool local = (CompanyID)this->window_number == _local_company; if (!local) return; @@ -1018,7 +1017,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -1031,7 +1030,7 @@ public: if (!Group::IsValidID(this->sel)) { this->sel = INVALID_GROUP; - if (this->groups.Length() > 0) this->sel = this->groups[0]->index; + if (this->groups.size() > 0) this->sel = this->groups[0]->index; } this->SetDirty(); @@ -1102,7 +1101,7 @@ static WindowDesc _select_company_livery_desc( void ShowCompanyLiveryWindow(CompanyID company, GroupID group) { SelectCompanyLiveryWindow *w = (SelectCompanyLiveryWindow *)BringWindowToFrontById(WC_COMPANY_COLOUR, company); - if (w == NULL) { + if (w == nullptr) { new SelectCompanyLiveryWindow(&_select_company_livery_desc, company, group); } else if (group != INVALID_GROUP) { w->SetSelectedGroup(company, group); @@ -1370,7 +1369,7 @@ public: } } - virtual void OnInit() + void OnInit() override { /* Size of the boolean yes/no button. */ Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO)); @@ -1393,7 +1392,7 @@ public: this->number_dim = number_dim; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SCMF_FACE: { @@ -1452,7 +1451,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { /* lower the non-selected gender button */ this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2, WIDGET_LIST_END); @@ -1513,7 +1512,7 @@ public: this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: @@ -1602,7 +1601,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { /* Toggle size, advanced/simple face selection */ @@ -1711,12 +1710,12 @@ public: } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; /* Set a new company manager face number */ if (!StrEmpty(str)) { - this->face = strtoul(str, NULL, 10); + this->face = strtoul(str, nullptr, 10); ScaleAllCompanyManagerFaceBits(this->face); ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO); this->UpdateData(); @@ -1784,6 +1783,10 @@ static const NWidgetPart _nested_company_infrastructure_widgets[] = { 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_TRAM_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_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), @@ -1821,7 +1824,7 @@ struct CompanyInfrastructureWindow : Window void UpdateRailRoadTypes() { this->railtypes = RAILTYPES_NONE; - this->roadtypes = ROADTYPES_ROAD; // Road is always available. + this->roadtypes = ROADTYPES_NONE; /* Find the used railtypes. */ Engine *e; @@ -1834,14 +1837,16 @@ struct CompanyInfrastructureWindow : Window /* Get the date introduced railtypes as well. */ this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY); - /* Tram is only visible when there will be a tram. */ + /* Find the used roadtypes. */ 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; + this->roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes; } + + /* Get the date introduced roadtypes as well. */ + this->roadtypes = AddDateIntroducedRoadTypes(this->roadtypes, MAX_DAY); + this->roadtypes &= ~_roadtypes_hidden_mask; } /** Get total infrastructure maintenance cost. */ @@ -1856,8 +1861,11 @@ struct CompanyInfrastructureWindow : Window } 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]); + uint32 road_total = c->infrastructure.GetRoadTotal(); + uint32 tram_total = c->infrastructure.GetTramTotal(); + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (HasBit(this->roadtypes, rt)) total += RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total); + } total += CanalMaintenanceCost(c->infrastructure.water); total += StationMaintenanceCost(c->infrastructure.station); @@ -1866,7 +1874,7 @@ struct CompanyInfrastructureWindow : Window return total; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_CI_CAPTION: @@ -1875,7 +1883,7 @@ struct CompanyInfrastructureWindow : Window } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { const Company *c = Company::Get((CompanyID)this->window_number); @@ -1885,7 +1893,8 @@ struct CompanyInfrastructureWindow : Window size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width); - for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { + RailType rt; + FOR_ALL_SORTED_RAILTYPES(rt) { if (HasBit(this->railtypes, rt)) { lines++; SetDParam(0, GetRailTypeInfo(rt)->strings.name); @@ -1901,18 +1910,19 @@ struct CompanyInfrastructureWindow : Window break; } - case WID_CI_ROAD_DESC: { - uint lines = 1; + case WID_CI_ROAD_DESC: + case WID_CI_TRAM_DESC: { + uint lines = 0; - size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width); + size->width = max(size->width, GetStringBoundingBox(widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_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); + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { + lines++; + SetDParam(0, GetRoadTypeInfo(rt)->strings.name); + size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT); + } } size->height = max(size->height, lines * FONT_HEIGHT_NORMAL); @@ -1932,6 +1942,7 @@ struct CompanyInfrastructureWindow : Window case WID_CI_RAIL_COUNT: case WID_CI_ROAD_COUNT: + case WID_CI_TRAM_COUNT: case WID_CI_WATER_COUNT: case WID_CI_STATION_COUNT: case WID_CI_TOTAL: { @@ -1945,9 +1956,12 @@ struct CompanyInfrastructureWindow : Window } max_val = max(max_val, c->infrastructure.signal); max_cost = max(max_cost, SignalMaintenanceCost(c->infrastructure.signal)); + uint32 road_total = c->infrastructure.GetRoadTotal(); + uint32 tram_total = c->infrastructure.GetTramTotal(); 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_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total)); + } max_val = max(max_val, c->infrastructure.water); max_cost = max(max_cost, CanalMaintenanceCost(c->infrastructure.water)); @@ -1998,7 +2012,7 @@ struct CompanyInfrastructureWindow : Window } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { const Company *c = Company::Get((CompanyID)this->window_number); int y = r.top; @@ -2043,26 +2057,32 @@ struct CompanyInfrastructureWindow : Window } case WID_CI_ROAD_DESC: - DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT); + case WID_CI_TRAM_DESC: { + DrawString(r.left, r.right, y, widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_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); + /* Draw name of each valid roadtype. */ + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { + SetDParam(0, GetRoadTypeInfo(rt)->strings.name); + DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING); + } } 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])); + case WID_CI_TRAM_COUNT: { + uint32 road_tram_total = widget == WID_CI_ROAD_COUNT ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal(); + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_COUNT)) { + this->DrawCountLine(r, y, c->infrastructure.road[rt], RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_tram_total)); + } } break; + } case WID_CI_WATER_DESC: DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT); @@ -2101,7 +2121,7 @@ struct CompanyInfrastructureWindow : Window * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -2287,7 +2307,7 @@ struct CompanyWindow : Window this->OnInvalidateData(); } - virtual void OnPaint() + void OnPaint() override { const Company *c = Company::Get((CompanyID)this->window_number); bool local = this->window_number == _local_company; @@ -2370,7 +2390,7 @@ struct CompanyWindow : Window this->DrawWidgets(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_C_FACE: { @@ -2432,15 +2452,13 @@ struct CompanyWindow : Window // size->height = 0; // } // 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 + void DrawWidget(const Rect &r, int widget) const override { const Company *c = Company::Get((CompanyID)this->window_number); switch (widget) { @@ -2543,17 +2561,15 @@ struct CompanyWindow : Window 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 + void SetStringParameters(int widget) const override { switch (widget) { case WID_C_CAPTION: @@ -2571,7 +2587,7 @@ struct CompanyWindow : Window } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break; @@ -2639,7 +2655,6 @@ struct CompanyWindow : Window 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; @@ -2652,7 +2667,7 @@ struct CompanyWindow : Window 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); + ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_PASSWORD); } else { /* just send the join command */ NetworkClientRequestMove(company); @@ -2687,17 +2702,16 @@ struct CompanyWindow : Window MarkWholeScreenDirty(); break; } -#endif /* ENABLE_NETWORK */ } } - virtual void OnHundredthTick() + void OnHundredthTick() override { /* redraw the window every now and then */ this->SetDirty(); } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS)) && !_shift_pressed) { ResetObjectToPlace(); @@ -2705,31 +2719,29 @@ struct CompanyWindow : Window } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->RaiseButtons(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) 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); + DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_PRESIDENT), nullptr, 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); + DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), nullptr, str); break; -#ifdef ENABLE_NETWORK case WID_C_COMPANY_JOIN: NetworkClientRequestMove((CompanyID)this->window_number, str); break; -#endif /* ENABLE_NETWORK */ } } @@ -2739,7 +2751,7 @@ struct CompanyWindow : Window * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (this->window_number == _local_company) return; @@ -2798,7 +2810,7 @@ struct BuyCompanyWindow : Window { this->InitNested(window_number); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BC_FACE: @@ -2814,7 +2826,7 @@ struct BuyCompanyWindow : Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_BC_CAPTION: @@ -2824,7 +2836,7 @@ struct BuyCompanyWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_BC_FACE: { @@ -2843,7 +2855,7 @@ struct BuyCompanyWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BC_NO: @@ -2877,7 +2889,7 @@ static const NWidgetPart _nested_buy_company_widgets[] = { }; static WindowDesc _buy_company_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUY_COMPANY, WC_NONE, WDF_CONSTRUCTION, _nested_buy_company_widgets, lengthof(_nested_buy_company_widgets) diff --git a/src/company_type.h b/src/company_type.h index 771e6d8b93..576a57bf16 100644 --- a/src/company_type.h +++ b/src/company_type.h @@ -17,7 +17,7 @@ /** * Enum for all companies/owners. */ -enum Owner { +enum Owner : byte { /* All companies below MAX_COMPANIES are playable * companies, above, they are special, computer controlled 'companies' */ OWNER_BEGIN = 0x00, ///< First owner @@ -45,10 +45,8 @@ static const uint MAX_HISTORY_QUARTERS = 24; ///< The maximum number /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT OwnerByte; typedef Owner CompanyID; -typedef OwnerByte CompanyByte; typedef uint16 CompanyMask; diff --git a/src/console.cpp b/src/console.cpp index 2cf9d96958..eedf604bab 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -32,11 +32,9 @@ FILE *_iconsole_output_file; void IConsoleInit() { - _iconsole_output_file = NULL; -#ifdef ENABLE_NETWORK /* Initialize network only variables */ + _iconsole_output_file = nullptr; _redirect_console_to_client = INVALID_CLIENT_ID; _redirect_console_to_admin = INVALID_ADMIN_ID; -#endif IConsoleGUIInit(); @@ -45,14 +43,14 @@ void IConsoleInit() static void IConsoleWriteToLogFile(const char *string) { - if (_iconsole_output_file != NULL) { + if (_iconsole_output_file != nullptr) { /* 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; + _iconsole_output_file = nullptr; IConsolePrintF(CC_DEFAULT, "cannot write to log file"); } } @@ -60,10 +58,10 @@ static void IConsoleWriteToLogFile(const char *string) bool CloseConsoleLogIfActive() { - if (_iconsole_output_file != NULL) { + if (_iconsole_output_file != nullptr) { IConsolePrintF(CC_DEFAULT, "file output complete"); fclose(_iconsole_output_file); - _iconsole_output_file = NULL; + _iconsole_output_file = nullptr; return true; } @@ -90,7 +88,6 @@ 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); @@ -101,7 +98,6 @@ void IConsolePrint(TextColour colour_code, const char *string) 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 */ @@ -110,9 +106,7 @@ void IConsolePrint(TextColour colour_code, const char *string) 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); @@ -209,22 +203,22 @@ bool GetArgumentInteger(uint32 *value, const char *arg) template void IConsoleAddSorted(T **base, T *item_new) { - if (*base == NULL) { + if (*base == nullptr) { *base = item_new; return; } - T *item_before = NULL; + T *item_before = nullptr; T *item = *base; /* The list is alphabetically sorted, insert the new item at the correct location */ - while (item != NULL) { + while (item != nullptr) { if (strcmp(item->name, item_new->name) > 0) break; // insert here item_before = item; item = item->next; } - if (item_before == NULL) { + if (item_before == nullptr) { *base = item_new; } else { item_before->next = item_new; @@ -257,7 +251,7 @@ void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook * { IConsoleCmd *item_new = MallocT(1); item_new->name = RemoveUnderscores(stredup(name)); - item_new->next = NULL; + item_new->next = nullptr; item_new->proc = proc; item_new->hook = hook; @@ -267,16 +261,16 @@ void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook * /** * 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 + * @return return Cmdstruct of the found command, or nullptr on failure */ IConsoleCmd *IConsoleCmdGet(const char *name) { IConsoleCmd *item; - for (item = _iconsole_cmds; item != NULL; item = item->next) { + for (item = _iconsole_cmds; item != nullptr; item = item->next) { if (strcmp(item->name, name) == 0) return item; } - return NULL; + return nullptr; } /** @@ -286,7 +280,7 @@ IConsoleCmd *IConsoleCmdGet(const char *name) */ void IConsoleAliasRegister(const char *name, const char *cmd) { - if (IConsoleAliasGet(name) != NULL) { + if (IConsoleAliasGet(name) != nullptr) { IConsoleError("an alias with this name already exists; insertion aborted"); return; } @@ -295,7 +289,7 @@ void IConsoleAliasRegister(const char *name, const char *cmd) char *cmd_aliased = stredup(cmd); IConsoleAlias *item_new = MallocT(1); - item_new->next = NULL; + item_new->next = nullptr; item_new->cmdline = cmd_aliased; item_new->name = new_alias; @@ -305,17 +299,17 @@ void IConsoleAliasRegister(const char *name, const char *cmd) /** * 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 + * @return return Aliasstruct of the found alias, or nullptr on failure */ IConsoleAlias *IConsoleAliasGet(const char *name) { IConsoleAlias *item; - for (item = _iconsole_aliases; item != NULL; item = item->next) { + for (item = _iconsole_aliases; item != nullptr; item = item->next) { if (strcmp(item->name, name) == 0) return item; } - return NULL; + return nullptr; } /** * An alias is just another name for a command, or for more commands @@ -484,7 +478,7 @@ void IConsoleCmdExec(const char *cmdstr) } } - for (uint i = 0; i < lengthof(tokens) && tokens[i] != NULL; i++) { + for (uint i = 0; i < lengthof(tokens) && tokens[i] != nullptr; i++) { DEBUG(console, 8, "Token %d is: '%s'", i, tokens[i]); } @@ -495,12 +489,12 @@ void IConsoleCmdExec(const char *cmdstr) */ RemoveUnderscores(tokens[0]); IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]); - if (cmd != NULL) { - ConsoleHookResult chr = (cmd->hook == NULL ? CHR_ALLOW : cmd->hook(true)); + if (cmd != nullptr) { + ConsoleHookResult chr = (cmd->hook == nullptr ? 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 + cmd->proc(0, nullptr); // if command failed, give help } return; @@ -511,7 +505,7 @@ void IConsoleCmdExec(const char *cmdstr) t_index--; IConsoleAlias *alias = IConsoleAliasGet(tokens[0]); - if (alias != NULL) { + if (alias != nullptr) { IConsoleAliasExec(alias, t_index, &tokens[1]); return; } diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 298fd4f98d..cdc6c10e09 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -39,6 +39,7 @@ #include "engine_base.h" #include "game/game.hpp" #include "table/strings.h" +#include #include "safeguards.h" @@ -86,8 +87,6 @@ static ConsoleFileList _console_file_list; ///< File storage cache for the conso * command hooks ****************/ -#ifdef ENABLE_NETWORK - /** * Check network availability and inform in console about failure of detection. * @return Network availability. @@ -159,10 +158,6 @@ DEF_CONSOLE_HOOK(ConHookNoNetwork) return CHR_ALLOW; } -#else -# define ConHookNoNetwork NULL -#endif /* ENABLE_NETWORK */ - DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool) { if (_settings_client.gui.newgrf_developer_tools) { @@ -170,11 +165,7 @@ DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool) 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; } @@ -258,7 +249,7 @@ DEF_CONSOLE_CMD(ConResetTile) * 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. + * @note When only one argument is given it is interpreted 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. @@ -359,7 +350,7 @@ DEF_CONSOLE_CMD(ConLoad) const char *file = argv[1]; _console_file_list.ValidateFileList(); const FiosItem *item = _console_file_list.FindItem(file); - if (item != NULL) { + if (item != nullptr) { if (GetAbstractFileType(item->type) == FT_SAVEGAME) { _switch_mode = SM_LOAD_GAME; _file_to_saveload.SetMode(item->type); @@ -388,7 +379,7 @@ DEF_CONSOLE_CMD(ConRemove) const char *file = argv[1]; _console_file_list.ValidateFileList(); const FiosItem *item = _console_file_list.FindItem(file); - if (item != NULL) { + if (item != nullptr) { if (!FiosDelete(item->name)) { IConsolePrintF(CC_ERROR, "%s: Failed to delete file", file); } @@ -430,7 +421,7 @@ DEF_CONSOLE_CMD(ConChangeDirectory) const char *file = argv[1]; _console_file_list.ValidateFileList(true); const FiosItem *item = _console_file_list.FindItem(file); - if (item != NULL) { + if (item != nullptr) { switch (item->type) { case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT: FiosBrowseTo(item); @@ -458,7 +449,7 @@ DEF_CONSOLE_CMD(ConPrintWorkingDirectory) _console_file_list.ValidateFileList(true); _console_file_list.InvalidateFileList(); - FiosGetDescText(&path, NULL); + FiosGetDescText(&path, nullptr); IConsolePrint(CC_DEFAULT, path); return true; } @@ -479,13 +470,12 @@ DEF_CONSOLE_CMD(ConClearBuffer) /********************************** * 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 + if (strchr(argv, '.') == nullptr && strchr(argv, ':') == nullptr) { // 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 @@ -498,7 +488,7 @@ static bool ConKickOrBan(const char *argv, bool ban) } NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); - if (ci == NULL) { + if (ci == nullptr) { IConsoleError("Invalid client"); return true; } @@ -563,21 +553,20 @@ DEF_CONSOLE_CMD(ConUnBan) /* Try by IP. */ uint index; - for (index = 0; index < _network_ban_list.Length(); index++) { - if (strcmp(_network_ban_list[index], argv[1]) == 0) break; + for (index = 0; index < _network_ban_list.size(); index++) { + if (_network_ban_list[index] == argv[1]) break; } /* Try by index. */ - if (index >= _network_ban_list.Length()) { + if (index >= _network_ban_list.size()) { index = atoi(argv[1]) - 1U; // let it wrap } - if (index < _network_ban_list.Length()) { + if (index < _network_ban_list.size()) { char msg[64]; - seprintf(msg, lastof(msg), "Unbanned %s", _network_ban_list[index]); + seprintf(msg, lastof(msg), "Unbanned %s", _network_ban_list[index].c_str()); IConsolePrint(CC_DEFAULT, msg); - free(_network_ban_list[index]); - _network_ban_list.Erase(_network_ban_list.Get(index)); + _network_ban_list.erase(_network_ban_list.begin() + 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'"); @@ -596,8 +585,8 @@ DEF_CONSOLE_CMD(ConBanList) 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); + for (const auto &entry : _network_ban_list) { + IConsolePrintF(CC_DEFAULT, " %d) %s", i, entry.c_str()); } return true; @@ -700,7 +689,7 @@ DEF_CONSOLE_CMD(ConClientNickChange) return true; } - if (NetworkClientInfo::GetByClientID(client_id) == NULL) { + if (NetworkClientInfo::GetByClientID(client_id) == nullptr) { IConsoleError("Invalid client"); return true; } @@ -771,7 +760,7 @@ DEF_CONSOLE_CMD(ConMoveClient) CompanyID company_id = (CompanyID)(atoi(argv[2]) <= MAX_COMPANIES ? atoi(argv[2]) - 1 : atoi(argv[2])); /* check the client exists */ - if (ci == NULL) { + if (ci == nullptr) { IConsoleError("Invalid client-id, check the command 'clients' for valid client-id's."); return true; } @@ -870,8 +859,7 @@ DEF_CONSOLE_CMD(ConNetworkReconnect) 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; + if (playas < COMPANY_FIRST + 1 || playas > MAX_COMPANIES + 1) return false; break; } @@ -899,8 +887,8 @@ DEF_CONSOLE_CMD(ConNetworkConnect) if (argc < 2) return false; if (_networking) NetworkDisconnect(); // we are in network-mode, first close it! - const char *port = NULL; - const char *company = NULL; + const char *port = nullptr; + const char *company = nullptr; char *ip = argv[1]; /* Default settings: default port and new company */ uint16 rport = NETWORK_DEFAULT_PORT; @@ -909,7 +897,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect) ParseConnectionString(&company, &port, ip); IConsolePrintF(CC_DEFAULT, "Connecting to %s...", ip); - if (company != NULL) { + if (company != nullptr) { join_as = (CompanyID)atoi(company); IConsolePrintF(CC_DEFAULT, " company-no: %d", join_as); @@ -920,7 +908,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect) join_as--; } } - if (port != NULL) { + if (port != nullptr) { rport = atoi(port); IConsolePrintF(CC_DEFAULT, " port: %s", port); } @@ -930,8 +918,6 @@ DEF_CONSOLE_CMD(ConNetworkConnect) return true; } -#endif /* ENABLE_NETWORK */ - /********************************* * script file console commands *********************************/ @@ -947,7 +933,7 @@ DEF_CONSOLE_CMD(ConExec) FILE *script_file = FioFOpenFile(argv[1], "r", BASE_DIR); - if (script_file == NULL) { + if (script_file == nullptr) { if (argc == 2 || atoi(argv[2]) != 0) IConsoleError("script file not found"); return true; } @@ -955,7 +941,7 @@ DEF_CONSOLE_CMD(ConExec) _script_running = true; char cmdline[ICON_CMDLN_SIZE]; - while (_script_running && fgets(cmdline, sizeof(cmdline), script_file) != NULL) { + while (_script_running && fgets(cmdline, sizeof(cmdline), script_file) != nullptr) { /* Remove newline characters from the executing script */ for (char *cmdptr = cmdline; *cmdptr != '\0'; cmdptr++) { if (*cmdptr == '\n' || *cmdptr == '\r') { @@ -1006,7 +992,7 @@ DEF_CONSOLE_CMD(ConScript) IConsolePrintF(CC_DEFAULT, "file output started to: %s", argv[1]); _iconsole_output_file = fopen(argv[1], "ab"); - if (_iconsole_output_file == NULL) IConsoleError("could not open file"); + if (_iconsole_output_file == nullptr) IConsoleError("could not open file"); } return true; @@ -1045,7 +1031,7 @@ DEF_CONSOLE_CMD(ConNewGame) return true; } - StartNewGameWithoutGUI((argc == 2) ? strtoul(argv[1], NULL, 10) : GENERATE_NEW_SEED); + StartNewGameWithoutGUI((argc == 2) ? strtoul(argv[1], nullptr, 10) : GENERATE_NEW_SEED); return true; } @@ -1297,7 +1283,7 @@ DEF_CONSOLE_CMD(ConRescanNewGRF) return true; } - ScanNewGRFFiles(NULL); + ScanNewGRFFiles(nullptr); return true; } @@ -1317,13 +1303,27 @@ DEF_CONSOLE_CMD(ConGetSeed) DEF_CONSOLE_CMD(ConGetDate) { if (argc == 0) { - IConsoleHelp("Returns the current date (day-month-year) of the game. Usage: 'getdate'"); + IConsoleHelp("Returns the current date (year-month-day) of the game. Usage: 'getdate'"); return true; } YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); - IConsolePrintF(CC_DEFAULT, "Date: %d-%d-%d", ymd.day, ymd.month + 1, ymd.year); + IConsolePrintF(CC_DEFAULT, "Date: %04d-%02d-%02d", ymd.year, ymd.month + 1, ymd.day); + return true; +} + +DEF_CONSOLE_CMD(ConGetSysDate) +{ + if (argc == 0) { + IConsoleHelp("Returns the current date (year-month-day) of your system. Usage: 'getsysdate'"); + return true; + } + + time_t t; + time(&t); + auto timeinfo = localtime(&t); + IConsolePrintF(CC_DEFAULT, "System Date: %04d-%02d-%02d %02d:%02d:%02d", timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); return true; } @@ -1340,7 +1340,7 @@ DEF_CONSOLE_CMD(ConAlias) if (argc < 3) return false; alias = IConsoleAliasGet(argv[1]); - if (alias == NULL) { + if (alias == nullptr) { IConsoleAliasRegister(argv[1], argv[2]); } else { free(alias->cmdline); @@ -1362,7 +1362,7 @@ DEF_CONSOLE_CMD(ConScreenShot) if (argc > 3) return false; ScreenshotType type = SC_VIEWPORT; - const char *name = NULL; + const char *name = nullptr; if (argc > 1) { if (strcmp(argv[1], "big") == 0) { @@ -1400,7 +1400,7 @@ DEF_CONSOLE_CMD(ConInfoCmd) if (argc < 2) return false; const IConsoleCmd *cmd = IConsoleCmdGet(argv[1]); - if (cmd == NULL) { + if (cmd == nullptr) { IConsoleError("the given command was not found"); return true; } @@ -1408,7 +1408,7 @@ DEF_CONSOLE_CMD(ConInfoCmd) IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name); IConsolePrintF(CC_DEFAULT, "command proc: %p", cmd->proc); - if (cmd->hook != NULL) IConsoleWarning("command is hooked"); + if (cmd->hook != nullptr) IConsoleWarning("command is hooked"); return true; } @@ -1466,16 +1466,16 @@ DEF_CONSOLE_CMD(ConHelp) RemoveUnderscores(argv[1]); cmd = IConsoleCmdGet(argv[1]); - if (cmd != NULL) { - cmd->proc(0, NULL); + if (cmd != nullptr) { + cmd->proc(0, nullptr); return true; } alias = IConsoleAliasGet(argv[1]); - if (alias != NULL) { + if (alias != nullptr) { cmd = IConsoleCmdGet(alias->cmdline); - if (cmd != NULL) { - cmd->proc(0, NULL); + if (cmd != nullptr) { + cmd->proc(0, nullptr); return true; } IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline); @@ -1505,9 +1505,9 @@ DEF_CONSOLE_CMD(ConListCommands) return true; } - for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != NULL; cmd = cmd->next) { - if (argv[1] == NULL || strstr(cmd->name, argv[1]) != NULL) { - if (cmd->hook == NULL || cmd->hook(false) != CHR_HIDE) IConsolePrintF(CC_DEFAULT, "%s", cmd->name); + for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != nullptr; cmd = cmd->next) { + if (argv[1] == nullptr || strstr(cmd->name, argv[1]) != nullptr) { + if (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE) IConsolePrintF(CC_DEFAULT, "%s", cmd->name); } } @@ -1521,8 +1521,8 @@ DEF_CONSOLE_CMD(ConListAliases) return true; } - for (const IConsoleAlias *alias = _iconsole_aliases; alias != NULL; alias = alias->next) { - if (argv[1] == NULL || strstr(alias->name, argv[1]) != NULL) { + for (const IConsoleAlias *alias = _iconsole_aliases; alias != nullptr; alias = alias->next) { + if (argv[1] == nullptr || strstr(alias->name, argv[1]) != nullptr) { IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name, alias->cmdline); } } @@ -1547,12 +1547,9 @@ DEF_CONSOLE_CMD(ConCompanies) const char *password_state = ""; if (c->is_ai) { password_state = "AI"; - } -#ifdef ENABLE_NETWORK - else if (_network_server) { + } else if (_network_server) { password_state = StrEmpty(_network_company_states[c->index].password) ? "unprotected" : "protected"; } -#endif char colour[512]; GetString(colour, STR_COLOUR_DARK_BLUE + _company_colours[c->index], lastof(colour)); @@ -1569,8 +1566,6 @@ DEF_CONSOLE_CMD(ConCompanies) return true; } -#ifdef ENABLE_NETWORK - DEF_CONSOLE_CMD(ConSay) { if (argc == 0) { @@ -1736,8 +1731,8 @@ static void OutputContentState(const ContentInfo *const ci) DEF_CONSOLE_CMD(ConContent) { - static ContentCallback *cb = NULL; - if (cb == NULL) { + static ContentCallback *cb = nullptr; + if (cb == nullptr) { cb = new ConsoleContentCallback(); _network_content_client.AddCallback(cb); } @@ -1795,7 +1790,7 @@ DEF_CONSOLE_CMD(ConContent) if (strcasecmp(argv[1], "state") == 0) { IConsolePrintF(CC_WHITE, "id, type, state, name"); for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { - if (argc > 2 && strcasestr((*iter)->name, argv[2]) == NULL) continue; + if (argc > 2 && strcasestr((*iter)->name, argv[2]) == nullptr) continue; OutputContentState(*iter); } return true; @@ -1812,7 +1807,6 @@ DEF_CONSOLE_CMD(ConContent) return false; } #endif /* defined(WITH_ZLIB) */ -#endif /* ENABLE_NETWORK */ DEF_CONSOLE_CMD(ConSetting) { @@ -1861,7 +1855,7 @@ DEF_CONSOLE_CMD(ConListSettings) if (argc > 2) return false; - IConsoleListSettings((argc == 2) ? argv[1] : NULL); + IConsoleListSettings((argc == 2) ? argv[1] : nullptr); return true; } @@ -1946,6 +1940,7 @@ void IConsoleStdLibRegister() IConsoleCmdRegister("restart", ConRestart); IConsoleCmdRegister("getseed", ConGetSeed); IConsoleCmdRegister("getdate", ConGetDate); + IConsoleCmdRegister("getsysdate", ConGetSysDate); IConsoleCmdRegister("quit", ConExit); IConsoleCmdRegister("resetengines", ConResetEngines, ConHookNoNetwork); IConsoleCmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork); @@ -1992,7 +1987,7 @@ void IConsoleStdLibRegister() IConsoleAliasRegister("players", "companies"); /* networking functions */ -#ifdef ENABLE_NETWORK + /* Content downloading is only available with ZLIB */ #if defined(WITH_ZLIB) IConsoleCmdRegister("content", ConContent); @@ -2050,7 +2045,6 @@ void IConsoleStdLibRegister() IConsoleAliasRegister("restart_game_year", "setting restart_game_year %+"); IConsoleAliasRegister("min_players", "setting min_active_clients %+"); IConsoleAliasRegister("reload_cfg", "setting reload_cfg %+"); -#endif /* ENABLE_NETWORK */ /* debugging stuff */ #ifdef _DEBUG diff --git a/src/console_gui.cpp b/src/console_gui.cpp index ed46938cd5..916a2ec74f 100644 --- a/src/console_gui.cpp +++ b/src/console_gui.cpp @@ -78,7 +78,7 @@ struct IConsoleLine { static const IConsoleLine *Get(uint index) { const IConsoleLine *item = IConsoleLine::front; - while (index != 0 && item != NULL) { + while (index != 0 && item != nullptr) { index--; item = item->previous; } @@ -96,14 +96,14 @@ struct IConsoleLine { static bool Truncate() { IConsoleLine *cur = IConsoleLine::front; - if (cur == NULL) return false; + if (cur == nullptr) return false; int count = 1; - for (IConsoleLine *item = cur->previous; item != NULL; count++, cur = item, item = item->previous) { + for (IConsoleLine *item = cur->previous; item != nullptr; count++, cur = item, item = item->previous) { if (item->time > _settings_client.gui.console_backlog_timeout && count > _settings_client.gui.console_backlog_length) { delete item; - cur->previous = NULL; + cur->previous = nullptr; return true; } @@ -119,12 +119,12 @@ struct IConsoleLine { static void Reset() { delete IConsoleLine::front; - IConsoleLine::front = NULL; + IConsoleLine::front = nullptr; IConsoleLine::size = 0; } }; -/* static */ IConsoleLine *IConsoleLine::front = NULL; +/* static */ IConsoleLine *IConsoleLine::front = nullptr; /* static */ int IConsoleLine::size = 0; @@ -162,7 +162,7 @@ static const struct NWidgetPart _nested_console_window_widgets[] = { }; static WindowDesc _console_window_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_CONSOLE, WC_NONE, 0, _nested_console_window_widgets, lengthof(_nested_console_window_widgets) @@ -201,13 +201,13 @@ struct IConsoleWindow : Window this->SetDirty(); } - virtual void OnPaint() + void OnPaint() override { const int right = this->width - 5; GfxFillRect(0, 0, this->width - 1, this->height - 1, PC_BLACK); int ypos = this->height - this->line_height; - for (const IConsoleLine *print = IConsoleLine::Get(IConsoleWindow::scroll); print != NULL; print = print->previous) { + for (const IConsoleLine *print = IConsoleLine::Get(IConsoleWindow::scroll); print != nullptr; print = print->previous) { SetDParamStr(0, print->buffer); ypos = DrawStringMultiLine(5, right, -this->line_height, ypos, STR_JUST_RAW_STRING, print->colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - ICON_LINE_SPACING; if (ypos < 0) break; @@ -229,7 +229,7 @@ struct IConsoleWindow : Window } } - virtual void OnHundredthTick() + void OnHundredthTick() override { if (IConsoleLine::Truncate() && (IConsoleWindow::scroll > IConsoleLine::size)) { @@ -238,12 +238,12 @@ struct IConsoleWindow : Window } } - virtual void OnMouseLoop() + void OnMouseLoop() override { if (_iconsole_cmdline.HandleCaret()) this->SetDirty(); } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { if (_focused_window != this) return ES_NOT_HANDLED; @@ -281,13 +281,13 @@ struct IConsoleWindow : Window case WKC_RETURN: case WKC_NUM_ENTER: { /* We always want the ] at the left side; we always force these strings to be left - * aligned anyway. So enforce this in all cases by addding a left-to-right marker, + * aligned anyway. So enforce this in all cases by adding a left-to-right marker, * otherwise it will be drawn at the wrong side with right-to-left texts. */ IConsolePrintF(CC_COMMAND, LRM "] %s", _iconsole_cmdline.buf); const char *cmd = IConsoleHistoryAdd(_iconsole_cmdline.buf); IConsoleClearCommand(); - if (cmd != NULL) IConsoleCmdExec(cmd); + if (cmd != nullptr) IConsoleCmdExec(cmd); break; } @@ -314,7 +314,7 @@ struct IConsoleWindow : Window return ES_HANDLED; } - virtual void InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) + void InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) override { if (_iconsole_cmdline.InsertString(str, marked, caret, insert_location, replacement_end)) { IConsoleWindow::scroll = 0; @@ -323,25 +323,25 @@ struct IConsoleWindow : Window } } - virtual const char *GetFocusedText() const + const char *GetFocusedText() const override { return _iconsole_cmdline.buf; } - virtual const char *GetCaret() const + const char *GetCaret() const override { return _iconsole_cmdline.buf + _iconsole_cmdline.caretpos; } - virtual const char *GetMarkedText(size_t *length) const + const char *GetMarkedText(size_t *length) const override { - if (_iconsole_cmdline.markend == 0) return NULL; + if (_iconsole_cmdline.markend == 0) return nullptr; *length = _iconsole_cmdline.markend - _iconsole_cmdline.markpos; return _iconsole_cmdline.buf + _iconsole_cmdline.markpos; } - virtual Point GetCaretPosition() const + Point GetCaretPosition() const override { int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); Point pt = {this->line_offset + delta + _iconsole_cmdline.caretxoffs, this->height - this->line_height}; @@ -349,7 +349,7 @@ struct IConsoleWindow : Window return pt; } - virtual Rect GetTextBoundingRect(const char *from, const char *to) const + Rect GetTextBoundingRect(const char *from, const char *to) const override { int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); @@ -360,21 +360,21 @@ struct IConsoleWindow : Window return r; } - virtual const char *GetTextCharacterAtPosition(const Point &pt) const + const char *GetTextCharacterAtPosition(const Point &pt) const override { int delta = min(this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH, 0); - if (!IsInsideMM(pt.y, this->height - this->line_height, this->height)) return NULL; + if (!IsInsideMM(pt.y, this->height - this->line_height, this->height)) return nullptr; return GetCharAtPosition(_iconsole_cmdline.buf, pt.x - delta); } - virtual void OnMouseWheel(int wheel) + void OnMouseWheel(int wheel) override { this->Scroll(-wheel); } - virtual void OnFocusLost() + void OnFocusLost() override { VideoDriver::GetInstance()->EditBoxLostFocus(); } @@ -459,10 +459,10 @@ static const char *IConsoleHistoryAdd(const char *cmd) while (IsWhitespace(*cmd)) cmd++; /* Do not put empty command in history */ - if (StrEmpty(cmd)) return NULL; + if (StrEmpty(cmd)) return nullptr; /* Do not put in history if command is same as previous */ - if (_iconsole_history[0] == NULL || strcmp(_iconsole_history[0], cmd) != 0) { + if (_iconsole_history[0] == nullptr || strcmp(_iconsole_history[0], cmd) != 0) { free(_iconsole_history[ICON_HISTORY_SIZE - 1]); memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1)); _iconsole_history[0] = stredup(cmd); @@ -479,10 +479,10 @@ static const char *IConsoleHistoryAdd(const char *cmd) */ static void IConsoleHistoryNavigate(int direction) { - if (_iconsole_history[0] == NULL) return; // Empty history + if (_iconsole_history[0] == nullptr) return; // Empty history _iconsole_historypos = Clamp(_iconsole_historypos + direction, -1, ICON_HISTORY_SIZE - 1); - if (direction > 0 && _iconsole_history[_iconsole_historypos] == NULL) _iconsole_historypos--; + if (direction > 0 && _iconsole_history[_iconsole_historypos] == nullptr) _iconsole_historypos--; if (_iconsole_historypos == -1) { _iconsole_cmdline.DeleteAll(); diff --git a/src/console_internal.h b/src/console_internal.h index 1b63b26f0d..4c07a96f24 100644 --- a/src/console_internal.h +++ b/src/console_internal.h @@ -69,7 +69,7 @@ extern IConsoleAlias *_iconsole_aliases; ///< List of registered aliases. void IConsoleClearBuffer(); /* Commands */ -void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook = NULL); +void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook = nullptr); void IConsoleAliasRegister(const char *name, const char *cmd); IConsoleCmd *IConsoleCmdGet(const char *name); IConsoleAlias *IConsoleAliasGet(const char *name); diff --git a/src/core/alloc_func.hpp b/src/core/alloc_func.hpp index c33e733016..c4ea1f561f 100644 --- a/src/core/alloc_func.hpp +++ b/src/core/alloc_func.hpp @@ -53,23 +53,23 @@ static inline void CheckAllocationConstraints(size_t num_elements) * @note the memory contains garbage data (i.e. possibly non-zero values). * @tparam T the type of the variable(s) to allocation. * @param num_elements the number of elements to allocate of the given type. - * @return NULL when num_elements == 0, non-NULL otherwise. + * @return nullptr when num_elements == 0, non-nullptr otherwise. */ template static inline T *MallocT(size_t num_elements) { /* * MorphOS cannot handle 0 elements allocations, or rather that always - * returns NULL. So we do that for *all* allocations, thus causing it + * returns nullptr. So we do that for *all* allocations, thus causing it * to behave the same on all OSes. */ - if (num_elements == 0) return NULL; + if (num_elements == 0) return nullptr; /* Ensure the size does not overflow. */ CheckAllocationConstraints(num_elements); T *t_ptr = (T*)malloc(num_elements * sizeof(T)); - if (t_ptr == NULL) MallocError(num_elements * sizeof(T)); + if (t_ptr == nullptr) MallocError(num_elements * sizeof(T)); return t_ptr; } @@ -81,20 +81,20 @@ static inline T *MallocT(size_t num_elements) * @note the memory contains all zero values. * @tparam T the type of the variable(s) to allocation. * @param num_elements the number of elements to allocate of the given type. - * @return NULL when num_elements == 0, non-NULL otherwise. + * @return nullptr when num_elements == 0, non-nullptr otherwise. */ template static inline T *CallocT(size_t num_elements) { /* * MorphOS cannot handle 0 elements allocations, or rather that always - * returns NULL. So we do that for *all* allocations, thus causing it + * returns nullptr. So we do that for *all* allocations, thus causing it * to behave the same on all OSes. */ - if (num_elements == 0) return NULL; + if (num_elements == 0) return nullptr; T *t_ptr = (T*)calloc(num_elements, sizeof(T)); - if (t_ptr == NULL) MallocError(num_elements * sizeof(T)); + if (t_ptr == nullptr) MallocError(num_elements * sizeof(T)); return t_ptr; } @@ -107,26 +107,26 @@ static inline T *CallocT(size_t num_elements) * @tparam T the type of the variable(s) to allocation. * @param t_ptr the previous allocation to extend/shrink. * @param num_elements the number of elements to allocate of the given type. - * @return NULL when num_elements == 0, non-NULL otherwise. + * @return nullptr when num_elements == 0, non-nullptr otherwise. */ template static inline T *ReallocT(T *t_ptr, size_t num_elements) { /* * MorphOS cannot handle 0 elements allocations, or rather that always - * returns NULL. So we do that for *all* allocations, thus causing it + * returns nullptr. So we do that for *all* allocations, thus causing it * to behave the same on all OSes. */ if (num_elements == 0) { free(t_ptr); - return NULL; + return nullptr; } /* Ensure the size does not overflow. */ CheckAllocationConstraints(num_elements); t_ptr = (T*)realloc(static_cast(t_ptr), num_elements * sizeof(T)); - if (t_ptr == NULL) ReallocError(num_elements * sizeof(T)); + if (t_ptr == nullptr) ReallocError(num_elements * sizeof(T)); return t_ptr; } diff --git a/src/core/alloc_type.hpp b/src/core/alloc_type.hpp index 9c25cc9e3f..e351bf360d 100644 --- a/src/core/alloc_type.hpp +++ b/src/core/alloc_type.hpp @@ -14,69 +14,6 @@ #include "alloc_func.hpp" -/** - * A small 'wrapper' for allocations that can be done on most OSes on the - * stack, but are just too large to fit in the stack on devices with a small - * stack such as the NDS. - * So when it is possible a stack allocation is made, otherwise a heap - * allocation is made and this is freed once the struct goes out of scope. - * @param T the type to make the allocation for - * @param length the amount of items to allocate - */ -template -struct SmallStackSafeStackAlloc { -#if !defined(__NDS__) - /** Storing the data on the stack */ - T data[length]; -#else - /** Storing it on the heap */ - T *data; - /** The length (in elements) of data in this allocator. */ - size_t len; - - /** Allocating the memory */ - SmallStackSafeStackAlloc() : data(MallocT(length)), len(length) {} - - /** And freeing when it goes out of scope */ - ~SmallStackSafeStackAlloc() - { - free(data); - } -#endif - - /** - * Gets a pointer to the data stored in this wrapper. - * @return the pointer. - */ - inline operator T *() - { - return data; - } - - /** - * Gets a pointer to the data stored in this wrapper. - * @return the pointer. - */ - inline T *operator -> () - { - return data; - } - - /** - * Gets a pointer to the last data element stored in this wrapper. - * @note needed because endof does not work properly for pointers. - * @return the 'endof' pointer. - */ - inline T *EndOf() - { -#if !defined(__NDS__) - return endof(data); -#else - return &data[len]; -#endif - } -}; - /** * A reusable buffer that can be used for places that temporary allocate * a bit of memory and do that very often, or for places where static @@ -93,7 +30,7 @@ private: public: /** Create a new buffer */ - ReusableBuffer() : buffer(NULL), count(0) {} + ReusableBuffer() : buffer(nullptr), count(0) {} /** Clear the buffer */ ~ReusableBuffer() { free(this->buffer); } @@ -180,38 +117,4 @@ public: inline void operator delete[](void *ptr) { free(ptr); } }; -/** - * A smart pointer class that free()'s the pointer on destruction. - * @tparam T Storage type. - */ -template -class AutoFreePtr -{ - T *ptr; ///< Stored pointer. - -public: - AutoFreePtr(T *ptr) : ptr(ptr) {} - ~AutoFreePtr() { free(this->ptr); } - - /** - * Take ownership of a new pointer and free the old one if needed. - * @param ptr NEw pointer. - */ - inline void Assign(T *ptr) - { - free(this->ptr); - this->ptr = ptr; - } - - /** Dereference pointer. */ - inline T *operator ->() { return this->ptr; } - /** Dereference pointer. */ - inline const T *operator ->() const { return this->ptr; } - - /** Cast to underlaying regular pointer. */ - inline operator T *() { return this->ptr; } - /** Cast to underlaying regular pointer. */ - inline operator const T *() const { return this->ptr; } -}; - #endif /* ALLOC_TYPE_HPP */ diff --git a/src/core/bitmath_func.hpp b/src/core/bitmath_func.hpp index fd05aa3f59..8fdc7100e8 100644 --- a/src/core/bitmath_func.hpp +++ b/src/core/bitmath_func.hpp @@ -367,12 +367,12 @@ static inline T ROR(const T x, const uint8 n) * (since it will use hardware swapping if available). * Even though they should return uint16 and uint32, we get * warnings if we don't cast those (why?) */ - #define BSWAP32(x) ((uint32)CFSwapInt32(x)) - #define BSWAP16(x) ((uint16)CFSwapInt16(x)) +# define BSWAP32(x) (static_cast(CFSwapInt32(x))) +# define BSWAP16(x) (static_cast(CFSwapInt16(x))) #elif defined(_MSC_VER) /* MSVC has intrinsics for swapping, resulting in faster code */ - #define BSWAP32(x) (_byteswap_ulong(x)) - #define BSWAP16(x) (_byteswap_ushort(x)) +# define BSWAP32(x) (_byteswap_ulong(x)) +# define BSWAP16(x) (_byteswap_ushort(x)) #else /** * Perform a 32 bits endianness bitswap on x. @@ -383,7 +383,7 @@ static inline T ROR(const T x, const uint8 n) { #if !defined(__ICC) && defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ >= 3)) /* GCC >= 4.3 provides a builtin, resulting in faster code */ - return (uint32)__builtin_bswap32((int32)x); + return static_cast(__builtin_bswap32(static_cast(x))); #else return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000); #endif /* defined(__GNUC__) */ diff --git a/src/core/endian_type.hpp b/src/core/endian_type.hpp index 4058c5c19a..1cacf6c0cb 100644 --- a/src/core/endian_type.hpp +++ b/src/core/endian_type.hpp @@ -26,7 +26,7 @@ #define TTD_BIG_ENDIAN 1 /* Windows has always LITTLE_ENDIAN */ -#if defined(_WIN32) || defined(__OS2__) +#if defined(_WIN32) || defined(__OS2__) || defined(__HAIKU__) # define TTD_ENDIAN TTD_LITTLE_ENDIAN #elif defined(OSX) # include diff --git a/src/core/enum_type.hpp b/src/core/enum_type.hpp index fc89b9489e..8526a91a56 100644 --- a/src/core/enum_type.hpp +++ b/src/core/enum_type.hpp @@ -12,8 +12,6 @@ #ifndef ENUM_TYPE_HPP #define ENUM_TYPE_HPP -#include - /** Some enums need to have allowed incrementing (i.e. StationClassID) */ #define DECLARE_POSTFIX_INCREMENT(enum_type) \ inline enum_type operator ++(enum_type& e, int) \ @@ -48,8 +46,6 @@ * we will create specialization derived from MakeEnumPropsT<>. * i.e.: * template <> struct EnumPropsT : MakeEnumPropsT {}; - * followed by: - * typedef TinyEnumT TrackByte; */ template struct EnumPropsT; @@ -74,106 +70,4 @@ struct MakeEnumPropsT { static const uint num_bits = Tnum_bits; ///< Number of bits for storing the enum in command parameters }; - - -/** - * In some cases we use byte or uint16 to store values that are defined as enum. It is - * necessary in order to control the sizeof() such values. Some compilers make enum - * the same size as int (4 or 8 bytes instead of 1 or 2). As a consequence the strict - * compiler type - checking causes errors like: - * 'HasPowerOnRail' : cannot convert parameter 1 from 'byte' to 'RailType' when - * u->u.rail.railtype is passed as argument or type RailType. In such cases it is better - * to teach the compiler that u->u.rail.railtype is to be treated as RailType. - */ -template struct TinyEnumT; - -/** The general declaration of TinyEnumT<> (above) */ -template -struct TinyEnumT { - typedef Tenum_t enum_type; ///< expose our enumeration type (i.e. Trackdir) to outside - typedef EnumPropsT Props; ///< make easier access to our enumeration properties - typedef typename Props::storage storage_type; ///< small storage type - static const enum_type begin = Props::begin; ///< enum beginning (i.e. TRACKDIR_BEGIN) - static const enum_type end = Props::end; ///< enum end (i.e. TRACKDIR_END) - static const enum_type invalid = Props::invalid;///< invalid value (i.e. INVALID_TRACKDIR) - - storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form - - /** Cast operator - invoked then the value is assigned to the Tenum_t type */ - inline operator enum_type () const - { - return (enum_type)m_val; - } - - /** Assignment operator (from Tenum_t type) */ - inline TinyEnumT& operator = (enum_type e) - { - m_val = (storage_type)e; - return *this; - } - - /** Assignment operator (from Tenum_t type) */ - inline TinyEnumT& operator = (uint u) - { - m_val = (storage_type)u; - return *this; - } - - /** postfix ++ operator on tiny type */ - inline TinyEnumT operator ++ (int) - { - TinyEnumT org = *this; - if (++m_val >= end) m_val -= (storage_type)(end - begin); - return org; - } - - /** prefix ++ operator on tiny type */ - inline TinyEnumT& operator ++ () - { - if (++m_val >= end) m_val -= (storage_type)(end - begin); - return *this; - } -}; - - -/** Template of struct holding enum types (on most archs, enums are stored in an int32). No math operators are provided. */ -template -struct SimpleTinyEnumT { - storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form - - /** Cast operator - invoked then the value is assigned to the storage_type */ - inline operator enum_type () const - { - return (enum_type)this->m_val; - } - - /** Assignment operator (from enum_type) */ - inline SimpleTinyEnumT &operator = (enum_type e) - { - this->m_val = (storage_type)e; - return *this; - } - - /** Assignment operator (from general uint) */ - inline SimpleTinyEnumT &operator = (uint u) - { - this->m_val = (storage_type)u; - return *this; - } - - /** Bit math (or) assignment operator (from enum_type) */ - inline SimpleTinyEnumT &operator |= (enum_type e) - { - this->m_val = (storage_type)((enum_type)this->m_val | e); - return *this; - } - - /** Bit math (and) assignment operator (from enum_type) */ - inline SimpleTinyEnumT &operator &= (enum_type e) - { - this->m_val = (storage_type)((enum_type)this->m_val & e); - return *this; - } -}; - #endif /* ENUM_TYPE_HPP */ diff --git a/src/core/geometry_type.hpp b/src/core/geometry_type.hpp index 2bd8ffbade..2927cd9804 100644 --- a/src/core/geometry_type.hpp +++ b/src/core/geometry_type.hpp @@ -12,11 +12,6 @@ #ifndef GEOMETRY_TYPE_HPP #define GEOMETRY_TYPE_HPP -#if defined(__AMIGA__) - /* AmigaOS already has a Point declared */ - #define Point OTTD_Point -#endif /* __AMIGA__ */ - #if defined(__APPLE__) /* Mac OS X already has both Rect and Point declared */ #define Rect OTTD_Rect @@ -34,6 +29,20 @@ struct Point { struct Dimension { uint width; uint height; + + Dimension(uint w = 0, uint h = 0) : width(w), height(h) {}; + + bool operator< (const Dimension &other) const + { + int x = (*this).width - other.width; + if (x != 0) return x < 0; + return (*this).height < other.height; + } + + bool operator== (const Dimension &other) const + { + return (*this).width == other.width && (*this).height == other.height; + } }; /** Specification of a rectangle with absolute coordinates of all edges */ diff --git a/src/core/kdtree.hpp b/src/core/kdtree.hpp new file mode 100644 index 0000000000..c37ab8eea2 --- /dev/null +++ b/src/core/kdtree.hpp @@ -0,0 +1,486 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 kdtree.hpp K-d tree template specialised for 2-dimensional Manhattan geometry */ + +#ifndef KDTREE_HPP +#define KDTREE_HPP + +#include "../stdafx.h" +#include +#include +#include + +/** + * K-dimensional tree, specialised for 2-dimensional space. + * This is not intended as a primary storage of data, but as an index into existing data. + * Usually the type stored by this tree should be an index into an existing array. + * + * This implementation assumes Manhattan distances are used. + * + * Be careful when using this in game code, depending on usage pattern, the tree shape may + * end up different for different clients in multiplayer, causing iteration order to differ + * and possibly having elements returned in different order. The using code should be designed + * to produce the same result regardless of iteration order. + * + * The element type T must be less-than comparable for FindNearest to work. + * + * @tparam T Type stored in the tree, should be cheap to copy. + * @tparam TxyFunc Functor type to extract coordinate from a T value and dimension index (0 or 1). + * @tparam CoordT Type of coordinate values extracted via TxyFunc. + * @tparam DistT Type to use for representing distance values. + */ +template +class Kdtree { + /** Type of a node in the tree */ + struct node { + T element; ///< Element stored at node + size_t left; ///< Index of node to the left, INVALID_NODE if none + size_t right; ///< Index of node to the right, INVALID_NODE if none + + node(T element) : element(element), left(INVALID_NODE), right(INVALID_NODE) { } + }; + + static const size_t INVALID_NODE = SIZE_MAX; ///< Index value indicating no-such-node + + std::vector nodes; ///< Pool of all nodes in the tree + std::vector free_list; ///< List of dead indices in the nodes vector + size_t root; ///< Index of root node + TxyFunc xyfunc; ///< Functor to extract a coordinate from an element + size_t unbalanced; ///< Number approximating how unbalanced the tree might be + + /** Create one new node in the tree, return its index in the pool */ + size_t AddNode(const T &element) + { + if (this->free_list.size() == 0) { + this->nodes.emplace_back(element); + return this->nodes.size() - 1; + } else { + size_t newidx = this->free_list.back(); + this->free_list.pop_back(); + this->nodes[newidx] = node{ element }; + return newidx; + } + } + + /** Find a coordinate value to split a range of elements at */ + template + CoordT SelectSplitCoord(It begin, It end, int level) + { + It mid = begin + (end - begin) / 2; + std::nth_element(begin, mid, end, [&](T a, T b) { return this->xyfunc(a, level % 2) < this->xyfunc(b, level % 2); }); + return this->xyfunc(*mid, level % 2); + } + + /** Construct a subtree from elements between begin and end iterators, return index of root */ + template + size_t BuildSubtree(It begin, It end, int level) + { + ptrdiff_t count = end - begin; + + if (count == 0) { + return INVALID_NODE; + } else if (count == 1) { + return this->AddNode(*begin); + } else if (count > 1) { + CoordT split_coord = SelectSplitCoord(begin, end, level); + It split = std::partition(begin, end, [&](T v) { return this->xyfunc(v, level % 2) < split_coord; }); + size_t newidx = this->AddNode(*split); + this->nodes[newidx].left = this->BuildSubtree(begin, split, level + 1); + this->nodes[newidx].right = this->BuildSubtree(split + 1, end, level + 1); + return newidx; + } else { + NOT_REACHED(); + } + } + + /** Rebuild the tree with all existing elements, optionally adding or removing one more */ + bool Rebuild(const T *include_element, const T *exclude_element) + { + size_t initial_count = this->Count(); + if (initial_count < 8) return false; // arbitrary value for "not worth rebalancing" + + T root_element = this->nodes[this->root].element; + std::vector elements = this->FreeSubtree(this->root); + elements.push_back(root_element); + + if (include_element != nullptr) { + elements.push_back(*include_element); + initial_count++; + } + if (exclude_element != nullptr) { + typename std::vector::iterator removed = std::remove(elements.begin(), elements.end(), *exclude_element); + elements.erase(removed, elements.end()); + initial_count--; + } + + this->Build(elements.begin(), elements.end()); + assert(initial_count == this->Count()); + return true; + } + + /** Insert one element in the tree somewhere below node_idx */ + void InsertRecursive(const T &element, size_t node_idx, int level) + { + /* Dimension index of current level */ + int dim = level % 2; + /* Node reference */ + node &n = this->nodes[node_idx]; + + /* Coordinate of element splitting at this node */ + CoordT nc = this->xyfunc(n.element, dim); + /* Coordinate of the new element */ + CoordT ec = this->xyfunc(element, dim); + /* Which side to insert on */ + size_t &next = (ec < nc) ? n.left : n.right; + + if (next == INVALID_NODE) { + /* New leaf */ + size_t newidx = this->AddNode(element); + /* Vector may have been reallocated at this point, n and next are invalid */ + node &nn = this->nodes[node_idx]; + if (ec < nc) nn.left = newidx; else nn.right = newidx; + } else { + this->InsertRecursive(element, next, level + 1); + } + } + + /** + * Free all children of the given node + * @return Collection of elements that were removed from tree. + */ + std::vector FreeSubtree(size_t node_idx) + { + std::vector subtree_elements; + node &n = this->nodes[node_idx]; + + /* We'll be appending items to the free_list, get index of our first item */ + size_t first_free = this->free_list.size(); + /* Prepare the descent with our children */ + if (n.left != INVALID_NODE) this->free_list.push_back(n.left); + if (n.right != INVALID_NODE) this->free_list.push_back(n.right); + n.left = n.right = INVALID_NODE; + + /* Recursively free the nodes being collected */ + for (size_t i = first_free; i < this->free_list.size(); i++) { + node &fn = this->nodes[this->free_list[i]]; + subtree_elements.push_back(fn.element); + if (fn.left != INVALID_NODE) this->free_list.push_back(fn.left); + if (fn.right != INVALID_NODE) this->free_list.push_back(fn.right); + fn.left = fn.right = INVALID_NODE; + } + + return subtree_elements; + } + + /** + * Find and remove one element from the tree. + * @param element The element to search for + * @param node_idx Sub-tree to search in + * @param level Current depth in the tree + * @return New root node index of the sub-tree processed + */ + size_t RemoveRecursive(const T &element, size_t node_idx, int level) + { + /* Node reference */ + node &n = this->nodes[node_idx]; + + if (n.element == element) { + /* Remove this one */ + this->free_list.push_back(node_idx); + if (n.left == INVALID_NODE && n.right == INVALID_NODE) { + /* Simple case, leaf, new child node for parent is "none" */ + return INVALID_NODE; + } else { + /* Complex case, rebuild the sub-tree */ + std::vector subtree_elements = this->FreeSubtree(node_idx); + return this->BuildSubtree(subtree_elements.begin(), subtree_elements.end(), level);; + } + } else { + /* Search in a sub-tree */ + /* Dimension index of current level */ + int dim = level % 2; + /* Coordinate of element splitting at this node */ + CoordT nc = this->xyfunc(n.element, dim); + /* Coordinate of the element being removed */ + CoordT ec = this->xyfunc(element, dim); + /* Which side to remove from */ + size_t next = (ec < nc) ? n.left : n.right; + assert(next != INVALID_NODE); // node must exist somewhere and must be found before a leaf is reached + /* Descend */ + size_t new_branch = this->RemoveRecursive(element, next, level + 1); + if (new_branch != next) { + /* Vector may have been reallocated at this point, n and next are invalid */ + node &nn = this->nodes[node_idx]; + if (ec < nc) nn.left = new_branch; else nn.right = new_branch; + } + return node_idx; + } + } + + + DistT ManhattanDistance(const T &element, CoordT x, CoordT y) const + { + return abs((DistT)this->xyfunc(element, 0) - (DistT)x) + abs((DistT)this->xyfunc(element, 1) - (DistT)y); + } + + /** A data element and its distance to a searched-for point */ + using node_distance = std::pair; + /** Ordering function for node_distance objects, elements with equal distance are ordered by less-than comparison */ + static node_distance SelectNearestNodeDistance(const node_distance &a, const node_distance &b) + { + if (a.second < b.second) return a; + if (b.second < a.second) return b; + if (a.first < b.first) return a; + if (b.first < a.first) return b; + NOT_REACHED(); // a.first == b.first: same element must not be inserted twice + } + /** Search a sub-tree for the element nearest to a given point */ + node_distance FindNearestRecursive(CoordT xy[2], size_t node_idx, int level, DistT limit = std::numeric_limits::max()) const + { + /* Dimension index of current level */ + int dim = level % 2; + /* Node reference */ + const node &n = this->nodes[node_idx]; + + /* Coordinate of element splitting at this node */ + CoordT c = this->xyfunc(n.element, dim); + /* This node's distance to target */ + DistT thisdist = ManhattanDistance(n.element, xy[0], xy[1]); + /* Assume this node is the best choice for now */ + node_distance best = std::make_pair(n.element, thisdist); + + /* Next node to visit */ + size_t next = (xy[dim] < c) ? n.left : n.right; + if (next != INVALID_NODE) { + /* Check if there is a better node down the tree */ + best = SelectNearestNodeDistance(best, this->FindNearestRecursive(xy, next, level + 1)); + } + + limit = min(best.second, limit); + + /* Check if the distance from current best is worse than distance from target to splitting line, + * if it is we also need to check the other side of the split. */ + size_t opposite = (xy[dim] >= c) ? n.left : n.right; // reverse of above + if (opposite != INVALID_NODE && limit >= abs((int)xy[dim] - (int)c)) { + node_distance other_candidate = this->FindNearestRecursive(xy, opposite, level + 1, limit); + best = SelectNearestNodeDistance(best, other_candidate); + } + + return best; + } + + template + void FindContainedRecursive(CoordT p1[2], CoordT p2[2], size_t node_idx, int level, Outputter outputter) const + { + /* Dimension index of current level */ + int dim = level % 2; + /* Node reference */ + const node &n = this->nodes[node_idx]; + + /* Coordinate of element splitting at this node */ + CoordT ec = this->xyfunc(n.element, dim); + /* Opposite coordinate of element */ + CoordT oc = this->xyfunc(n.element, 1 - dim); + + /* Test if this element is within rectangle */ + if (ec >= p1[dim] && ec < p2[dim] && oc >= p1[1 - dim] && oc < p2[1 - dim]) outputter(n.element); + + /* Recurse left if part of rectangle is left of split */ + if (p1[dim] < ec && n.left != INVALID_NODE) this->FindContainedRecursive(p1, p2, n.left, level + 1, outputter); + + /* Recurse right if part of rectangle is right of split */ + if (p2[dim] > ec && n.right != INVALID_NODE) this->FindContainedRecursive(p1, p2, n.right, level + 1, outputter); + } + + /** Debugging function, counts number of occurrences of an element regardless of its correct position in the tree */ + size_t CountValue(const T &element, size_t node_idx) const + { + if (node_idx == INVALID_NODE) return 0; + const node &n = this->nodes[node_idx]; + return CountValue(element, n.left) + CountValue(element, n.right) + ((n.element == element) ? 1 : 0); + } + + void IncrementUnbalanced(size_t amount = 1) + { + this->unbalanced += amount; + } + + /** Check if the entire tree is in need of rebuilding */ + bool IsUnbalanced() + { + size_t count = this->Count(); + if (count < 8) return false; + return this->unbalanced > this->Count() / 4; + } + + /** Verify that the invariant is true for a sub-tree, assert if not */ + void CheckInvariant(size_t node_idx, int level, CoordT min_x, CoordT max_x, CoordT min_y, CoordT max_y) + { + if (node_idx == INVALID_NODE) return; + + const node &n = this->nodes[node_idx]; + CoordT cx = this->xyfunc(n.element, 0); + CoordT cy = this->xyfunc(n.element, 1); + + assert(cx >= min_x); + assert(cx < max_x); + assert(cy >= min_y); + assert(cy < max_y); + + if (level % 2 == 0) { + // split in dimension 0 = x + CheckInvariant(n.left, level + 1, min_x, cx, min_y, max_y); + CheckInvariant(n.right, level + 1, cx, max_x, min_y, max_y); + } else { + // split in dimension 1 = y + CheckInvariant(n.left, level + 1, min_x, max_x, min_y, cy); + CheckInvariant(n.right, level + 1, min_x, max_x, cy, max_y); + } + } + + /** Verify the invariant for the entire tree, does nothing unless KDTREE_DEBUG is defined */ + void CheckInvariant() + { +#ifdef KDTREE_DEBUG + CheckInvariant(this->root, 0, std::numeric_limits::min(), std::numeric_limits::max(), std::numeric_limits::min(), std::numeric_limits::max()); +#endif + } + +public: + /** Construct a new Kdtree with the given xyfunc */ + Kdtree(TxyFunc xyfunc) : root(INVALID_NODE), xyfunc(xyfunc), unbalanced(0) { } + + /** + * Clear and rebuild the tree from a new sequence of elements, + * @tparam It Iterator type for element sequence. + * @param begin First element in sequence. + * @param end One past last element in sequence. + */ + template + void Build(It begin, It end) + { + this->nodes.clear(); + this->free_list.clear(); + this->unbalanced = 0; + if (begin == end) return; + this->nodes.reserve(end - begin); + + this->root = this->BuildSubtree(begin, end, 0); + CheckInvariant(); + } + + /** + * Clear the tree. + */ + void Clear() + { + this->nodes.clear(); + this->free_list.clear(); + this->unbalanced = 0; + return; + } + + /** + * Reconstruct the tree with the same elements, letting it be fully balanced. + */ + void Rebuild() + { + this->Rebuild(nullptr, nullptr); + } + + /** + * Insert a single element in the tree. + * Repeatedly inserting single elements may cause the tree to become unbalanced. + * Undefined behaviour if the element already exists in the tree. + */ + void Insert(const T &element) + { + if (this->Count() == 0) { + this->root = this->AddNode(element); + } else { + if (!this->IsUnbalanced() || !this->Rebuild(&element, nullptr)) { + this->InsertRecursive(element, this->root, 0); + this->IncrementUnbalanced(); + } + CheckInvariant(); + } + } + + /** + * Remove a single element from the tree, if it exists. + * Since elements are stored in interior nodes as well as leaf nodes, removing one may + * require a larger sub-tree to be re-built. Because of this, worst case run time is + * as bad as a full tree rebuild. + */ + void Remove(const T &element) + { + size_t count = this->Count(); + if (count == 0) return; + if (!this->IsUnbalanced() || !this->Rebuild(nullptr, &element)) { + /* If the removed element is the root node, this modifies this->root */ + this->root = this->RemoveRecursive(element, this->root, 0); + this->IncrementUnbalanced(); + } + CheckInvariant(); + } + + /** Get number of elements stored in tree */ + size_t Count() const + { + assert(this->free_list.size() <= this->nodes.size()); + return this->nodes.size() - this->free_list.size(); + } + + /** + * Find the element closest to given coordinate, in Manhattan distance. + * For multiple elements with the same distance, the one comparing smaller with + * a less-than comparison is chosen. + */ + T FindNearest(CoordT x, CoordT y) const + { + assert(this->Count() > 0); + + CoordT xy[2] = { x, y }; + return this->FindNearestRecursive(xy, this->root, 0).first; + } + + /** + * Find all items contained within the given rectangle. + * @note Start coordinates are inclusive, end coordinates are exclusive. x1 + void FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2, Outputter outputter) const + { + assert(x1 < x2); + assert(y1 < y2); + + if (this->Count() == 0) return; + + CoordT p1[2] = { x1, y1 }; + CoordT p2[2] = { x2, y2 }; + this->FindContainedRecursive(p1, p2, this->root, 0, outputter); + } + + /** + * Find all items contained within the given rectangle. + * @note End coordinates are exclusive, x1 FindContained(CoordT x1, CoordT y1, CoordT x2, CoordT y2) const + { + std::vector result; + this->FindContained(x1, y1, x2, y2, [&result](T e) {result.push_back(e); }); + return result; + } +}; + +#endif diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp index 4a19033f45..570f54c232 100644 --- a/src/core/math_func.hpp +++ b/src/core/math_func.hpp @@ -115,7 +115,7 @@ template static inline T *AlignPtr(T *x, uint n) { assert_compile(sizeof(size_t) == sizeof(void *)); - return (T *)Align((size_t)x, n); + return reinterpret_cast(Align((size_t)x, n)); } /** @@ -202,7 +202,7 @@ static inline uint ClampU(const uint a, const uint min, const uint max) */ static inline int32 ClampToI32(const int64 a) { - return (int32)Clamp(a, INT32_MIN, INT32_MAX); + return static_cast(Clamp(a, INT32_MIN, INT32_MAX)); } /** @@ -218,7 +218,7 @@ static inline uint16 ClampToU16(const uint64 a) * match for min(uint64, uint) than uint64 min(uint64, uint64). As such we * need to cast the UINT16_MAX to prevent MSVC from displaying its * infinite loads of warnings. */ - return (uint16)min(a, (uint64)UINT16_MAX); + return static_cast(min(a, static_cast(UINT16_MAX))); } /** @@ -247,9 +247,9 @@ static inline T Delta(const T a, const T b) * @return True if the value is in the interval, false else. */ template -static inline bool IsInsideBS(const T x, const uint base, const uint size) +static inline bool IsInsideBS(const T x, const size_t base, const size_t size) { - return (uint)(x - base) < size; + return (size_t)(x - base) < size; } /** @@ -263,9 +263,9 @@ static inline bool IsInsideBS(const T x, const uint base, const uint size) * @see IsInsideBS() */ template -static inline bool IsInsideMM(const T x, const uint min, const uint max) +static inline bool IsInsideMM(const T x, const size_t min, const size_t max) { - return (uint)(x - min) < (max - min); + return (size_t)(x - min) < (max - min); } /** @@ -339,10 +339,10 @@ static inline int RoundDivSU(int a, uint b) { if (a > 0) { /* 0.5 is rounded to 1 */ - return (a + (int)b / 2) / (int)b; + return (a + static_cast(b) / 2) / static_cast(b); } else { /* -0.5 is rounded to 0 */ - return (a - ((int)b - 1) / 2) / (int)b; + return (a - (static_cast(b) - 1) / 2) / static_cast(b); } } diff --git a/src/core/mem_func.hpp b/src/core/mem_func.hpp index 6878711645..5b3fe4caba 100644 --- a/src/core/mem_func.hpp +++ b/src/core/mem_func.hpp @@ -78,7 +78,7 @@ static inline int MemCmpT(const T *ptr1, const T *ptr2, size_t num = 1) template static inline void MemReverseT(T *ptr1, T *ptr2) { - assert(ptr1 != NULL && ptr2 != NULL); + assert(ptr1 != nullptr && ptr2 != nullptr); assert(ptr1 < ptr2); do { @@ -95,7 +95,7 @@ static inline void MemReverseT(T *ptr1, T *ptr2) template static inline void MemReverseT(T *ptr, size_t num) { - assert(ptr != NULL); + assert(ptr != nullptr); MemReverseT(ptr, ptr + (num - 1)); } diff --git a/src/core/pool_func.cpp b/src/core/pool_func.cpp index f8ff93cecc..7a65bf77a4 100644 --- a/src/core/pool_func.cpp +++ b/src/core/pool_func.cpp @@ -21,8 +21,8 @@ /* virtual */ PoolBase::~PoolBase() { PoolVector *pools = PoolBase::GetPools(); - pools->Erase(pools->Find(this)); - if (pools->Length() == 0) delete pools; + pools->erase(std::find(pools->begin(), pools->end(), this)); + if (pools->size() == 0) delete pools; } /** @@ -31,10 +31,7 @@ */ /* static */ void PoolBase::Clean(PoolType pt) { - PoolVector *pools = PoolBase::GetPools(); - PoolBase **end = pools->End(); - for (PoolBase **ppool = pools->Begin(); ppool != end; ppool++) { - PoolBase *pool = *ppool; + for (PoolBase *pool : *PoolBase::GetPools()) { if (pool->type & pt) pool->CleanPool(); } } diff --git a/src/core/pool_func.hpp b/src/core/pool_func.hpp index 64af175649..ee49992862 100644 --- a/src/core/pool_func.hpp +++ b/src/core/pool_func.hpp @@ -39,8 +39,8 @@ DEFINE_POOL_METHOD(inline)::Pool(const char *name) : checked(0), #endif /* OTTD_ASSERT */ cleaning(false), - data(NULL), - alloc_cache(NULL) + data(nullptr), + alloc_cache(nullptr) { } /** @@ -71,7 +71,7 @@ DEFINE_POOL_METHOD(inline size_t)::FindFirstFree() size_t index = this->first_free; for (; index < this->first_unused; index++) { - if (this->data[index] == NULL) return index; + if (this->data[index] == nullptr) return index; } if (index < this->size) { @@ -96,17 +96,17 @@ DEFINE_POOL_METHOD(inline size_t)::FindFirstFree() * @param size size of item * @param index index of item * @pre index < this->size - * @pre this->Get(index) == NULL + * @pre this->Get(index) == nullptr */ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index) { - assert(this->data[index] == NULL); + assert(this->data[index] == nullptr); this->first_unused = max(this->first_unused, index + 1); this->items++; Titem *item; - if (Tcache && this->alloc_cache != NULL) { + if (Tcache && this->alloc_cache != nullptr) { assert(sizeof(Titem) == size); item = (Titem *)this->alloc_cache; this->alloc_cache = this->alloc_cache->next; @@ -164,7 +164,7 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index) if (index >= this->size) this->ResizeFor(index); - if (this->data[index] != NULL) { + if (this->data[index] != nullptr) { SlErrorCorruptFmt("%s index " PRINTF_SIZE " already in use", this->name, index); } @@ -174,13 +174,13 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index) /** * Deallocates memory used by this index and marks item as free * @param index item to deallocate - * @pre unit is allocated (non-NULL) - * @note 'delete NULL' doesn't cause call of this function, so it is safe + * @pre unit is allocated (non-nullptr) + * @note 'delete nullptr' doesn't cause call of this function, so it is safe */ DEFINE_POOL_METHOD(void)::FreeItem(size_t index) { assert(index < this->size); - assert(this->data[index] != NULL); + assert(this->data[index] != nullptr); if (Tcache) { AllocCache *ac = (AllocCache *)this->data[index]; ac->next = this->alloc_cache; @@ -188,7 +188,7 @@ DEFINE_POOL_METHOD(void)::FreeItem(size_t index) } else { free(this->data[index]); } - this->data[index] = NULL; + this->data[index] = nullptr; this->first_free = min(this->first_free, index); this->items--; if (!this->cleaning) Titem::PostDestructor(index); @@ -199,16 +199,16 @@ DEFINE_POOL_METHOD(void)::CleanPool() { this->cleaning = true; for (size_t i = 0; i < this->first_unused; i++) { - delete this->Get(i); // 'delete NULL;' is very valid + delete this->Get(i); // 'delete nullptr;' is very valid } assert(this->items == 0); free(this->data); this->first_unused = this->first_free = this->size = 0; - this->data = NULL; + this->data = nullptr; this->cleaning = false; if (Tcache) { - while (this->alloc_cache != NULL) { + while (this->alloc_cache != nullptr) { AllocCache *ac = this->alloc_cache; this->alloc_cache = ac->next; free(ac); diff --git a/src/core/pool_type.hpp b/src/core/pool_type.hpp index 4d20ed1abb..8102d580c6 100644 --- a/src/core/pool_type.hpp +++ b/src/core/pool_type.hpp @@ -7,7 +7,7 @@ * See the GNU 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 pool_type.hpp Defintion of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle, Town, and other indexed items. */ +/** @file pool_type.hpp Definition of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle, Town, and other indexed items. */ #ifndef POOL_TYPE_HPP #define POOL_TYPE_HPP @@ -26,7 +26,7 @@ enum PoolType { }; DECLARE_ENUM_AS_BIT_SET(PoolType) -typedef SmallVector PoolVector; ///< Vector of pointers to PoolBase +typedef std::vector PoolVector; ///< Vector of pointers to PoolBase /** Base class for base of all pools. */ struct PoolBase { @@ -50,7 +50,7 @@ struct PoolBase { */ PoolBase(PoolType pt) : type(pt) { - *PoolBase::GetPools()->Append() = this; + PoolBase::GetPools()->push_back(this); } virtual ~PoolBase(); @@ -91,7 +91,7 @@ struct Pool : PoolBase { size_t size; ///< Current allocated size size_t first_free; ///< No item with index lower than this is free (doesn't say anything about this one!) size_t first_unused; ///< This and all higher indexes are free (doesn't say anything about first_unused-1 !) - size_t items; ///< Number of used indexes (non-NULL) + size_t items; ///< Number of used indexes (non-nullptr) #ifdef OTTD_ASSERT size_t checked; ///< Number of items we checked for #endif /* OTTD_ASSERT */ @@ -115,13 +115,13 @@ struct Pool : PoolBase { } /** - * Tests whether given index can be used to get valid (non-NULL) Titem + * Tests whether given index can be used to get valid (non-nullptr) Titem * @param index index to examine - * @return true if PoolItem::Get(index) will return non-NULL pointer + * @return true if PoolItem::Get(index) will return non-nullptr pointer */ inline bool IsValidID(size_t index) { - return index < this->first_unused && this->Get(index) != NULL; + return index < this->first_unused && this->Get(index) != nullptr; } /** @@ -150,7 +150,7 @@ struct Pool : PoolBase { * Allocates space for new Titem * @param size size of Titem * @return pointer to allocated memory - * @note can never fail (return NULL), use CanAllocate() to check first! + * @note can never fail (return nullptr), use CanAllocate() to check first! */ inline void *operator new(size_t size) { @@ -164,7 +164,7 @@ struct Pool : PoolBase { */ inline void operator delete(void *p) { - if (p == NULL) return; + if (p == nullptr) return; Titem *pn = (Titem *)p; assert(pn == Tpool->Get(pn->index)); Tpool->FreeItem(pn->index); @@ -175,7 +175,7 @@ struct Pool : PoolBase { * @param size size of Titem * @param index index of item * @return pointer to allocated memory - * @note can never fail (return NULL), use CanAllocate() to check first! + * @note can never fail (return nullptr), use CanAllocate() to check first! * @pre index has to be unused! Else it will crash */ inline void *operator new(size_t size, size_t index) @@ -228,9 +228,9 @@ struct Pool : PoolBase { } /** - * Tests whether given index can be used to get valid (non-NULL) Titem + * Tests whether given index can be used to get valid (non-nullptr) Titem * @param index index to examine - * @return true if PoolItem::Get(index) will return non-NULL pointer + * @return true if PoolItem::Get(index) will return non-nullptr pointer */ static inline bool IsValidID(size_t index) { @@ -252,11 +252,11 @@ struct Pool : PoolBase { * Returns Titem with given index * @param index of item to get * @return pointer to Titem - * @note returns NULL for invalid index + * @note returns nullptr for invalid index */ static inline Titem *GetIfValid(size_t index) { - return index < Tpool->first_unused ? Tpool->Get(index) : NULL; + return index < Tpool->first_unused ? Tpool->Get(index) : nullptr; } /** @@ -282,7 +282,7 @@ struct Pool : PoolBase { * Dummy function called after destructor of each member. * If you want to use it, override it in PoolItem's subclass. * @param index index of deleted item - * @note when this function is called, PoolItem::Get(index) == NULL. + * @note when this function is called, PoolItem::Get(index) == nullptr. * @note it's called only when !CleaningPool() */ static inline void PostDestructor(size_t index) { } @@ -314,8 +314,8 @@ private: }; #define FOR_ALL_ITEMS_FROM(type, iter, var, start) \ - for (size_t iter = start; var = NULL, iter < type::GetPoolSize(); iter++) \ - if ((var = type::Get(iter)) != NULL) + for (size_t iter = start; var = nullptr, iter < type::GetPoolSize(); iter++) \ + if ((var = type::Get(iter)) != nullptr) #define FOR_ALL_ITEMS(type, iter, var) FOR_ALL_ITEMS_FROM(type, iter, var, 0) diff --git a/src/core/smallmap_type.hpp b/src/core/smallmap_type.hpp index dda0fc2a1e..d050522821 100644 --- a/src/core/smallmap_type.hpp +++ b/src/core/smallmap_type.hpp @@ -13,7 +13,6 @@ #define SMALLMAP_TYPE_HPP #include "smallvec_type.hpp" -#include "sort_func.hpp" /** * Simple pair of data. Both types have to be POD ("Plain Old Data")! @@ -27,6 +26,7 @@ struct SmallPair { /** Initializes this Pair with data */ inline SmallPair(const T &first, const U &second) : first(first), second(second) { } + SmallPair() = default; }; /** @@ -38,8 +38,8 @@ struct SmallPair { * * @see SmallVector */ -template -struct SmallMap : SmallVector, S> { +template +struct SmallMap : std::vector > { typedef ::SmallPair Pair; typedef Pair *iterator; typedef const Pair *const_iterator; @@ -54,12 +54,13 @@ struct SmallMap : SmallVector, S> { * @param key key to find * @return &Pair(key, data) if found, this->End() if not */ - inline const Pair *Find(const T &key) const + inline typename std::vector::const_iterator Find(const T &key) const { - for (uint i = 0; i < this->items; i++) { - if (key == this->data[i].first) return &this->data[i]; + typename std::vector::const_iterator it; + for (it = std::vector::begin(); it != std::vector::end(); it++) { + if (key == it->first) return it; } - return this->End(); + return it; } /** @@ -69,18 +70,39 @@ struct SmallMap : SmallVector, S> { */ inline Pair *Find(const T &key) { - for (uint i = 0; i < this->items; i++) { - if (key == this->data[i].first) return &this->data[i]; + for (uint i = 0; i < std::vector::size(); i++) { + if (key == std::vector::operator[](i).first) return &std::vector::operator[](i); } return this->End(); } + inline const Pair *End() const + { + return std::vector::data() + std::vector::size(); + } + + inline Pair *End() + { + return std::vector::data() + std::vector::size(); + } + + /** * Tests whether a key is assigned in this map. * @param key key to test * @return true iff the item is present */ inline bool Contains(const T &key) const + { + return this->Find(key) != std::vector::end(); + } + + /** + * Tests whether a key is assigned in this map. + * @param key key to test + * @return true iff the item is present + */ + inline bool Contains(const T &key) { return this->Find(key) != this->End(); } @@ -92,8 +114,9 @@ struct SmallMap : SmallVector, S> { */ inline void Erase(Pair *pair) { - assert(pair >= this->Begin() && pair < this->End()); - *pair = this->data[--this->items]; + assert(pair >= std::vector::data() && pair < this->End()); + auto distance = pair - std::vector::data(); + std::vector::erase(std::vector::begin() + distance); } /** @@ -104,13 +127,11 @@ struct SmallMap : SmallVector, S> { */ inline bool Erase(const T &key) { - for (uint i = 0; i < this->items; i++) { - if (key == this->data[i].first) { - this->data[i] = this->data[--this->items]; - return true; - } - } - return false; + auto *pair = this->Find(key); + if (pair == this->End()) return false; + + this->Erase(pair); + return true; } /** @@ -122,9 +143,7 @@ struct SmallMap : SmallVector, S> { inline bool Insert(const T &key, const U &data) { if (this->Contains(key)) return false; - Pair *n = this->Append(); - n->first = key; - n->second = data; + std::vector::emplace_back(key, data); return true; } @@ -136,22 +155,13 @@ struct SmallMap : SmallVector, S> { */ inline U &operator[](const T &key) { - for (uint i = 0; i < this->items; i++) { - if (key == this->data[i].first) return this->data[i].second; + for (uint i = 0; i < std::vector::size(); i++) { + if (key == std::vector::operator[](i).first) return std::vector::operator[](i).second; } - Pair *n = this->Append(); - n->first = key; - return n->second; - } - - inline void SortByKey() - { - QSortT(this->Begin(), this->items, KeySorter); - } - - static int CDECL KeySorter(const Pair *a, const Pair *b) - { - return a->first - b->first; + /*C++17: Pair &n = */ std::vector::emplace_back(); + Pair &n = std::vector::back(); + n.first = key; + return n.second; } }; diff --git a/src/core/smallmatrix_type.hpp b/src/core/smallmatrix_type.hpp index cd4dee4e3a..faa531d5fd 100644 --- a/src/core/smallmatrix_type.hpp +++ b/src/core/smallmatrix_type.hpp @@ -46,13 +46,13 @@ protected: public: - SmallMatrix() : data(NULL), width(0), height(0), capacity(0) {} + SmallMatrix() : data(nullptr), width(0), height(0), capacity(0) {} /** * Copy constructor. * @param other The other matrix to copy. */ - SmallMatrix(const SmallMatrix &other) : data(NULL), width(0), height(0), capacity(0) + SmallMatrix(const SmallMatrix &other) : data(nullptr), width(0), height(0), capacity(0) { this->Assign(other); } @@ -112,7 +112,7 @@ public: this->width = 0; this->capacity = 0; free(this->data); - this->data = NULL; + this->data = nullptr; } /** @@ -216,8 +216,8 @@ public: inline void Resize(uint new_width, uint new_height) { uint new_capacity = new_width * new_height; - T *new_data = NULL; - void (*copy)(T *dest, const T *src, size_t count) = NULL; + T *new_data = nullptr; + void (*copy)(T *dest, const T *src, size_t count) = nullptr; if (new_capacity > this->capacity) { /* If the data doesn't fit into current capacity, resize and copy ... */ new_data = MallocT(new_capacity); diff --git a/src/core/smallstack_type.hpp b/src/core/smallstack_type.hpp index 06b5aaafa6..6aded5a759 100644 --- a/src/core/smallstack_type.hpp +++ b/src/core/smallstack_type.hpp @@ -13,7 +13,7 @@ #define SMALLSTACK_TYPE_HPP #include "smallvec_type.hpp" -#include "../thread/thread.h" +#include /** * A simplified pool which stores values instead of pointers and doesn't @@ -23,15 +23,14 @@ template class SimplePool { public: - inline SimplePool() : first_unused(0), first_free(0), mutex(ThreadMutex::New()) {} - inline ~SimplePool() { delete this->mutex; } + inline SimplePool() : first_unused(0), first_free(0) {} /** * Get the mutex. We don't lock the mutex in the pool methods as the * SmallStack isn't necessarily in a consistent state after each method. * @return Mutex. */ - inline ThreadMutex *GetMutex() { return this->mutex; } + inline std::mutex &GetMutex() { return this->mutex; } /** * Get the item at position index. @@ -73,8 +72,8 @@ private: if (!this->data[index].valid) return index; } - if (index >= this->data.Length() && index < Tmax_size) { - this->data.Resize(index + 1); + if (index >= this->data.size() && index < Tmax_size) { + this->data.resize(index + 1); } return index; } @@ -86,8 +85,8 @@ private: Tindex first_unused; Tindex first_free; - ThreadMutex *mutex; - SmallVector data; + std::mutex mutex; + std::vector data; }; /** @@ -106,6 +105,7 @@ struct SmallStackItem { */ inline SmallStackItem(const Titem &value, Tindex next) : next(next), value(value) {} + SmallStackItem() = default; }; /** @@ -195,7 +195,7 @@ public: inline void Push(const Titem &item) { if (this->value != Tinvalid) { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); Tindex new_item = SmallStack::GetPool().Create(); if (new_item != Tmax_size) { PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item); @@ -218,7 +218,7 @@ public: if (this->next == Tmax_size) { this->value = Tinvalid; } else { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); PooledSmallStack &popped = SmallStack::GetPool().Get(this->next); this->value = popped.value; if (popped.branch_count == 0) { @@ -257,7 +257,7 @@ public: { if (item == Tinvalid || item == this->value) return true; if (this->next != Tmax_size) { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); const SmallStack *in_list = this; do { in_list = static_cast( @@ -281,7 +281,7 @@ protected: inline void Branch() { if (this->next != Tmax_size) { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); ++(SmallStack::GetPool().Get(this->next).branch_count); } } diff --git a/src/core/smallvec_type.hpp b/src/core/smallvec_type.hpp index 588dd599dc..3cf33f8b7e 100644 --- a/src/core/smallvec_type.hpp +++ b/src/core/smallvec_type.hpp @@ -14,438 +14,42 @@ #include "alloc_func.hpp" #include "mem_func.hpp" +#include +#include /** - * Simple vector template class. + * Helper function to append an item to a vector if it is not already contained + * Consider using std::set, std::unordered_set or std::flat_set in new code * - * @note There are no asserts in the class so you have - * to care about that you grab an item which is - * inside the list. + * @param vec A reference to the vector to be extended + * @param item Reference to the item to be copy-constructed if not found * - * @tparam T The type of the items stored - * @tparam S The steps of allocation + * @return Whether the item was already present */ -template -class SmallVector { -protected: - T *data; ///< The pointer to the first item - uint items; ///< The number of items stored - uint capacity; ///< The available space for storing items - -public: - SmallVector() : data(NULL), items(0), capacity(0) { } - - /** - * Copy constructor. - * @param other The other vector to copy. - */ - SmallVector(const SmallVector &other) : data(NULL), items(0), capacity(0) - { - this->Assign(other); - } - - /** - * Generic copy constructor. - * @param other The other vector to copy. - */ - template - SmallVector(const SmallVector &other) : data(NULL), items(0), capacity(0) - { - this->Assign(other); - } - - /** - * Assignment. - * @param other The other vector to assign. - */ - SmallVector &operator=(const SmallVector &other) - { - this->Assign(other); - return *this; - } - - /** - * Generic assignment. - * @param other The other vector to assign. - */ - template - SmallVector &operator=(const SmallVector &other) - { - this->Assign(other); - return *this; - } - - ~SmallVector() - { - free(this->data); - } - - /** - * Assign items from other vector. - */ - template - inline void Assign(const SmallVector &other) - { - if ((const void *)&other == (void *)this) return; - - this->Clear(); - if (other.Length() > 0) MemCpyT(this->Append(other.Length()), other.Begin(), other.Length()); - } - - /** - * Remove all items from the list. - */ - inline void Clear() - { - /* In fact we just reset the item counter avoiding the need to - * probably reallocate the same amount of memory the list was - * previously using. */ - this->items = 0; - } - - /** - * Remove all items from the list and free allocated memory. - */ - inline void Reset() - { - this->items = 0; - this->capacity = 0; - free(data); - data = NULL; - } - - /** - * Compact the list down to the smallest block size boundary. - */ - inline void Compact() - { - uint capacity = Align(this->items, S); - if (capacity >= this->capacity) return; - - this->capacity = capacity; - this->data = ReallocT(this->data, this->capacity); - } - - /** - * Append an item and return it. - * @param to_add the number of items to append - * @return pointer to newly allocated item - */ - inline T *Append(uint to_add = 1) - { - uint begin = this->items; - this->items += to_add; - - if (this->items > this->capacity) { - this->capacity = Align(this->items, S); - this->data = ReallocT(this->data, this->capacity); - } - - return &this->data[begin]; - } - - /** - * Set the size of the vector, effectively truncating items from the end or appending uninitialised ones. - * @param num_items Target size. - */ - inline void Resize(uint num_items) - { - this->items = num_items; - - if (this->items > this->capacity) { - this->capacity = Align(this->items, S); - this->data = ReallocT(this->data, this->capacity); - } - } - - /** - * Insert a new item at a specific position into the vector, moving all following items. - * @param item Position at which the new item should be inserted - * @return pointer to the new item - */ - inline T *Insert(T *item) - { - assert(item >= this->Begin() && item <= this->End()); - - size_t to_move = this->End() - item; - size_t start = item - this->Begin(); - - this->Append(); - if (to_move > 0) MemMoveT(this->Begin() + start + 1, this->Begin() + start, to_move); - return this->Begin() + start; - } - - /** - * Search for the first occurrence of an item. - * The '!=' operator of T is used for comparison. - * @param item Item to search for - * @return The position of the item, or End() when not present - */ - inline const T *Find(const T &item) const - { - const T *pos = this->Begin(); - const T *end = this->End(); - while (pos != end && *pos != item) pos++; - return pos; - } - - /** - * Search for the first occurrence of an item. - * The '!=' operator of T is used for comparison. - * @param item Item to search for - * @return The position of the item, or End() when not present - */ - inline T *Find(const T &item) - { - T *pos = this->Begin(); - const T *end = this->End(); - while (pos != end && *pos != item) pos++; - return pos; - } - - /** - * Search for the first occurrence of an item. - * The '!=' operator of T is used for comparison. - * @param item Item to search for - * @return The position of the item, or -1 when not present - */ - inline int FindIndex(const T &item) const - { - int index = 0; - const T *pos = this->Begin(); - const T *end = this->End(); - while (pos != end && *pos != item) { - pos++; - index++; - } - return pos == end ? -1 : index; - } - - /** - * Tests whether a item is present in the vector. - * The '!=' operator of T is used for comparison. - * @param item Item to test for - * @return true iff the item is present - */ - inline bool Contains(const T &item) const - { - return this->Find(item) != this->End(); - } - - /** - * Removes given item from this vector - * @param item item to remove - * @note it has to be pointer to item in this map. It is overwritten by the last item. - */ - inline void Erase(T *item) - { - assert(item >= this->Begin() && item < this->End()); - *item = this->data[--this->items]; - } - - /** - * Remove items from the vector while preserving the order of other items. - * @param pos First item to remove. - * @param count Number of consecutive items to remove. - */ - void ErasePreservingOrder(uint pos, uint count = 1) - { - ErasePreservingOrder(this->data + pos, count); - } - - /** - * Remove items from the vector while preserving the order of other items. - * @param item First item to remove. - * @param count Number of consecutive items to remove. - */ - inline void ErasePreservingOrder(T *item, uint count = 1) - { - if (count == 0) return; - assert(item >= this->Begin()); - assert(item + count <= this->End()); - - this->items -= count; - ptrdiff_t to_move = this->End() - item; - if (to_move > 0) MemMoveT(item, item + count, to_move); - } - - /** - * Tests whether a item is present in the vector, and appends it to the end if not. - * The '!=' operator of T is used for comparison. - * @param item Item to test for - * @return true iff the item is was already present - */ - inline bool Include(const T &item) - { - bool is_member = this->Contains(item); - if (!is_member) *this->Append() = item; - return is_member; - } - - /** - * Get the number of items in the list. - * - * @return The number of items in the list. - */ - inline uint Length() const - { - return this->items; - } - - /** - * Get the pointer to the first item (const) - * - * @return the pointer to the first item - */ - inline const T *Begin() const - { - return this->data; - } - - /** - * Get the pointer to the first item - * - * @return the pointer to the first item - */ - inline T *Begin() - { - return this->data; - } - - /** - * Get the pointer behind the last valid item (const) - * - * @return the pointer behind the last valid item - */ - inline const T *End() const - { - return &this->data[this->items]; - } - - /** - * Get the pointer behind the last valid item - * - * @return the pointer behind the last valid item - */ - inline T *End() - { - return &this->data[this->items]; - } - - /** - * Get the pointer to item "number" (const) - * - * @param index the position of the item - * @return the pointer to the item - */ - inline const T *Get(uint index) const - { - /* Allow access to the 'first invalid' item */ - assert(index <= this->items); - return &this->data[index]; - } - - /** - * Get the pointer to item "number" - * - * @param index the position of the item - * @return the pointer to the item - */ - inline T *Get(uint index) - { - /* Allow access to the 'first invalid' item */ - assert(index <= this->items); - return &this->data[index]; - } - - /** - * Get item "number" (const) - * - * @param index the position of the item - * @return the item - */ - inline const T &operator[](uint index) const - { - assert(index < this->items); - return this->data[index]; - } - - /** - * Get item "number" - * - * @param index the position of the item - * @return the item - */ - inline T &operator[](uint index) - { - assert(index < this->items); - return this->data[index]; - } -}; - +template +inline bool include(std::vector& vec, const T &item) +{ + const bool is_member = std::find(vec.begin(), vec.end(), item) != vec.end(); + if (!is_member) vec.emplace_back(item); + return is_member; +} /** - * Simple vector template class, with automatic free. + * Helper function to get the index of an item + * Consider using std::set, std::unordered_set or std::flat_set in new code * - * @note There are no asserts in the class so you have - * to care about that you grab an item which is - * inside the list. + * @param vec A reference to the vector to be extended + * @param item Reference to the item to be search for * - * @param T The type of the items stored, must be a pointer - * @param S The steps of allocation + * @return Index of element if found, otherwise -1 */ -template -class AutoFreeSmallVector : public SmallVector { -public: - ~AutoFreeSmallVector() - { - this->Clear(); - } +template +int find_index(std::vector const& vec, T const& item) +{ + auto const it = std::find(vec.begin(), vec.end(), item); + if (it != vec.end()) return it - vec.begin(); - /** - * Remove all items from the list. - */ - inline void Clear() - { - for (uint i = 0; i < this->items; i++) { - free(this->data[i]); - } - - this->items = 0; - } -}; - -/** - * Simple vector template class, with automatic delete. - * - * @note There are no asserts in the class so you have - * to care about that you grab an item which is - * inside the list. - * - * @param T The type of the items stored, must be a pointer - * @param S The steps of allocation - */ -template -class AutoDeleteSmallVector : public SmallVector { -public: - ~AutoDeleteSmallVector() - { - this->Clear(); - } - - /** - * Remove all items from the list. - */ - inline void Clear() - { - for (uint i = 0; i < this->items; i++) { - delete this->data[i]; - } - - this->items = 0; - } -}; - -typedef AutoFreeSmallVector StringList; ///< Type for a list of strings. + return -1; +} #endif /* SMALLVEC_TYPE_HPP */ diff --git a/src/cpu.cpp b/src/cpu.cpp index 9393ea0613..8d5eb5e5e7 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -35,7 +35,7 @@ unsigned __int64 ottd_rdtsc(); #endif /* rdtsc for all other *nix-en (hopefully). Use GCC syntax */ -#if (defined(__i386__) || defined(__x86_64__)) && !defined(__DJGPP__) && !defined(RDTSC_AVAILABLE) +#if (defined(__i386__) || defined(__x86_64__)) && !defined(RDTSC_AVAILABLE) uint64 ottd_rdtsc() { uint32 high, low; diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 792739316b..378e322c22 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -52,27 +52,27 @@ # include # include FT_FREETYPE_H #endif /* WITH_FREETYPE */ -#if defined(WITH_ICU_LAYOUT) || defined(WITH_ICU_SORT) +#if defined(WITH_ICU_LX) || defined(WITH_ICU_I18N) # include -#endif /* WITH_ICU_SORT || WITH_ICU_LAYOUT */ -#ifdef WITH_LZMA +#endif /* WITH_ICU_LX || WITH_ICU_I18N */ +#ifdef WITH_LIBLZMA # include #endif #ifdef WITH_LZO #include #endif -#ifdef WITH_SDL +#if defined(WITH_SDL) || defined(WITH_SDL2) # include -#endif /* WITH_SDL */ +#endif /* WITH_SDL || WITH_SDL2 */ #ifdef WITH_ZLIB # include #endif #include "safeguards.h" -/* static */ const char *CrashLog::message = NULL; -/* static */ char *CrashLog::gamelog_buffer = NULL; -/* static */ const char *CrashLog::gamelog_last = NULL; +/* static */ const char *CrashLog::message = nullptr; +/* static */ char *CrashLog::gamelog_buffer = nullptr; +/* static */ const char *CrashLog::gamelog_last = nullptr; char *CrashLog::LogCompiler(char *buffer, const char *last) const { @@ -119,7 +119,7 @@ char *CrashLog::LogCompiler(char *buffer, const char *last) const char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const { return buffer + seprintf(buffer, last, - "OpenTTD version: CityMania patched client http://citymania.org\n\n\n" + "OpenTTD version: CityMania patched client http://citymania.org\n\n" " Version: %s (%d)\n" " NewGRF ver: %08x\n" " Bits: %d\n" @@ -168,18 +168,18 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const " Sound driver: %s\n" " Sound set: %s (%u)\n" " Video driver: %s\n\n", - BlitterFactory::GetCurrentBlitter() == NULL ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(), - BaseGraphics::GetUsedSet() == NULL ? "none" : BaseGraphics::GetUsedSet()->name, - BaseGraphics::GetUsedSet() == NULL ? UINT32_MAX : BaseGraphics::GetUsedSet()->version, - _current_language == NULL ? "none" : _current_language->file, - MusicDriver::GetInstance() == NULL ? "none" : MusicDriver::GetInstance()->GetName(), - BaseMusic::GetUsedSet() == NULL ? "none" : BaseMusic::GetUsedSet()->name, - BaseMusic::GetUsedSet() == NULL ? UINT32_MAX : BaseMusic::GetUsedSet()->version, + BlitterFactory::GetCurrentBlitter() == nullptr ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(), + BaseGraphics::GetUsedSet() == nullptr ? "none" : BaseGraphics::GetUsedSet()->name, + BaseGraphics::GetUsedSet() == nullptr ? UINT32_MAX : BaseGraphics::GetUsedSet()->version, + _current_language == nullptr ? "none" : _current_language->file, + MusicDriver::GetInstance() == nullptr ? "none" : MusicDriver::GetInstance()->GetName(), + BaseMusic::GetUsedSet() == nullptr ? "none" : BaseMusic::GetUsedSet()->name, + BaseMusic::GetUsedSet() == nullptr ? UINT32_MAX : BaseMusic::GetUsedSet()->version, _networking ? (_network_server ? "server" : "client") : "no", - SoundDriver::GetInstance() == NULL ? "none" : SoundDriver::GetInstance()->GetName(), - BaseSounds::GetUsedSet() == NULL ? "none" : BaseSounds::GetUsedSet()->name, - BaseSounds::GetUsedSet() == NULL ? UINT32_MAX : BaseSounds::GetUsedSet()->version, - VideoDriver::GetInstance() == NULL ? "none" : VideoDriver::GetInstance()->GetName() + SoundDriver::GetInstance() == nullptr ? "none" : SoundDriver::GetInstance()->GetName(), + BaseSounds::GetUsedSet() == nullptr ? "none" : BaseSounds::GetUsedSet()->name, + BaseSounds::GetUsedSet() == nullptr ? UINT32_MAX : BaseSounds::GetUsedSet()->version, + VideoDriver::GetInstance() == nullptr ? "none" : VideoDriver::GetInstance()->GetName() ); buffer += seprintf(buffer, last, @@ -197,14 +197,14 @@ char *CrashLog::LogConfiguration(char *buffer, const char *last) const buffer += seprintf(buffer, last, "AI Configuration (local: %i) (current: %i):\n", (int)_local_company, (int)_current_company); const Company *c; FOR_ALL_COMPANIES(c) { - if (c->ai_info == NULL) { + if (c->ai_info == nullptr) { buffer += seprintf(buffer, last, " %2i: Human\n", (int)c->index); } else { buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); } } - if (Game::GetInfo() != NULL) { + if (Game::GetInfo() != nullptr) { buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion()); } buffer += seprintf(buffer, last, "\n"); @@ -240,21 +240,21 @@ char *CrashLog::LogLibraries(char *buffer, const char *last) const buffer += seprintf(buffer, last, " FreeType: %d.%d.%d\n", major, minor, patch); #endif /* WITH_FREETYPE */ -#if defined(WITH_ICU_LAYOUT) || defined(WITH_ICU_SORT) +#if defined(WITH_ICU_LX) || defined(WITH_ICU_I18N) /* 4 times 0-255, separated by dots (.) and a trailing '\0' */ char buf[4 * 3 + 3 + 1]; UVersionInfo ver; u_getVersion(ver); u_versionToString(ver, buf); -#ifdef WITH_ICU_SORT +#ifdef WITH_ICU_I18N buffer += seprintf(buffer, last, " ICU i18n: %s\n", buf); #endif -#ifdef WITH_ICU_LAYOUT +#ifdef WITH_ICU_LX buffer += seprintf(buffer, last, " ICU lx: %s\n", buf); #endif -#endif /* WITH_ICU_SORT || WITH_ICU_LAYOUT */ +#endif /* WITH_ICU_LX || WITH_ICU_I18N */ -#ifdef WITH_LZMA +#ifdef WITH_LIBLZMA buffer += seprintf(buffer, last, " LZMA: %s\n", lzma_version_string()); #endif @@ -263,13 +263,17 @@ char *CrashLog::LogLibraries(char *buffer, const char *last) const #endif #ifdef WITH_PNG - buffer += seprintf(buffer, last, " PNG: %s\n", png_get_libpng_ver(NULL)); + buffer += seprintf(buffer, last, " PNG: %s\n", png_get_libpng_ver(nullptr)); #endif /* WITH_PNG */ #ifdef WITH_SDL - const SDL_version *v = SDL_Linked_Version(); - buffer += seprintf(buffer, last, " SDL: %d.%d.%d\n", v->major, v->minor, v->patch); -#endif /* WITH_SDL */ + const SDL_version *sdl_v = SDL_Linked_Version(); + buffer += seprintf(buffer, last, " SDL1: %d.%d.%d\n", sdl_v->major, sdl_v->minor, sdl_v->patch); +#elif defined(WITH_SDL2) + SDL_version sdl2_v; + SDL_GetVersion(&sdl2_v); + buffer += seprintf(buffer, last, " SDL2: %d.%d.%d\n", sdl2_v.major, sdl2_v.minor, sdl2_v.patch); +#endif #ifdef WITH_ZLIB buffer += seprintf(buffer, last, " Zlib: %s\n", zlibVersion()); @@ -313,7 +317,7 @@ char *CrashLog::LogRecentNews(char *buffer, const char *last) const buffer += seprintf(buffer, last, "Recent news messages:\n"); int i = 0; - for (NewsItem *news = _latest_news; i < 32 && news != NULL; news = news->prev, i++) { + for (NewsItem *news = _latest_news; i < 32 && news != nullptr; news = news->prev, i++) { YearMonthDay ymd; ConvertDateToYMD(news->date, &ymd); buffer += seprintf(buffer, last, "(%i-%02i-%02i) StringID: %u, Type: %u, Ref1: %u, %u, Ref2: %u, %u\n", @@ -332,7 +336,7 @@ char *CrashLog::LogRecentNews(char *buffer, const char *last) const */ char *CrashLog::FillCrashLog(char *buffer, const char *last) const { - time_t cur_time = time(NULL); + time_t cur_time = time(nullptr); buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\nCityMania patched client http://citymania.org\nPlease, unless you encounter this bug with unpatched OpenTTD version, report bug to CityMania team\n\n"); buffer += seprintf(buffer, last, "Crash at: %s", asctime(gmtime(&cur_time))); @@ -370,7 +374,7 @@ bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *fil seprintf(filename, filename_last, "%scrash.log", _personal_dir); FILE *file = FioFOpenFile(filename, "w", NO_DIRECTORY); - if (file == NULL) return false; + if (file == nullptr) return false; size_t len = strlen(buffer); size_t written = fwrite(buffer, 1, len, file); @@ -397,7 +401,7 @@ bool CrashLog::WriteSavegame(char *filename, const char *filename_last) const { /* If the map array doesn't exist, saving will fail too. If the map got * initialised, there is a big chance the rest is initialised too. */ - if (_m == NULL) return false; + if (_m == nullptr) return false; try { GamelogEmergency(); @@ -422,7 +426,7 @@ bool CrashLog::WriteSavegame(char *filename, const char *filename_last) const bool CrashLog::WriteScreenshot(char *filename, const char *filename_last) const { /* Don't draw when we have invalid screen size */ - if (_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == NULL) return false; + if (_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == nullptr) return false; bool res = MakeScreenshot(SC_CRASHLOG, "crash"); if (res) strecpy(filename, _full_screenshot_name, filename_last); @@ -505,7 +509,7 @@ bool CrashLog::MakeCrashLog() const */ /* static */ void CrashLog::AfterCrashLogCleanup() { - if (MusicDriver::GetInstance() != NULL) MusicDriver::GetInstance()->Stop(); - if (SoundDriver::GetInstance() != NULL) SoundDriver::GetInstance()->Stop(); - if (VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop(); + if (MusicDriver::GetInstance() != nullptr) MusicDriver::GetInstance()->Stop(); + if (SoundDriver::GetInstance() != nullptr) SoundDriver::GetInstance()->Stop(); + if (VideoDriver::GetInstance() != nullptr) VideoDriver::GetInstance()->Stop(); } diff --git a/src/crashlog.h b/src/crashlog.h index b9bc8afa24..03acdc5aae 100644 --- a/src/crashlog.h +++ b/src/crashlog.h @@ -48,7 +48,7 @@ protected: * Writes actually encountered error to the buffer. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. - * @param message Message passed to use for possible errors. Can be NULL. + * @param message Message passed to use for possible errors. Can be nullptr. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogError(char *buffer, const char *last, const char *message) const = 0; diff --git a/src/currency.cpp b/src/currency.cpp index b87f77393b..7bffdd0edd 100644 --- a/src/currency.cpp +++ b/src/currency.cpp @@ -64,6 +64,9 @@ static const CurrencySpec origin_currency_specs[CURRENCY_END] = { { 4901, "", CF_NOEURO, "", NBSP "Rls", 1, STR_GAME_OPTIONS_CURRENCY_IRR }, ///< Iranian Rial { 80, "", CF_NOEURO, "", NBSP "rub", 1, STR_GAME_OPTIONS_CURRENCY_RUB }, ///< New Russian Ruble { 24, "", CF_NOEURO, "$", "", 0, STR_GAME_OPTIONS_CURRENCY_MXN }, ///< Mexican peso + { 40, "", CF_NOEURO, "NTD" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_NTD }, ///< new taiwan dollar + { 8, "", CF_NOEURO, "\xC2\xA5", "", 0, STR_GAME_OPTIONS_CURRENCY_CNY }, ///< chinese renminbi + { 10, "", CF_NOEURO, "HKD" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_HKD }, ///< hong kong dollar }; /** Array of currencies used by the system */ diff --git a/src/currency.h b/src/currency.h index 401df5ec1f..a3772951d2 100644 --- a/src/currency.h +++ b/src/currency.h @@ -60,6 +60,9 @@ enum Currencies { CURRENCY_IRR, ///< Iranian Rial CURRENCY_RUB, ///< New Russian Ruble CURRENCY_MXN, ///< Mexican Peso + CURRENCY_NTD, ///< New Taiwan Dollar + CURRENCY_CNY, ///< Chinese Renminbi + CURRENCY_HKD, ///< Hong Kong Dollar CURRENCY_END, ///< always the last item }; diff --git a/src/date.cpp b/src/date.cpp index 9c25af40ee..8b8fab5b0a 100644 --- a/src/date.cpp +++ b/src/date.cpp @@ -195,9 +195,7 @@ static void OnNewYear() VehiclesYearlyLoop(); TownsYearlyLoop(); InvalidateWindowClassesData(WC_BUILD_STATION); -#ifdef ENABLE_NETWORK if (_network_server) NetworkServerYearlyLoop(); -#endif /* ENABLE_NETWORK */ if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant(); @@ -217,11 +215,9 @@ static void OnNewYear() LinkGraph *lg; FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(-days_this_year); -#ifdef ENABLE_NETWORK /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out * all of them if the date is set back, else those messages will hang for ever */ NetworkInitChatMessage(); -#endif /* ENABLE_NETWORK */ } if (_settings_client.gui.auto_euro) CheckSwitchToEuro(); @@ -244,9 +240,7 @@ static void OnNewMonth() IndustryMonthlyLoop(); SubsidyMonthlyLoop(); StationMonthlyLoop(); -#ifdef ENABLE_NETWORK if (_network_server) NetworkServerMonthlyLoop(); -#endif /* ENABLE_NETWORK */ } /** @@ -254,9 +248,7 @@ static void OnNewMonth() */ static void OnNewDay() { -#ifdef ENABLE_NETWORK if (_network_server) NetworkServerDailyLoop(); -#endif /* ENABLE_NETWORK */ DisasterDailyLoop(); IndustryDailyLoop(); diff --git a/src/date_gui.cpp b/src/date_gui.cpp index 468a74db99..86c09087c3 100644 --- a/src/date_gui.cpp +++ b/src/date_gui.cpp @@ -55,7 +55,7 @@ struct SetDateWindow : Window { this->date.year = Clamp(this->date.year, min_year, max_year); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt = { this->parent->left + this->parent->width / 2 - sm_width / 2, this->parent->top + this->parent->height / 2 - sm_height / 2 }; return pt; @@ -68,21 +68,21 @@ struct SetDateWindow : Window { void ShowDateDropDown(int widget) { int selected; - DropDownList *list = new DropDownList(); + DropDownList list; switch (widget) { default: NOT_REACHED(); case WID_SD_DAY: for (uint i = 0; i < 31; i++) { - *list->Append() = new DropDownListStringItem(STR_DAY_NUMBER_1ST + i, i + 1, false); + list.emplace_back(new DropDownListStringItem(STR_DAY_NUMBER_1ST + i, i + 1, false)); } selected = this->date.day; break; case WID_SD_MONTH: for (uint i = 0; i < 12; i++) { - *list->Append() = new DropDownListStringItem(STR_MONTH_JAN + i, i, false); + list.emplace_back(new DropDownListStringItem(STR_MONTH_JAN + i, i, false)); } selected = this->date.month; break; @@ -91,16 +91,16 @@ struct SetDateWindow : Window { for (Year i = this->min_year; i <= this->max_year; i++) { DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false); item->SetParam(0, i); - *list->Append() = item; + list.emplace_back(item); } selected = this->date.year; break; } - ShowDropDownList(this, list, selected, widget); + ShowDropDownList(this, std::move(list), selected, widget); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { Dimension d = {0, 0}; switch (widget) { @@ -129,7 +129,7 @@ struct SetDateWindow : Window { *size = d; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_SD_DAY: SetDParam(0, this->date.day - 1 + STR_DAY_NUMBER_1ST); break; @@ -138,7 +138,7 @@ struct SetDateWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SD_DAY: @@ -148,13 +148,13 @@ struct SetDateWindow : Window { break; case WID_SD_SET_DATE: - if (this->callback != NULL) this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day)); + if (this->callback != nullptr) this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day)); delete this; break; } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_SD_DAY: @@ -197,7 +197,7 @@ static const NWidgetPart _nested_set_date_widgets[] = { /** Description of the date setting window. */ static WindowDesc _set_date_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_SET_DATE, WC_NONE, 0, _nested_set_date_widgets, lengthof(_nested_set_date_widgets) diff --git a/src/debug.cpp b/src/debug.cpp index 13df98db34..c300c9fac1 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -23,10 +23,8 @@ #include -#if defined(ENABLE_NETWORK) #include "network/network_admin.h" SOCKET _debug_socket = INVALID_SOCKET; -#endif /* ENABLE_NETWORK */ #include "safeguards.h" @@ -111,7 +109,6 @@ char *DumpDebugFacilityNames(char *buf, char *last) */ static void debug_print(const char *dbg, const char *buf) { -#if defined(ENABLE_NETWORK) if (_debug_socket != INVALID_SOCKET) { char buf2[1024 + 32]; @@ -121,17 +118,16 @@ static void debug_print(const char *dbg, const char *buf) send(_debug_socket, buf2, (int)strlen(buf2), 0); return; } -#endif /* ENABLE_NETWORK */ if (strcmp(dbg, "desync") == 0) { static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR); - if (f == NULL) return; + if (f == nullptr) return; fprintf(f, "%s%s\n", GetLogPrefix(), buf); fflush(f); #ifdef RANDOM_DEBUG } else if (strcmp(dbg, "random") == 0) { static FILE *f = FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR); - if (f == NULL) return; + if (f == nullptr) return; fprintf(f, "%s\n", buf); fflush(f); @@ -146,9 +142,7 @@ static void debug_print(const char *dbg, const char *buf) #else fputs(buffer, stderr); #endif -#ifdef ENABLE_NETWORK NetworkAdminConsole(dbg, buf); -#endif /* ENABLE_NETWORK */ IConsoleDebug(dbg, buf); } } @@ -206,7 +200,7 @@ void SetDebugString(const char *s) while (*s >= 'a' && *s <= 'z') s++; /* check debugging levels */ - p = NULL; + p = nullptr; for (i = debug_level; i != endof(debug_level); ++i) { if (s == t + strlen(i->name) && strncmp(t, i->name, s - t) == 0) { p = i->level; @@ -217,7 +211,7 @@ void SetDebugString(const char *s) if (*s == '=') s++; v = strtoul(s, &end, 0); s = end; - if (p != NULL) { + if (p != nullptr) { *p = v; } else { ShowInfoF("Unknown debug level '%.*s'", (int)(s - t), t); @@ -252,13 +246,13 @@ const char *GetDebugString() /** * Get the prefix for logs; if show_date_in_logs is enabled it returns * the date, otherwise it returns nothing. - * @return the prefix for logs (do not free), never NULL + * @return the prefix for logs (do not free), never nullptr */ const char *GetLogPrefix() { static char _log_prefix[24]; if (_settings_client.gui.show_date_in_logs) { - time_t cur_time = time(NULL); + time_t cur_time = time(nullptr); strftime(_log_prefix, sizeof(_log_prefix), "[%Y-%m-%d %H:%M:%S] ", localtime(&cur_time)); } else { *_log_prefix = '\0'; diff --git a/src/debug.h b/src/debug.h index ce454c962e..337fe86394 100644 --- a/src/debug.h +++ b/src/debug.h @@ -13,6 +13,7 @@ #define DEBUG_H #include "cpu.h" +#include /* Debugging messages policy: * These should be the severities used for direct DEBUG() calls @@ -83,21 +84,40 @@ const char *GetDebugString(); * * TIC() / TOC() creates its own block, so make sure not the mangle * it with another block. + * + * The output is counted in CPU cycles, and not comparable across + * machines. Mainly useful for local optimisations. **/ #define TIC() {\ uint64 _xxx_ = ottd_rdtsc();\ - static uint64 __sum__ = 0;\ - static uint32 __i__ = 0; + static uint64 _sum_ = 0;\ + static uint32 _i_ = 0; #define TOC(str, count)\ - __sum__ += ottd_rdtsc() - _xxx_;\ - if (++__i__ == count) {\ - DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " [avg: %.1f]", str, __sum__, __sum__/(double)__i__);\ - __i__ = 0;\ - __sum__ = 0;\ + _sum_ += ottd_rdtsc() - _xxx_;\ + if (++_i_ == count) {\ + DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " [avg: %.1f]", str, _sum_, _sum_/(double)_i_);\ + _i_ = 0;\ + _sum_ = 0;\ }\ } +/* Chrono based version. The output is in microseconds. */ +#define TICC() {\ + auto _start_ = std::chrono::high_resolution_clock::now();\ + static uint64 _sum_ = 0;\ + static uint32 _i_ = 0; + +#define TOCC(str, _count_)\ + _sum_ += (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - _start_)).count();\ + if (++_i_ == _count_) {\ + DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " us [avg: %.1f us]", str, _sum_, _sum_/(double)_i_);\ + _i_ = 0;\ + _sum_ = 0;\ + }\ +} + + void ShowInfo(const char *str); void CDECL ShowInfoF(const char *str, ...) WARN_FORMAT(1, 2); diff --git a/src/dedicated.cpp b/src/dedicated.cpp index ce383ee4a5..2ceab0752c 100644 --- a/src/dedicated.cpp +++ b/src/dedicated.cpp @@ -11,21 +11,18 @@ #include "stdafx.h" -#ifdef ENABLE_NETWORK +char *_log_file = nullptr; ///< File to reroute output of a forked OpenTTD to +FILE *_log_fd = nullptr; ///< File to reroute output of a forked OpenTTD to -char *_log_file = NULL; ///< File to reroute output of a forked OpenTTD to -FILE *_log_fd = NULL; ///< File to reroute output of a forked OpenTTD to - -#if defined(UNIX) && !defined(__MORPHOS__) +#if defined(UNIX) #include #include "safeguards.h" -#if (defined(SUNOS) && !defined(_LP64) && !defined(_I32LPx)) || defined(__HAIKU__) +#if defined(SUNOS) && !defined(_LP64) && !defined(_I32LPx) /* Solaris has, in certain situation, pid_t defined as long, while in other * cases it has it defined as int... this handles all cases nicely. - * Haiku has also defined pid_t as a long. */ # define PRINTF_PID_T "%ld" #else @@ -44,7 +41,7 @@ void DedicatedFork() case 0: { // We're the child /* Open the log-file to log all stuff too */ _log_fd = fopen(_log_file, "a"); - if (_log_fd == NULL) { + if (_log_fd == nullptr) { perror("Unable to open logfile"); exit(1); } @@ -68,10 +65,3 @@ void DedicatedFork() } } #endif - -#else - -/** Empty helper function call for NOT(UNIX and not MORPHOS) systems */ -void DedicatedFork() {} - -#endif /* ENABLE_NETWORK */ diff --git a/src/depend/depend.cpp b/src/depend/depend.cpp index 9f8de891bd..a5d35c6356 100644 --- a/src/depend/depend.cpp +++ b/src/depend/depend.cpp @@ -54,7 +54,7 @@ * * Copies the source string to the destination buffer with respect of the * terminating null-character and the last pointer to the last element in - * the destination buffer. If the last pointer is set to NULL no boundary + * the destination buffer. If the last pointer is set to nullptr no boundary * check is performed. * * @note usage: strecpy(dst, src, lastof(dst)); @@ -85,7 +85,7 @@ char *strecpy(char *dst, const char *src, const char *last) * * Appends the source string to the destination string with respect of the * terminating null-character and and the last pointer to the last element - * in the destination buffer. If the last pointer is set to NULL no + * in the destination buffer. If the last pointer is set to nullptr no * boundary check is performed. * * @note usage: strecat(dst, src, lastof(dst)); @@ -107,6 +107,23 @@ static char *strecat(char *dst, const char *src, const char *last) return strecpy(dst, src, last); } +#if defined(__CYGWIN__) +/** + * Version of strdup copied from glibc. + * Duplicate S, returning an identical malloc'd string. + * @param s The string to duplicate. + */ +char * +strdup (const char *s) +{ + size_t len = strlen(s) + 1; + void *n = malloc(len); + + if (n == NULL) return NULL; + return (char *) memcpy(n, s, len); +} +#endif + /** * Version of the standard free that accepts const pointers. * @param ptr The data to free. @@ -163,13 +180,13 @@ public: File(const char *filename) { this->fp = fopen(filename, "r"); - if (this->fp == NULL) { + if (this->fp == nullptr) { fprintf(stdout, "Could not open %s for reading\n", filename); exit(1); } this->dirname = strdup(filename); char *last = strrchr(this->dirname, '/'); - if (last != NULL) { + if (last != nullptr) { *last = '\0'; } else { *this->dirname = '\0'; @@ -247,7 +264,7 @@ public: * Create the lexer and fill the keywords table. * @param file the file to read from. */ - Lexer(const File *file) : file(file), current_char('\0'), string(NULL), token(TOKEN_UNKNOWN) + Lexer(const File *file) : file(file), current_char('\0'), string(nullptr), token(TOKEN_UNKNOWN) { this->keywords["define"] = TOKEN_DEFINE; this->keywords["defined"] = TOKEN_DEFINED; @@ -292,8 +309,8 @@ public: } /** - * Read the currenty processed string. - * @return the string, can be NULL. + * Read the currently processed string. + * @return the string, can be nullptr. */ const char *GetString() const { @@ -308,7 +325,7 @@ public: { for (;;) { free(this->string); - this->string = NULL; + this->string = nullptr; this->token = TOKEN_UNKNOWN; switch (this->current_char) { @@ -503,10 +520,13 @@ private: * @param dirname the directory to look in. * @param filename the file to look for. * @param local whether to look locally (in dirname) for the file. - * @return the absolute path, or NULL if the file doesn't exist. + * @return the absolute path, or nullptr if the file doesn't exist. */ const char *GeneratePath(const char *dirname, const char *filename, bool local) { + /* Ignore C++ standard library headers. */ + if (strchr(filename, '.') == nullptr) return nullptr; + if (local) { if (access(filename, R_OK) == 0) return strdup(filename); @@ -517,7 +537,7 @@ const char *GeneratePath(const char *dirname, const char *filename, bool local) while (*p == '.') { if (*(++p) == '.') { char *s = strrchr(path, '/'); - if (s != NULL) *s = '\0'; + if (s != nullptr) *s = '\0'; p += 2; } } @@ -535,7 +555,7 @@ const char *GeneratePath(const char *dirname, const char *filename, bool local) while (*p == '.') { if (*(++p) == '.') { char *s = strrchr(path, '/'); - if (s != NULL) *s = '\0'; + if (s != nullptr) *s = '\0'; p += 2; } } @@ -545,7 +565,7 @@ const char *GeneratePath(const char *dirname, const char *filename, bool local) if (access(path, R_OK) == 0) return strdup(path); } - return NULL; + return nullptr; } /** @@ -730,7 +750,7 @@ void ScanFile(const char *filename, const char *ext, bool header, bool verbose) break; } const char *h = GeneratePath(file.GetDirname(), lexer.GetString(), lexer.GetToken() == TOKEN_LOCAL); - if (h != NULL) { + if (h != nullptr) { StringMap::iterator it = _headers.find(h); if (it == _headers.end()) { it = (_headers.insert(StringMapItem(strdup(h), new StringSet()))).first; @@ -745,7 +765,7 @@ void ScanFile(const char *filename, const char *ext, bool header, bool verbose) char path[PATH_MAX]; strecpy(path, filename, lastof(path)); *(strrchr(path, '.')) = '\0'; - strecat(path, ext != NULL ? ext : ".o", lastof(path)); + strecat(path, ext != nullptr ? ext : ".o", lastof(path)); curfile = _files.find(path); if (curfile == _files.end()) { curfile = (_files.insert(StringMapItem(strdup(path), new StringSet()))).first; @@ -909,9 +929,9 @@ void ScanFile(const char *filename, const char *ext, bool header, bool verbose) int main(int argc, char *argv[]) { bool ignorenext = true; - char *filename = NULL; - char *ext = NULL; - char *delimiter = NULL; + char *filename = nullptr; + char *ext = nullptr; + char *delimiter = nullptr; bool append = false; bool verbose = false; @@ -936,25 +956,25 @@ int main(int argc, char *argv[]) /* Define */ if (strncmp(argv[i], "-D", 2) == 0) { char *p = strchr(argv[i], '='); - if (p != NULL) *p = '\0'; + if (p != nullptr) *p = '\0'; _defines.insert(strdup(&argv[i][2])); continue; } /* Output file */ if (strncmp(argv[i], "-f", 2) == 0) { - if (filename != NULL) continue; + if (filename != nullptr) continue; filename = strdup(&argv[i][2]); continue; } /* Object file extension */ if (strncmp(argv[i], "-o", 2) == 0) { - if (ext != NULL) continue; + if (ext != nullptr) continue; ext = strdup(&argv[i][2]); continue; } /* Starting string delimiter */ if (strncmp(argv[i], "-s", 2) == 0) { - if (delimiter != NULL) continue; + if (delimiter != nullptr) continue; delimiter = strdup(&argv[i][2]); continue; } @@ -966,22 +986,22 @@ int main(int argc, char *argv[]) } /* Default output file is Makefile */ - if (filename == NULL) filename = strdup("Makefile"); + if (filename == nullptr) filename = strdup("Makefile"); /* Default delimiter string */ - if (delimiter == NULL) delimiter = strdup("# DO NOT DELETE"); + if (delimiter == nullptr) delimiter = strdup("# DO NOT DELETE"); char backup[PATH_MAX]; strecpy(backup, filename, lastof(backup)); strecat(backup, ".bak", lastof(backup)); - char *content = NULL; + char *content = nullptr; long size = 0; /* Read in the current file; so we can overwrite everything from the * end of non-depend data marker down till the end. */ FILE *src = fopen(filename, "rb"); - if (src != NULL) { + if (src != nullptr) { fseek(src, 0, SEEK_END); if ((size = ftell(src)) < 0) { fprintf(stderr, "Could not read %s\n", filename); @@ -1009,7 +1029,7 @@ int main(int argc, char *argv[]) /* Then append it to the real file. */ src = fopen(backup, "r"); - while (fgets(content, size, src) != NULL) { + while (fgets(content, size, src) != nullptr) { fputs(content, dst); if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true; if (!append && found_delimiter) break; diff --git a/src/depot_cmd.cpp b/src/depot_cmd.cpp index 5101b7c2ca..710878b28c 100644 --- a/src/depot_cmd.cpp +++ b/src/depot_cmd.cpp @@ -33,7 +33,7 @@ static bool IsUniqueDepotName(const char *name) const Depot *d; FOR_ALL_DEPOTS(d) { - if (d->name != NULL && strcmp(d->name, name) == 0) return false; + if (d->name != nullptr && strcmp(d->name, name) == 0) return false; } return true; @@ -51,7 +51,7 @@ static bool IsUniqueDepotName(const char *name) CommandCost CmdRenameDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Depot *d = Depot::GetIfValid(p1); - if (d == NULL) return CMD_ERROR; + if (d == nullptr) return CMD_ERROR; CommandCost ret = CheckTileOwnership(d->xy); if (ret.Failed()) return ret; @@ -67,7 +67,7 @@ CommandCost CmdRenameDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 free(d->name); if (reset) { - d->name = NULL; + d->name = nullptr; MakeDefaultName(d); } else { d->name = stredup(text); diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index 49b0ff1a31..e3a6b9f825 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -106,16 +106,16 @@ static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Veh if (v == wagon) return; - if (wagon == NULL) { - if (head != NULL) wagon = head->Last(); + if (wagon == nullptr) { + if (head != nullptr) wagon = head->Last(); } else { wagon = wagon->Previous(); - if (wagon == NULL) return; + if (wagon == nullptr) return; } if (wagon == v) return; - DoCommandP(v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20, wagon == NULL ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE)); + DoCommandP(v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20, wagon == nullptr ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE)); } static VehicleCellSize _base_block_sizes_depot[VEH_COMPANY_END]; ///< Cell size for vehicle images in the depot view. @@ -201,7 +201,7 @@ void InitDepotWindowBlockSizes() if (!e->IsEnabled()) continue; uint w = TRAININFO_DEFAULT_VEHICLE_WIDTH; - if (e->GetGRF() != NULL && is_custom_sprite(e->u.rail.image_index)) { + if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { w = e->GetGRF()->traininfo_vehicle_width; if (w != VEHICLEINFO_FULL_VEHICLE_WIDTH) { /* Hopeless. @@ -252,7 +252,7 @@ struct DepotWindow : Window { this->unitnumber_digits = 2; this->CreateNestedTree(); - this->hscroll = (this->type == VEH_TRAIN ? this->GetScrollbar(WID_D_H_SCROLL) : NULL); + this->hscroll = (this->type == VEH_TRAIN ? this->GetScrollbar(WID_D_H_SCROLL) : nullptr); this->vscroll = this->GetScrollbar(WID_D_V_SCROLL); /* Don't show 'rename button' of aircraft hangar */ this->GetWidget(WID_D_SHOW_RENAME)->SetDisplayedPlane(type == VEH_AIRCRAFT ? SZSP_NONE : 0); @@ -344,7 +344,7 @@ struct DepotWindow : Window { } } - void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_D_MATRIX) return; @@ -378,7 +378,7 @@ struct DepotWindow : Window { uint16 rows_in_display = wid->current_y / wid->resize_y; uint16 num = this->vscroll->GetPosition() * this->num_columns; - int maxval = min(this->vehicle_list.Length(), num + (rows_in_display * this->num_columns)); + int maxval = min((uint)this->vehicle_list.size(), num + (rows_in_display * this->num_columns)); int y; for (y = r.top + 1; num < maxval; y += this->resize.step_height) { // Draw the rows for (byte i = 0; i < this->num_columns && num < maxval; i++, num++) { @@ -393,16 +393,16 @@ struct DepotWindow : Window { } } - maxval = min(this->vehicle_list.Length() + this->wagon_list.Length(), (this->vscroll->GetPosition() * this->num_columns) + (rows_in_display * this->num_columns)); + maxval = min((uint)this->vehicle_list.size() + (uint)this->wagon_list.size(), (this->vscroll->GetPosition() * this->num_columns) + (rows_in_display * this->num_columns)); /* Draw the train wagons without an engine in front. */ for (; num < maxval; num++, y += this->resize.step_height) { - const Vehicle *v = this->wagon_list[num - this->vehicle_list.Length()]; + const Vehicle *v = this->wagon_list[num - this->vehicle_list.size()]; this->DrawVehicleInDepot(v, r.left, r.right, y); } } - void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget != WID_D_CAPTION) return; @@ -445,12 +445,12 @@ struct DepotWindow : Window { uint pos = ((row + this->vscroll->GetPosition()) * this->num_columns) + xt; - if (this->vehicle_list.Length() + this->wagon_list.Length() <= pos) { + if (this->vehicle_list.size() + this->wagon_list.size() <= pos) { /* Clicking on 'line' / 'block' without a vehicle */ if (this->type == VEH_TRAIN) { /* End the dragging */ - d->head = NULL; - d->wagon = NULL; + d->head = nullptr; + d->wagon = nullptr; return MODE_DRAG_VEHICLE; } else { return MODE_ERROR; // empty block, so no vehicle is selected @@ -458,19 +458,19 @@ struct DepotWindow : Window { } bool wagon = false; - if (this->vehicle_list.Length() > pos) { + if (this->vehicle_list.size() > pos) { *veh = this->vehicle_list[pos]; /* Skip vehicles that are scrolled off the list */ if (this->type == VEH_TRAIN) x += this->hscroll->GetPosition(); } else { - pos -= this->vehicle_list.Length(); + pos -= (uint)this->vehicle_list.size(); *veh = this->wagon_list[pos]; /* free wagons don't have an initial loco. */ x -= ScaleGUITrad(VEHICLEINFO_FULL_VEHICLE_WIDTH); wagon = true; } - const Train *v = NULL; + const Train *v = nullptr; if (this->type == VEH_TRAIN) { v = Train::From(*veh); d->head = d->wagon = v; @@ -505,12 +505,12 @@ struct DepotWindow : Window { x -= this->header_width; /* find the vehicle in this row that was clicked */ - for (; v != NULL; v = v->Next()) { + for (; v != nullptr; v = v->Next()) { x -= v->GetDisplayImageWidth(); if (x < 0) break; } - d->wagon = (v != NULL ? v->GetFirstEnginePart() : NULL); + d->wagon = (v != nullptr ? v->GetFirstEnginePart() : nullptr); return MODE_DRAG_VEHICLE; } @@ -522,8 +522,8 @@ struct DepotWindow : Window { */ void DepotClick(int x, int y) { - GetDepotVehiclePtData gdvp = { NULL, NULL }; - const Vehicle *v = NULL; + GetDepotVehiclePtData gdvp = { nullptr, nullptr }; + const Vehicle *v = nullptr; DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp); if (this->type == VEH_TRAIN) v = gdvp.wagon; @@ -533,14 +533,14 @@ struct DepotWindow : Window { return; case MODE_DRAG_VEHICLE: { // start dragging of vehicle - if (v != NULL && VehicleClicked(v)) return; + if (v != nullptr && VehicleClicked(v)) return; VehicleID sel = this->sel; if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) { this->sel = INVALID_VEHICLE; TrainDepotMoveVehicle(v, sel, gdvp.head); - } else if (v != NULL) { + } else if (v != nullptr) { SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); SetMouseCursorVehicle(v, EIT_IN_DEPOT); _cursor.vehchain = _ctrl_pressed; @@ -630,7 +630,7 @@ struct DepotWindow : Window { uint flag_width; uint flag_height; - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_D_MATRIX: { @@ -681,12 +681,12 @@ struct DepotWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { this->generate_list = true; } - virtual void OnPaint() + void OnPaint() override { if (this->generate_list) { /* Generate the vehicle list @@ -706,19 +706,19 @@ struct DepotWindow : Window { /* determine amount of items for scroller */ if (this->type == VEH_TRAIN) { uint max_width = ScaleGUITrad(VEHICLEINFO_FULL_VEHICLE_WIDTH); - for (uint num = 0; num < this->vehicle_list.Length(); num++) { + for (uint num = 0; num < this->vehicle_list.size(); num++) { uint width = 0; - for (const Train *v = Train::From(this->vehicle_list[num]); v != NULL; v = v->Next()) { + for (const Train *v = Train::From(this->vehicle_list[num]); v != nullptr; v = v->Next()) { width += v->GetDisplayImageWidth(); } max_width = max(max_width, width); } /* Always have 1 empty row, so people can change the setting of the train */ - this->vscroll->SetCount(this->vehicle_list.Length() + this->wagon_list.Length() + 1); + this->vscroll->SetCount((uint)this->vehicle_list.size() + (uint)this->wagon_list.size() + 1); /* Always make it longer than the longest train, so you can attach vehicles at the end, and also see the next vertical tile separator line */ this->hscroll->SetCount(max_width + ScaleGUITrad(2 * VEHICLEINFO_FULL_VEHICLE_WIDTH + 1)); } else { - this->vscroll->SetCount(CeilDiv(this->vehicle_list.Length(), this->num_columns)); + this->vscroll->SetCount(CeilDiv((uint)this->vehicle_list.size(), this->num_columns)); } /* Setup disabled buttons. */ @@ -738,7 +738,7 @@ struct DepotWindow : Window { this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_D_MATRIX: { // List @@ -791,7 +791,7 @@ struct DepotWindow : Window { case WID_D_SELL_ALL: /* Only open the confirmation window if there are anything to sell */ - if (this->vehicle_list.Length() != 0 || this->wagon_list.Length() != 0) { + if (this->vehicle_list.size() != 0 || this->wagon_list.size() != 0) { TileIndex tile = this->window_number; byte vehtype = this->type; @@ -817,26 +817,26 @@ struct DepotWindow : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; /* Do depot renaming */ - DoCommandP(0, GetDepotIndex(this->window_number), 0, CMD_RENAME_DEPOT | CMD_MSG(STR_ERROR_CAN_T_RENAME_DEPOT), NULL, str); + DoCommandP(0, GetDepotIndex(this->window_number), 0, CMD_RENAME_DEPOT | CMD_MSG(STR_ERROR_CAN_T_RENAME_DEPOT), nullptr, str); } - virtual bool OnRightClick(Point pt, int widget) + bool OnRightClick(Point pt, int widget) override { if (widget != WID_D_MATRIX) return false; - GetDepotVehiclePtData gdvp = { NULL, NULL }; - const Vehicle *v = NULL; + GetDepotVehiclePtData gdvp = { nullptr, nullptr }; + const Vehicle *v = nullptr; NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp); if (this->type == VEH_TRAIN) v = gdvp.wagon; - if (v == NULL || mode != MODE_DRAG_VEHICLE) return false; + if (v == nullptr || mode != MODE_DRAG_VEHICLE) return false; CargoArray capacity, loaded; @@ -845,7 +845,7 @@ struct DepotWindow : Window { /* loop through vehicle chain and collect cargoes */ uint num = 0; - for (const Vehicle *w = v; w != NULL; w = w->Next()) { + for (const Vehicle *w = v; w != nullptr; w = w->Next()) { if (w->cargo_cap > 0 && w->cargo_type < NUM_CARGO) { capacity[w->cargo_type] += w->cargo_cap; loaded [w->cargo_type] += w->cargo.StoredCount(); @@ -886,11 +886,11 @@ struct DepotWindow : Window { * @param v the original vehicle to clone * @return Always true. */ - virtual bool OnVehicleSelect(const Vehicle *v) + bool OnVehicleSelect(const Vehicle *v) override { if (_ctrl_pressed) { /* Share-clone, do not open new viewport, and keep tool active */ - DoCommandP(this->window_number, v->index, 1, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), NULL); + DoCommandP(this->window_number, v->index, 1, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), nullptr); } else { /* Copy-clone, open viewport for new vehicle, and deselect the tool (assume player wants to changs things on new vehicle) */ if (DoCommandP(this->window_number, v->index, 0, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), CcCloneVehicle)) { @@ -901,7 +901,7 @@ struct DepotWindow : Window { return true; } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { /* abort clone */ this->RaiseWidget(WID_D_CLONE); @@ -919,7 +919,7 @@ struct DepotWindow : Window { } } - virtual void OnMouseDrag(Point pt, int widget) + void OnMouseDrag(Point pt, int widget) override { if (this->sel == INVALID_VEHICLE) return; if (widget != this->hovered_widget) { @@ -945,20 +945,20 @@ struct DepotWindow : Window { } NWidgetBase *matrix = this->GetWidget(widget); - const Vehicle *v = NULL; - GetDepotVehiclePtData gdvp = {NULL, NULL}; + const Vehicle *v = nullptr; + GetDepotVehiclePtData gdvp = {nullptr, nullptr}; if (this->GetVehicleFromDepotWndPt(pt.x - matrix->pos_x, pt.y - matrix->pos_y, &v, &gdvp) != MODE_DRAG_VEHICLE) return; VehicleID new_vehicle_over = INVALID_VEHICLE; - if (gdvp.head != NULL) { - if (gdvp.wagon == NULL && gdvp.head->Last()->index != this->sel) { // ..at the end of the train. + if (gdvp.head != nullptr) { + if (gdvp.wagon == nullptr && gdvp.head->Last()->index != this->sel) { // ..at the end of the train. /* NOTE: As a wagon can't be moved at the begin of a train, head index isn't used to mark a drag-and-drop * destination inside a train. This head index is then used to indicate that a wagon is inserted at * the end of the train. */ new_vehicle_over = gdvp.head->index; - } else if (gdvp.wagon != NULL && gdvp.head != gdvp.wagon && + } else if (gdvp.wagon != nullptr && gdvp.head != gdvp.wagon && gdvp.wagon->index != this->sel && gdvp.wagon->Previous()->index != this->sel) { // ..over an existing wagon. new_vehicle_over = gdvp.wagon->index; @@ -971,11 +971,11 @@ struct DepotWindow : Window { this->SetWidgetDirty(widget); } - virtual void OnDragDrop(Point pt, int widget) + void OnDragDrop(Point pt, int widget) override { switch (widget) { case WID_D_MATRIX: { - const Vehicle *v = NULL; + const Vehicle *v = nullptr; VehicleID sel = this->sel; this->sel = INVALID_VEHICLE; @@ -983,20 +983,20 @@ struct DepotWindow : Window { NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); if (this->type == VEH_TRAIN) { - GetDepotVehiclePtData gdvp = { NULL, NULL }; + GetDepotVehiclePtData gdvp = { nullptr, nullptr }; if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) { - if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) { + if (gdvp.wagon != nullptr && gdvp.wagon->index == sel && _ctrl_pressed) { DoCommandP(Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE)); - } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) { + } else if (gdvp.wagon == nullptr || gdvp.wagon->index != sel) { this->vehicle_over = INVALID_VEHICLE; TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head); - } else if (gdvp.head != NULL && gdvp.head->IsFrontEngine()) { + } else if (gdvp.head != nullptr && gdvp.head->IsFrontEngine()) { ShowVehicleViewWindow(gdvp.head); } } - } else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, NULL) == MODE_DRAG_VEHICLE && v != NULL && sel == v->index) { + } else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, nullptr) == MODE_DRAG_VEHICLE && v != nullptr && sel == v->index) { ShowVehicleViewWindow(v); } break; @@ -1026,19 +1026,19 @@ struct DepotWindow : Window { _cursor.vehchain = false; } - virtual void OnTimeout() + void OnTimeout() override { if (!this->IsWidgetDisabled(WID_D_SELL)) { this->RaiseWidget(WID_D_SELL); this->SetWidgetDirty(WID_D_SELL); } - if (this->nested_array[WID_D_SELL] != NULL && !this->IsWidgetDisabled(WID_D_SELL_CHAIN)) { + if (this->nested_array[WID_D_SELL] != nullptr && !this->IsWidgetDisabled(WID_D_SELL_CHAIN)) { this->RaiseWidget(WID_D_SELL_CHAIN); this->SetWidgetDirty(WID_D_SELL_CHAIN); } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_D_MATRIX); NWidgetCore *nwi = this->GetWidget(WID_D_MATRIX); @@ -1049,7 +1049,7 @@ struct DepotWindow : Window { } } - virtual EventState OnCTRLStateChange() + EventState OnCTRLStateChange() override { if (this->sel != INVALID_VEHICLE) { _cursor.vehchain = _ctrl_pressed; @@ -1126,7 +1126,7 @@ static WindowDesc _aircraft_depot_desc( */ void ShowDepotWindow(TileIndex tile, VehicleType type) { - if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != NULL) return; + if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != nullptr) return; WindowDesc *desc; switch (type) { @@ -1154,7 +1154,7 @@ void DeleteDepotHighlightOfVehicle(const Vehicle *v) if (_special_mouse_mode != WSM_DRAGDROP) return; w = dynamic_cast(FindWindowById(WC_VEHICLE_DEPOT, v->tile)); - if (w != NULL) { + if (w != nullptr) { if (w->sel == v->index) ResetObjectToPlace(); } } diff --git a/src/direction_type.h b/src/direction_type.h index e6e08a182f..cf6b9f5cf1 100644 --- a/src/direction_type.h +++ b/src/direction_type.h @@ -23,7 +23,7 @@ * your viewport and not rotated by 45 degrees left or right to get * a "north" used in you games. */ -enum Direction { +enum Direction : byte { DIR_BEGIN = 0, ///< Used to iterate DIR_N = 0, ///< North DIR_NE = 1, ///< Northeast @@ -42,7 +42,6 @@ DECLARE_POSTFIX_INCREMENT(Direction) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT DirectionByte; ///< typedefing-enumification of Direction /** @@ -77,7 +76,7 @@ enum DirDiff { * * This enumeration is used for the 4 direction of the tile-edges. */ -enum DiagDirection { +enum DiagDirection : byte { DIAGDIR_BEGIN = 0, ///< Used for iterations DIAGDIR_NE = 0, ///< Northeast, upper right on your monitor DIAGDIR_SE = 1, ///< Southeast @@ -92,7 +91,6 @@ DECLARE_POSTFIX_INCREMENT(DiagDirection) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT DiagDirectionByte; ///< typedefing-enumification of DiagDirection /** diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 64ebcd3fa1..57ca0e9f8b 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -62,7 +62,7 @@ static void DisasterClearSquare(TileIndex tile) switch (GetTileType(tile)) { case MP_RAILWAY: if (Company::IsHumanID(GetTileOwner(tile)) && !IsRailDepot(tile)) { - Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); + Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); @@ -72,7 +72,7 @@ static void DisasterClearSquare(TileIndex tile) break; case MP_HOUSE: { - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); break; @@ -137,11 +137,11 @@ DisasterVehicle::DisasterVehicle(int x, int y, Direction direction, DisasterSubT case ST_HELICOPTER: case ST_BIG_UFO: case ST_BIG_UFO_DESTROYER: - GetAircraftFlightLevelBounds(this, &this->z_pos, NULL); + GetAircraftFlightLevelBounds(this, &this->z_pos, nullptr); break; case ST_HELICOPTER_ROTORS: - GetAircraftFlightLevelBounds(this, &this->z_pos, NULL); + GetAircraftFlightLevelBounds(this, &this->z_pos, nullptr); this->z_pos += ROTOR_Z_OFFSET; break; @@ -190,7 +190,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z) this->UpdatePositionAndViewport(); DisasterVehicle *u = this->Next(); - if (u != NULL) { + if (u != nullptr) { int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); int safe_y = Clamp(y - 1, 0, MapMaxY() * TILE_SIZE); @@ -203,7 +203,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z) u->UpdateImage(); u->UpdatePositionAndViewport(); - if ((u = u->Next()) != NULL) { + if ((u = u->Next()) != nullptr) { u->x_pos = x; u->y_pos = y; u->z_pos = z + ROTOR_Z_OFFSET; @@ -357,7 +357,7 @@ static bool DisasterTick_Ufo(DisasterVehicle *v) } else { /* Target a vehicle */ RoadVehicle *u = RoadVehicle::Get(v->dest_tile); - assert(u != NULL && u->type == VEH_ROAD && u->IsFrontEngine()); + assert(u != nullptr && u->type == VEH_ROAD && u->IsFrontEngine()); uint dist = Delta(v->x_pos, u->x_pos) + Delta(v->y_pos, u->y_pos); @@ -748,16 +748,16 @@ static void Disaster_Airplane_Init() { if (!Vehicle::CanAllocateItem(2)) return; - Industry *i, *found = NULL; + Industry *i, *found = nullptr; FOR_ALL_INDUSTRIES(i) { if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_AIRPLANE_ATTACKS) && - (found == NULL || Chance16(1, 2))) { + (found == nullptr || Chance16(1, 2))) { found = i; } } - if (found == NULL) return; + if (found == nullptr) return; /* Start from the bottom (south side) of the map */ int x = (MapSizeX() + 9) * TILE_SIZE - 1; @@ -774,16 +774,16 @@ static void Disaster_Helicopter_Init() { if (!Vehicle::CanAllocateItem(3)) return; - Industry *i, *found = NULL; + Industry *i, *found = nullptr; FOR_ALL_INDUSTRIES(i) { if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_CHOPPER_ATTACKS) && - (found == NULL || Chance16(1, 2))) { + (found == nullptr || Chance16(1, 2))) { found = i; } } - if (found == NULL) return; + if (found == nullptr) return; int x = -16 * (int)TILE_SIZE; int y = TileY(found->location.tile) * TILE_SIZE + 37; @@ -966,7 +966,7 @@ void ReleaseDisastersTargetingVehicle(VehicleID vehicle) /* Revert to target-searching */ v->current_order.SetDestination(0); v->dest_tile = RandomTile(); - GetAircraftFlightLevelBounds(v, &v->z_pos, NULL); + GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr); v->age = 0; } } diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index a2e839feec..314d576036 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -60,7 +60,7 @@ void CcPlaySound_SPLAT_WATER(const CommandCost &result, TileIndex tile, uint32 p * @param[out] tile_to The tile till where to show a selection for the aqueduct. * @return The other end of the aqueduct, or otherwise a tile in line with the aqueduct to cause the right error message. */ -static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = NULL) +static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = nullptr) { int z; DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile_from, &z)); @@ -83,7 +83,7 @@ static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = N if (length > max_length) break; if (GetTileMaxZ(endtile) > z) { - if (tile_to != NULL) *tile_to = endtile; + if (tile_to != nullptr) *tile_to = endtile; break; } } @@ -105,6 +105,7 @@ struct BuildDocksToolbarWindow : Window { ~BuildDocksToolbarWindow() { + if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_DT_STATION)) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -113,7 +114,7 @@ struct BuildDocksToolbarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -129,7 +130,7 @@ struct BuildDocksToolbarWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_DT_CANAL: // Build canal button @@ -173,7 +174,7 @@ struct BuildDocksToolbarWindow : Window { this->last_clicked_widget = (DockToolbarWidgets)widget; } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { switch (this->last_clicked_widget) { case WID_DT_CANAL: // Build canal button @@ -224,12 +225,12 @@ struct BuildDocksToolbarWindow : Window { } } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1) { switch (select_proc) { @@ -248,8 +249,10 @@ struct BuildDocksToolbarWindow : Window { } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { + if (_game_mode != GM_EDITOR && this->IsWidgetLowered(WID_DT_STATION)) SetViewportCatchmentStation(nullptr, true); + this->RaiseButtons(); DeleteWindowById(WC_BUILD_STATION, TRANSPORT_WATER); @@ -258,7 +261,7 @@ struct BuildDocksToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } - virtual void OnPlacePresize(Point pt, TileIndex tile_from) + void OnPlacePresize(Point pt, TileIndex tile_from) override { TileIndex tile_to = tile_from; @@ -289,7 +292,7 @@ static EventState DockToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; Window *w = ShowBuildDocksToolbar(); - if (w == NULL) return ES_NOT_HANDLED; + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -343,11 +346,11 @@ static WindowDesc _build_docks_toolbar_desc( * * If the terraform toolbar is linked to the toolbar, that window is also opened. * - * @return newly opened water toolbar, or NULL if the toolbar could not be opened. + * @return newly opened water toolbar, or nullptr if the toolbar could not be opened. */ Window *ShowBuildDocksToolbar() { - if (!Company::IsValidID(_local_company)) return NULL; + if (!Company::IsValidID(_local_company)) return nullptr; DeleteWindowByClass(WC_BUILD_TOOLBAR); return AllocateWindowDescFront(&_build_docks_toolbar_desc, TRANSPORT_WATER); @@ -384,7 +387,7 @@ static WindowDesc _build_docks_scen_toolbar_desc( /** * Open the build water toolbar window for the scenario editor. * - * @return newly opened water toolbar, or NULL if the toolbar could not be opened. + * @return newly opened water toolbar, or nullptr if the toolbar could not be opened. */ Window *ShowBuildDocksScenToolbar() { @@ -412,7 +415,7 @@ public: DeleteWindowById(WC_SELECT_STATION, 0); } - virtual void OnPaint() + void OnPaint() override { int rad = (_settings_game.station.modified_catchment) ? CA_DOCK : CA_UNMODIFIED; @@ -439,7 +442,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case BDSW_LT_OFF: @@ -453,7 +456,7 @@ public: } } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { CheckRedrawStationCoverage(this); } @@ -477,7 +480,7 @@ static const NWidgetPart _nested_build_dock_station_widgets[] = { }; static WindowDesc _build_dock_station_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_dock_station_widgets, lengthof(_nested_build_dock_station_widgets) @@ -507,7 +510,7 @@ public: UpdateDocksDirection(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BDD_X: @@ -518,7 +521,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { this->DrawWidgets(); @@ -533,7 +536,7 @@ public: DrawShipDepotSprite(this->GetWidget(WID_BDD_Y)->pos_x + x1, this->GetWidget(WID_BDD_Y)->pos_y + y2, AXIS_Y, DEPOT_PART_SOUTH); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BDD_X: @@ -570,7 +573,7 @@ static const NWidgetPart _nested_build_docks_depot_widgets[] = { }; static WindowDesc _build_docks_depot_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_docks_depot_widgets, lengthof(_nested_build_docks_depot_widgets) diff --git a/src/driver.cpp b/src/driver.cpp index 825c489b97..f1b4d67ded 100644 --- a/src/driver.cpp +++ b/src/driver.cpp @@ -18,18 +18,17 @@ #include "safeguards.h" -char *_ini_videodriver; ///< The video driver a stored in the configuration file. -int _num_resolutions; ///< The number of resolutions. -Dimension _resolutions[32]; ///< List of resolutions. -Dimension _cur_resolution; ///< The current resolution. -bool _rightclick_emulate; ///< Whether right clicking is emulated. +char *_ini_videodriver; ///< The video driver a stored in the configuration file. +std::vector _resolutions; ///< List of resolutions. +Dimension _cur_resolution; ///< The current resolution. +bool _rightclick_emulate; ///< Whether right clicking is emulated. -char *_ini_sounddriver; ///< The sound driver a stored in the configuration file. +char *_ini_sounddriver; ///< The sound driver a stored in the configuration file. -char *_ini_musicdriver; ///< The music driver a stored in the configuration file. +char *_ini_musicdriver; ///< The music driver a stored in the configuration file. -char *_ini_blitter; ///< The blitter as stored in the configuration file. -bool _blitter_autodetected; ///< Was the blitter autodetected or specified by the user? +char *_ini_blitter; ///< The blitter as stored in the configuration file. +bool _blitter_autodetected; ///< Was the blitter autodetected or specified by the user? /** * Get a string parameter the list of parameters. @@ -41,10 +40,10 @@ const char *GetDriverParam(const char * const *parm, const char *name) { size_t len; - if (parm == NULL) return NULL; + if (parm == nullptr) return nullptr; len = strlen(name); - for (; *parm != NULL; parm++) { + for (; *parm != nullptr; parm++) { const char *p = *parm; if (strncmp(p, name, len) == 0) { @@ -52,7 +51,7 @@ const char *GetDriverParam(const char * const *parm, const char *name) if (p[len] == '\0') return p + len; } } - return NULL; + return nullptr; } /** @@ -63,7 +62,7 @@ const char *GetDriverParam(const char * const *parm, const char *name) */ bool GetDriverParamBool(const char * const *parm, const char *name) { - return GetDriverParam(parm, name) != NULL; + return GetDriverParam(parm, name) != nullptr; } /** @@ -76,7 +75,7 @@ bool GetDriverParamBool(const char * const *parm, const char *name) int GetDriverParamInt(const char * const *parm, const char *name, int def) { const char *p = GetDriverParam(parm, name); - return p != NULL ? atoi(p) : def; + return p != nullptr ? atoi(p) : def; } /** @@ -120,8 +119,8 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) Driver *newd = d->CreateInstance(); *GetActiveDriver(type) = newd; - const char *err = newd->Start(NULL); - if (err == NULL) { + const char *err = newd->Start(nullptr); + if (err == nullptr) { DEBUG(driver, 1, "Successfully probed %s driver '%s'", GetDriverTypeName(type), d->name); delete oldd; return true; @@ -141,8 +140,8 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) /* Extract the driver name and put parameter list in parm */ strecpy(buffer, name, lastof(buffer)); parm = strchr(buffer, ':'); - parms[0] = NULL; - if (parm != NULL) { + parms[0] = nullptr; + if (parm != nullptr) { uint np = 0; /* Tokenize the parm. */ do { @@ -150,7 +149,7 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) if (np < lengthof(parms) - 1) parms[np++] = parm; while (*parm != '\0' && *parm != ',') parm++; } while (*parm == ','); - parms[np] = NULL; + parms[np] = nullptr; } /* Find this driver */ @@ -168,7 +167,7 @@ bool DriverFactoryBase::SelectDriverImpl(const char *name, Driver::Type type) Driver *newd = d->CreateInstance(); const char *err = newd->Start(parms); - if (err != NULL) { + if (err != nullptr) { delete newd; usererror("Unable to load driver '%s'. The error was: %s", d->name, err); } diff --git a/src/driver.h b/src/driver.h index 12ca4474d4..af387b5d81 100644 --- a/src/driver.h +++ b/src/driver.h @@ -26,7 +26,7 @@ public: /** * Start this driver. * @param parm Parameters passed to the driver. - * @return NULL if everything went okay, otherwise an error message. + * @return nullptr if everything went okay, otherwise an error message. */ virtual const char *Start(const char * const *parm) = 0; @@ -86,7 +86,7 @@ private: */ static Driver **GetActiveDriver(Driver::Type type) { - static Driver *s_driver[3] = { NULL, NULL, NULL }; + static Driver *s_driver[3] = { nullptr, nullptr, nullptr }; return &s_driver[type]; } @@ -116,7 +116,7 @@ public: { for (Driver::Type dt = Driver::DT_BEGIN; dt < Driver::DT_END; dt++) { Driver *driver = *GetActiveDriver(dt); - if (driver != NULL) driver->Stop(); + if (driver != nullptr) driver->Stop(); } } diff --git a/src/economy.cpp b/src/economy.cpp index 7659f18ab7..9858b92d3c 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -78,7 +78,7 @@ static inline int32 BigMulS(const int32 a, const int32 b, const uint8 shift) return (int32)((int64)a * (int64)b >> shift); } -typedef SmallVector SmallIndustryList; +typedef std::vector SmallIndustryList; /** * Score info, values used for computing the detailed performance rating. @@ -292,16 +292,14 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) /* We need to set _current_company to old_owner before we try to move * the client. This is needed as it needs to know whether "you" really * are the current local company. */ - Backup cur_company(_current_company, old_owner, FILE_LINE); -#ifdef ENABLE_NETWORK + Backup cur_company(_current_company, old_owner, FILE_LINE); /* In all cases, make spectators of clients connected to that company */ if (_networking) NetworkClientsToSpectators(old_owner); -#endif /* ENABLE_NETWORK */ if (old_owner == _local_company) { /* Single player cheated to AI company. * There are no spectators in single player, so we must pick some other company. */ assert(!_networking); - Backup cur_company2(_current_company, FILE_LINE); + Backup cur_company2(_current_company, FILE_LINE); Company *c; FOR_ALL_COMPANIES(c) { if (c->index != old_owner) { @@ -335,7 +333,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) } /* Sell all the shares that people have on this company */ - Backup cur_company2(_current_company, FILE_LINE); + Backup cur_company2(_current_company, FILE_LINE); c = Company::Get(old_owner); for (i = 0; i < 4; i++) { cur_company2.Change(c->share_owners[i]); @@ -406,7 +404,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) FOR_ALL_VEHICLES(v) { if (v->owner == old_owner && IsCompanyBuildableVehicleType(v->type)) { if (new_owner == INVALID_OWNER) { - if (v->Previous() == NULL) delete v; + if (v->Previous() == nullptr) delete v; } else { if (v->IsEngineCountable()) GroupStatistics::CountEngine(v, -1); if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, -1); @@ -481,7 +479,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) } /* Invalidate the vehicle's cargo payment "owner cache". */ - if (v->cargo_payment != NULL) v->cargo_payment->owner = NULL; + if (v->cargo_payment != nullptr) v->cargo_payment->owner = nullptr; } } @@ -670,7 +668,7 @@ static void CompaniesGenStatistics() CompanyCheckBankrupt(c); } - Backup cur_company(_current_company, FILE_LINE); + Backup cur_company(_current_company, FILE_LINE); if (!_settings_game.economy.infrastructure_maintenance) { Station *st; @@ -690,8 +688,10 @@ static void CompaniesGenStatistics() if (c->infrastructure.rail[rt] != 0) cost.AddCost(RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); } cost.AddCost(SignalMaintenanceCost(c->infrastructure.signal)); + uint32 road_total = c->infrastructure.GetRoadTotal(); + uint32 tram_total = c->infrastructure.GetTramTotal(); for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { - if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt])); + if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total)); } cost.AddCost(CanalMaintenanceCost(c->infrastructure.water)); cost.AddCost(StationMaintenanceCost(c->infrastructure.station)); @@ -840,7 +840,7 @@ static void CompaniesPayInterest() { const Company *c; - Backup cur_company(_current_company, FILE_LINE); + Backup cur_company(_current_company, FILE_LINE); FOR_ALL_COMPANIES(c) { cur_company.Change(c->index); @@ -971,7 +971,7 @@ Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift if (index >= PR_END) return 0; Money cost = _price[index] * cost_factor; - if (grf_file != NULL) shift += grf_file->price_base_multipliers[index]; + if (grf_file != nullptr) shift += grf_file->price_base_multipliers[index]; if (shift >= 0) { cost <<= shift; @@ -1054,8 +1054,9 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n uint accepted = 0; - for (uint i = 0; i < st->industries_near.Length() && num_pieces != 0; i++) { - Industry *ind = st->industries_near[i]; + for (Industry *ind : st->industries_near) { + if (num_pieces == 0) break; + if (ind->index == source) continue; uint cargo_index; @@ -1069,7 +1070,7 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n if (IndustryTemporarilyRefusesCargo(ind, cargo_type)) continue; /* Insert the industry into _cargo_delivery_destinations, if not yet contained */ - _cargo_delivery_destinations.Include(ind); + include(_cargo_delivery_destinations, ind); uint amount = min(num_pieces, 0xFFFFU - ind->incoming_cargo_waiting[cargo_index]); ind->incoming_cargo_waiting[cargo_index] += amount; @@ -1209,11 +1210,11 @@ CargoPayment::~CargoPayment() { if (this->CleaningPool()) return; - this->front->cargo_payment = NULL; + this->front->cargo_payment = nullptr; if (this->visual_profit == 0 && this->visual_transfer == 0) return; - Backup cur_company(_current_company, this->front->owner, FILE_LINE); + Backup cur_company(_current_company, this->front->owner, FILE_LINE); SubtractMoneyFromCompany(CommandCost(this->front->GetExpenseType(true), -this->route_profit)); this->front->profit_this_year += (this->visual_profit + this->visual_transfer) << 8; @@ -1240,7 +1241,7 @@ CargoPayment::~CargoPayment() */ void CargoPayment::PayFinalDelivery(const CargoPacket *cp, uint count) { - if (this->owner == NULL) { + if (this->owner == nullptr) { this->owner = Company::Get(this->front->owner); } @@ -1288,7 +1289,7 @@ void PrepareUnload(Vehicle *front_v) /* Start unloading at the first possible moment */ front_v->load_unload_ticks = 1; - assert(front_v->cargo_payment == NULL); + assert(front_v->cargo_payment == nullptr); /* One CargoPayment per vehicle and the vehicle limit equals the * limit in number of CargoPayments. Can't go wrong. */ assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); @@ -1296,9 +1297,9 @@ void PrepareUnload(Vehicle *front_v) front_v->cargo_payment = new CargoPayment(front_v); StationIDStack next_station = front_v->GetNextStoppingStation(); - if (front_v->orders.list == NULL || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { + if (front_v->orders.list == nullptr || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { Station *st = Station::Get(front_v->last_station_visited); - for (Vehicle *v = front_v; v != NULL; v = v->Next()) { + for (Vehicle *v = front_v; v != nullptr; v = v->Next()) { const GoodsEntry *ge = &st->goods[v->cargo_type]; if (v->cargo_cap > 0 && v->cargo.TotalCount() > 0) { v->cargo.Stage( @@ -1329,7 +1330,7 @@ static uint GetLoadAmount(Vehicle *v) if (_settings_game.order.gradual_loading) { uint16 cb_load_amount = CALLBACK_FAILED; - if (e->GetGRF() != NULL && e->GetGRF()->grf_version >= 8) { + if (e->GetGRF() != nullptr && e->GetGRF()->grf_version >= 8) { /* Use callback 36 */ cb_load_amount = GetVehicleProperty(v, PROP_VEHICLE_LOAD_AMOUNT, CALLBACK_FAILED); } else if (HasBit(e->info.callback_mask, CBM_VEHICLE_LOAD_AMOUNT)) { @@ -1365,8 +1366,8 @@ static uint GetLoadAmount(Vehicle *v) template bool IterateVehicleParts(Vehicle *v, Taction action) { - for (Vehicle *w = v; w != NULL; - w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : NULL) { + for (Vehicle *w = v; w != nullptr; + w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : nullptr) { if (!action(w)) return false; if (w->type == VEH_TRAIN) { Train *train = Train::From(w); @@ -1500,7 +1501,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station Vehicle *v_start = v->GetFirstEnginePart(); if (!IterateVehicleParts(v_start, IsEmptyAction())) return; - Backup cur_company(_current_company, v->owner, FILE_LINE); + Backup cur_company(_current_company, v->owner, FILE_LINE); CargoTypes refit_mask = v->GetEngine()->info.refit_mask; @@ -1593,8 +1594,8 @@ static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, /* If there is a cargo payment not all vehicles of the consist have tried to do the refit. * In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain" * a vehicle belongs to already has the right cargo. */ - bool must_reserve = !u->current_order.IsRefit() || u->cargo_payment == NULL; - for (Vehicle *v = u; v != NULL; v = v->Next()) { + bool must_reserve = !u->current_order.IsRefit() || u->cargo_payment == nullptr; + for (Vehicle *v = u; v != nullptr; v = v->Next()) { assert(v->cargo_cap >= v->cargo.RemainingCount()); /* Exclude various ways in which the vehicle might not be the head of an equivalent of @@ -1606,7 +1607,7 @@ static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, (must_reserve || u->current_order.GetRefitCargo() == v->cargo_type)) { IterateVehicleParts(v, ReserveCargoAction(st, next_station)); } - if (consist_capleft == NULL || v->cargo_cap == 0) continue; + if (consist_capleft == nullptr || v->cargo_cap == 0) continue; (*consist_capleft)[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); } } @@ -1647,9 +1648,9 @@ static void LoadUnloadVehicle(Vehicle *front) bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CT_AUTO_REFIT; CargoArray consist_capleft; if (_settings_game.order.improved_load && use_autorefit ? - front->cargo_payment == NULL : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) { + front->cargo_payment == nullptr : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) { ReserveConsist(st, front, - (use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : NULL, + (use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : nullptr, &next_station); } @@ -1681,7 +1682,7 @@ static void LoadUnloadVehicle(Vehicle *front) CargoPayment *payment = front->cargo_payment; uint artic_part = 0; // Articulated part we are currently trying to load. (not counting parts without capacity) - for (Vehicle *v = front; v != NULL; v = v->Next()) { + for (Vehicle *v = front; v != nullptr; v = v->Next()) { if (v == front || !v->Previous()->HasArticulatedPart()) artic_part = 0; if (v->cargo_cap == 0) continue; artic_part++; @@ -1693,7 +1694,7 @@ static void LoadUnloadVehicle(Vehicle *front) uint amount_unloaded = _settings_game.order.gradual_loading ? min(cargo_count, GetLoadAmount(v)) : cargo_count; bool remaining = false; // Are there cargo entities in this vehicle that can still be unloaded here? - assert(payment != NULL); + assert(payment != nullptr); payment->SetCargo(v->cargo_type); if (!HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE) && v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER) > 0) { @@ -1726,7 +1727,7 @@ static void LoadUnloadVehicle(Vehicle *front) dirty_station = true; if (!ge->HasRating()) { - /* Upon transfering cargo, make sure the station has a rating. Fake a pickup for the + /* Upon transferring cargo, make sure the station has a rating. Fake a pickup for the * first unload to prevent the cargo from quickly decaying after the initial drop. */ ge->time_since_pickup = 0; SetBit(ge->status, GoodsEntry::GES_RATING); @@ -1945,7 +1946,7 @@ void LoadUnloadStation(Station *st) /* No vehicle is here... */ if (st->loading_vehicles.empty()) return; - Vehicle *last_loading = NULL; + Vehicle *last_loading = nullptr; std::list::iterator iter; /* Check if anything will be loaded at all. Otherwise we don't need to reserve either. */ @@ -1965,7 +1966,7 @@ void LoadUnloadStation(Station *st) * consist in a station which is not allowed to load yet because its * load_unload_ticks is still not 0. */ - if (last_loading == NULL) return; + if (last_loading == nullptr) return; for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) { Vehicle *v = *iter; @@ -1974,11 +1975,10 @@ void LoadUnloadStation(Station *st) } /* Call the production machinery of industries */ - const Industry * const *isend = _cargo_delivery_destinations.End(); - for (Industry **iid = _cargo_delivery_destinations.Begin(); iid != isend; iid++) { - TriggerIndustryProduction(*iid); + for (Industry *iid : _cargo_delivery_destinations) { + TriggerIndustryProduction(iid); } - _cargo_delivery_destinations.Clear(); + _cargo_delivery_destinations.clear(); } /** @@ -2053,10 +2053,10 @@ CommandCost CmdBuyShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, /* Check if buying shares is allowed (protection against modified clients) * Cannot buy own shares */ - if (c == NULL || !_settings_game.economy.allow_shares || _current_company == target_company) return CMD_ERROR; + if (c == nullptr || !_settings_game.economy.allow_shares || _current_company == target_company) return CMD_ERROR; /* Protect new companies from hostile takeovers */ - if (_cur_year - c->inaugurated_year < 6) return_cmd_error(STR_ERROR_PROTECTED); + if (_cur_year - c->inaugurated_year < _settings_game.economy.min_years_for_shares) return_cmd_error(STR_ERROR_PROTECTED); /* Those lines are here for network-protection (clients can be slow) */ if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 0) return cost; @@ -2070,7 +2070,7 @@ CommandCost CmdBuyShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, cost.AddCost(CalculateCompanyValue(c) >> 2); if (flags & DC_EXEC) { - OwnerByte *b = c->share_owners; + Owner *b = c->share_owners; while (*b != COMPANY_SPECTATOR) b++; // share owners is guaranteed to contain at least one COMPANY_SPECTATOR *b = _current_company; @@ -2103,7 +2103,7 @@ CommandCost CmdSellShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1 Company *c = Company::GetIfValid(target_company); /* Cannot sell own shares */ - if (c == NULL || _current_company == target_company) return CMD_ERROR; + if (c == nullptr || _current_company == target_company) return CMD_ERROR; /* Check if selling shares is allowed (protection against modified clients). * However, we must sell shares of companies being closed down. */ @@ -2117,7 +2117,7 @@ CommandCost CmdSellShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1 cost = -(cost - (cost >> 7)); if (flags & DC_EXEC) { - OwnerByte *b = c->share_owners; + Owner *b = c->share_owners; while (*b != _current_company) b++; // share owners is guaranteed to contain company *b = COMPANY_SPECTATOR; InvalidateWindowData(WC_COMPANY, target_company); @@ -2142,7 +2142,7 @@ CommandCost CmdBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 { CompanyID target_company = (CompanyID)p1; Company *c = Company::GetIfValid(target_company); - if (c == NULL) return CMD_ERROR; + if (c == nullptr) return CMD_ERROR; /* Disable takeovers when not asked */ if (!HasBit(c->bankrupt_asked, _current_company)) return CMD_ERROR; diff --git a/src/economy_type.h b/src/economy_type.h index 31f74aacc7..aa5ab5daeb 100644 --- a/src/economy_type.h +++ b/src/economy_type.h @@ -147,7 +147,7 @@ typedef Money Prices[PR_END]; ///< Prices of everything. @see Price typedef int8 PriceMultipliers[PR_END]; /** Types of expenses. */ -enum ExpensesType { +enum ExpensesType : byte { EXPENSES_CONSTRUCTION = 0, ///< Construction costs. EXPENSES_NEW_VEHICLES, ///< New vehicles. EXPENSES_TRAIN_RUN, ///< Running costs trains. @@ -167,7 +167,6 @@ enum ExpensesType { /** Define basic enum properties for ExpensesType */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT ExpensesTypeByte; ///< typedefing-enumification of ExpensesType /** * Categories of a price bases. diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 4d8f58acb8..76c06a181d 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -595,7 +595,7 @@ assert_compile(lengthof(_effect_transparency_options) == EV_END); */ EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type) { - if (!Vehicle::CanAllocateItem()) return NULL; + if (!Vehicle::CanAllocateItem()) return nullptr; EffectVehicle *v = new EffectVehicle(); v->subtype = type; diff --git a/src/elrail.cpp b/src/elrail.cpp index 9fdfb57a3d..b3f447ef88 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -82,7 +82,7 @@ static inline TLG GetTLG(TileIndex t) /** * Finds which Electrified Rail Bits are present on a given tile. * @param t tile to check - * @param override pointer to PCP override, can be NULL + * @param override pointer to PCP override, can be nullptr * @return trackbits of tile if it is electrified */ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override) @@ -101,7 +101,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override) case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(t) != TRANSPORT_RAIL) return TRACK_BIT_NONE; if (!HasRailCatenary(GetRailType(t))) return TRACK_BIT_NONE; - if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) { + if (override != nullptr && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) { *override = 1 << GetTunnelBridgeDirection(t); } return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)); @@ -326,7 +326,7 @@ static void DrawRailCatenaryRailway(const TileInfo *ti) /* Here's one of the main headaches. GetTileSlope does not correct for possibly * existing foundataions, so we do have to do that manually later on.*/ tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour); - trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL); + trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, nullptr); wireconfig[TS_NEIGHBOUR] = MaskWireBits(neighbour, trackconfig[TS_NEIGHBOUR]); if (IsTunnelTile(neighbour) && i != GetTunnelBridgeDirection(neighbour)) wireconfig[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE; diff --git a/src/engine.cpp b/src/engine.cpp index d539a48520..f9363b6014 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -69,9 +69,9 @@ assert_compile(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_i const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; Engine::Engine() : - name(NULL), + name(nullptr), overrides_count(0), - overrides(NULL) + overrides(nullptr) { } @@ -162,7 +162,7 @@ bool Engine::IsEnabled() const uint32 Engine::GetGRFID() const { const GRFFile *file = this->GetGRF(); - return file == NULL ? 0 : file->grfid; + return file == nullptr ? 0 : file->grfid; } /** @@ -199,28 +199,28 @@ bool Engine::CanCarryCargo() const /** * Determines capacity of a given vehicle from scratch. * For aircraft the main capacity is determined. Mail might be present as well. - * @param v Vehicle of interest; NULL in purchase list + * @param v Vehicle of interest; nullptr in purchase list * @param mail_capacity returns secondary cargo (mail) capacity of aircraft * @return Capacity */ uint Engine::DetermineCapacity(const Vehicle *v, uint16 *mail_capacity) const { - assert(v == NULL || this->index == v->engine_type); - if (mail_capacity != NULL) *mail_capacity = 0; + assert(v == nullptr || this->index == v->engine_type); + if (mail_capacity != nullptr) *mail_capacity = 0; if (!this->CanCarryCargo()) return 0; bool new_multipliers = HasBit(this->info.misc_flags, EF_NO_DEFAULT_CARGO_MULTIPLIER); CargoID default_cargo = this->GetDefaultCargoType(); - CargoID cargo_type = (v != NULL) ? v->cargo_type : default_cargo; + CargoID cargo_type = (v != nullptr) ? v->cargo_type : default_cargo; - if (mail_capacity != NULL && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) { + if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) { *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v); } /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */ if (HasBit(this->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && - (new_multipliers || default_cargo != cargo_type || (v != NULL && v->cargo_subtype != 0))) { + (new_multipliers || default_cargo != cargo_type || (v != nullptr && v->cargo_subtype != 0))) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v); if (callback != CALLBACK_FAILED) return callback; } @@ -233,7 +233,7 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16 *mail_capacity) const capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v); /* In purchase list add the capacity of the second head. Always use the plain property for this. */ - if (v == NULL && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity; + if (v == nullptr && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity; break; case VEH_ROAD: @@ -487,14 +487,15 @@ StringID Engine::GetAircraftTypeText() const */ void EngineOverrideManager::ResetToDefaultMapping() { - this->Clear(); + this->clear(); for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) { for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) { - EngineIDMapping *eid = this->Append(); - eid->type = type; - eid->grfid = INVALID_GRFID; - eid->internal_id = internal_id; - eid->substitute_id = internal_id; + /*C++17: EngineIDMapping &eid = */ this->emplace_back(); + EngineIDMapping &eid = this->back(); + eid.type = type; + eid.grfid = INVALID_GRFID; + eid.internal_id = internal_id; + eid.substitute_id = internal_id; } } } @@ -510,12 +511,12 @@ void EngineOverrideManager::ResetToDefaultMapping() */ EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid) { - const EngineIDMapping *end = this->End(); EngineID index = 0; - for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) { - if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) { + for (const EngineIDMapping &eid : *this) { + if (eid.type == type && eid.grfid == grfid && eid.internal_id == grf_local_id) { return index; } + index++; } return INVALID_ENGINE; } @@ -547,15 +548,15 @@ void SetupEngines() DeleteWindowByClass(WC_ENGINE_PREVIEW); _engine_pool.CleanPool(); - assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES); - const EngineIDMapping *end = _engine_mngr.End(); + assert(_engine_mngr.size() >= _engine_mngr.NUM_DEFAULT_ENGINES); uint index = 0; - for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) { + for (const EngineIDMapping &eid : _engine_mngr) { /* Assert is safe; there won't be more than 256 original vehicles * in any case, and we just cleaned the pool. */ assert(Engine::CanAllocateItem()); - const Engine *e = new Engine(eid->type, eid->internal_id); + const Engine *e = new Engine(eid.type, eid.internal_id); assert(e->index == index); + index++; } } @@ -707,7 +708,7 @@ void StartupEngines() Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = GetCompanyRailtypes(c->index); - c->avail_roadtypes = GetCompanyRoadtypes(c->index); + c->avail_roadtypes = GetCompanyRoadTypes(c->index); } /* Invalidate any open purchase lists */ @@ -729,7 +730,8 @@ static void AcceptEnginePreview(EngineID eid, CompanyID company) assert(e->u.rail.railtype < RAILTYPE_END); c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); } else if (e->type == VEH_ROAD) { - SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); + assert(e->u.road.roadtype < ROADTYPE_END); + c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, _date); } e->preview_company = INVALID_COMPANY; @@ -809,6 +811,7 @@ void EnginesDailyLoop() Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date); + c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes, _date); } if (_cur_year >= _year_engine_aging_stops) return; @@ -868,7 +871,7 @@ void ClearEnginesHiddenFlagOfCompany(CompanyID cid) CommandCost CmdSetVehicleVisibility(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Engine *e = Engine::GetIfValid(GB(p2, 0, 31)); - if (e == NULL || _current_company >= MAX_COMPANIES) return CMD_ERROR; + if (e == nullptr || _current_company >= MAX_COMPANIES) return CMD_ERROR; if (!IsEngineBuildable(e->index, e->type, _current_company)) return CMD_ERROR; if ((flags & DC_EXEC) != 0) { @@ -892,7 +895,7 @@ CommandCost CmdSetVehicleVisibility(TileIndex tile, DoCommandFlag flags, uint32 CommandCost CmdWantEnginePreview(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Engine *e = Engine::GetIfValid(p1); - if (e == NULL || !(e->flags & ENGINE_EXCLUSIVE_PREVIEW) || e->preview_company != _current_company) return CMD_ERROR; + if (e == nullptr || !(e->flags & ENGINE_EXCLUSIVE_PREVIEW) || e->preview_company != _current_company) return CMD_ERROR; if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company); @@ -950,7 +953,8 @@ static void NewVehicleAvailable(Engine *e) FOR_ALL_COMPANIES(c) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); } else if (e->type == VEH_ROAD) { /* maybe make another road type available */ - FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); + assert(e->u.road.roadtype < ROADTYPE_END); + FOR_ALL_COMPANIES(c) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, _date); } /* Only broadcast event if AIs are able to build this vehicle type. */ @@ -1020,7 +1024,7 @@ static bool IsUniqueEngineName(const char *name) const Engine *e; FOR_ALL_ENGINES(e) { - if (e->name != NULL && strcmp(e->name, name) == 0) return false; + if (e->name != nullptr && strcmp(e->name, name) == 0) return false; } return true; @@ -1038,7 +1042,7 @@ static bool IsUniqueEngineName(const char *name) CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Engine *e = Engine::GetIfValid(p1); - if (e == NULL) return CMD_ERROR; + if (e == nullptr) return CMD_ERROR; bool reset = StrEmpty(text); @@ -1051,7 +1055,7 @@ CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint free(e->name); if (reset) { - e->name = NULL; + e->name = nullptr; } else { e->name = stredup(text); } @@ -1076,7 +1080,7 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company) const Engine *e = Engine::GetIfValid(engine); /* check if it's an engine that is in the engine array */ - if (e == NULL) return false; + if (e == nullptr) return false; /* check if it's an engine of specified type */ if (e->type != type) return false; @@ -1097,6 +1101,11 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company) const Company *c = Company::Get(company); if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false; } + if (type == VEH_ROAD && company != OWNER_DEITY) { + /* Check if the road type is available to this company */ + const Company *c = Company::Get(company); + if ((GetRoadTypeInfo(e->u.road.roadtype)->powered_roadtypes & c->avail_roadtypes) == ROADTYPES_NONE) return false; + } return true; } @@ -1112,7 +1121,7 @@ bool IsEngineRefittable(EngineID engine) const Engine *e = Engine::GetIfValid(engine); /* check if it's an engine that is in the engine array */ - if (e == NULL) return false; + if (e == nullptr) return false; if (!e->CanCarryCargo()) return false; diff --git a/src/engine_base.h b/src/engine_base.h index 25c6bfbeb9..a8dbb873c1 100644 --- a/src/engine_base.h +++ b/src/engine_base.h @@ -34,7 +34,7 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { uint16 duration_phase_3; ///< Third reliability phase on months, decaying to #reliability_final. byte flags; ///< Flags of the engine. @see EngineFlags CompanyMask preview_asked; ///< Bit for each company which has already been offered a preview. - CompanyByte preview_company;///< Company which is currently being offered a preview \c INVALID_COMPANY means no company. + CompanyID preview_company; ///< Company which is currently being offered a preview \c INVALID_COMPANY means no company. byte preview_wait; ///< Daily countdown timer for timeout of offering the engine to the #preview_company company. CompanyMask company_avail; ///< Bit for each company whether the engine is available for that company. CompanyMask company_hidden; ///< Bit for each company whether the engine is normally hidden in the build gui for that company. @@ -83,7 +83,7 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { return this->info.cargo_type; } - uint DetermineCapacity(const Vehicle *v, uint16 *mail_capacity = NULL) const; + uint DetermineCapacity(const Vehicle *v, uint16 *mail_capacity = nullptr) const; bool CanCarryCargo() const; @@ -98,9 +98,9 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { * @return The default capacity * @see GetDefaultCargoType */ - uint GetDisplayDefaultCapacity(uint16 *mail_capacity = NULL) const + uint GetDisplayDefaultCapacity(uint16 *mail_capacity = nullptr) const { - return this->DetermineCapacity(NULL, mail_capacity); + return this->DetermineCapacity(nullptr, mail_capacity); } Money GetRunningCost() const; @@ -118,7 +118,7 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { * @param c Company to check. * @return \c true iff the engine is hidden in the GUI for the given company. */ - inline bool IsHidden(CompanyByte c) const + inline bool IsHidden(CompanyID c) const { return c < MAX_COMPANIES && HasBit(this->company_hidden, c); } @@ -148,7 +148,7 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { struct EngineIDMapping { uint32 grfid; ///< The GRF ID of the file the entity belongs to uint16 internal_id; ///< The internal ID within the GRF file - VehicleTypeByte type; ///< The engine type + VehicleType type; ///< The engine type uint8 substitute_id; ///< The (original) entity ID to use if this GRF is not available (currently not used) }; @@ -156,7 +156,7 @@ struct EngineIDMapping { * Stores the mapping of EngineID to the internal id of newgrfs. * Note: This is not part of Engine, as the data in the EngineOverrideManager and the engine pool get resetted in different cases. */ -struct EngineOverrideManager : SmallVector { +struct EngineOverrideManager : std::vector { static const uint NUM_DEFAULT_ENGINES; ///< Number of default entries void ResetToDefaultMapping(); diff --git a/src/engine_func.h b/src/engine_func.h index 37fb005092..79dad18c72 100644 --- a/src/engine_func.h +++ b/src/engine_func.h @@ -26,7 +26,7 @@ extern const uint8 _engine_offsets[4]; bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company); bool IsEngineRefittable(EngineID engine); -void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits); +void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, CargoTypes *refits, CargoID cargo_type, uint16 cargo_capacity); void SetYearEngineAgingStops(); void StartupOneEngine(Engine *e, Date aging_date); diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp index 51c7e14836..90cba6ed18 100644 --- a/src/engine_gui.cpp +++ b/src/engine_gui.cpp @@ -19,6 +19,7 @@ #include "vehicle_func.h" #include "company_func.h" #include "rail.h" +#include "road.h" #include "settings_type.h" #include "train.h" #include "roadveh.h" @@ -41,7 +42,8 @@ StringID GetEngineCategoryName(EngineID engine) const Engine *e = Engine::Get(engine); switch (e->type) { default: NOT_REACHED(); - case VEH_ROAD: return STR_ENGINE_PREVIEW_ROAD_VEHICLE; + case VEH_ROAD: + return GetRoadTypeInfo(e->u.road.roadtype)->strings.new_engine; case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT; case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP; case VEH_TRAIN: @@ -75,7 +77,7 @@ struct EnginePreviewWindow : Window { this->flags |= WF_STICKY; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_EP_QUESTION) return; @@ -102,7 +104,7 @@ struct EnginePreviewWindow : Window { size->height += GetStringHeight(GetEngineInfoString(engine), size->width); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_EP_QUESTION) return; @@ -121,7 +123,7 @@ struct EnginePreviewWindow : Window { DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_EP_YES: @@ -133,7 +135,7 @@ struct EnginePreviewWindow : Window { } } - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -325,11 +327,8 @@ void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID eng */ void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare) { - uint size = el->Length(); - /* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems) - * generally, do not sort if there are less than 2 items */ - if (size < 2) return; - QSortT(el->Begin(), size, compare); + if (el->size() < 2) return; + std::sort(el->begin(), el->end(), compare); } /** @@ -342,8 +341,8 @@ void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare) void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items) { if (num_items < 2) return; - assert(begin < el->Length()); - assert(begin + num_items <= el->Length()); - QSortT(el->Get(begin), num_items, compare); + assert(begin < el->size()); + assert(begin + num_items <= el->size()); + std::sort(el->begin() + begin, el->begin() + begin + num_items, compare); } diff --git a/src/engine_gui.h b/src/engine_gui.h index fc0b7ad7d9..e95cc13e4d 100644 --- a/src/engine_gui.h +++ b/src/engine_gui.h @@ -19,7 +19,7 @@ typedef GUIList GUIEngineList; -typedef int CDECL EngList_SortTypeFunction(const EngineID*, const EngineID*); ///< argument type for #EngList_Sort. +typedef bool EngList_SortTypeFunction(const EngineID&, const EngineID&); ///< argument type for #EngList_Sort. void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare); void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items); diff --git a/src/engine_type.h b/src/engine_type.h index 82f10d9d87..6cc8dc68eb 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -14,6 +14,7 @@ #include "economy_type.h" #include "rail_type.h" +#include "road_type.h" #include "cargo_type.h" #include "date_type.h" #include "sound_type.h" @@ -44,7 +45,7 @@ struct RailVehicleInfo { byte image_index; RailVehicleTypes railveh_type; byte cost_factor; ///< Purchase cost factor; For multiheaded engines the sum of both engine prices. - RailTypeByte railtype; + RailType railtype; uint16 max_speed; ///< Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h) uint16 power; ///< Power of engine (hp); For multiheaded engines the sum of both engine powers. uint16 weight; ///< Weight of vehicle (tons); For multiheaded engines the weight of each single engine. @@ -123,6 +124,7 @@ struct RoadVehicleInfo { uint8 air_drag; ///< Coefficient of air drag byte visual_effect; ///< Bitstuffed NewGRF visual effect data byte shorten_factor; ///< length on main map for this type is 8 - shorten_factor + RoadType roadtype; ///< Road type }; /** diff --git a/src/error.h b/src/error.h index 597b62efbe..fe1ed659e4 100644 --- a/src/error.h +++ b/src/error.h @@ -43,7 +43,7 @@ protected: public: ErrorMessageData(const ErrorMessageData &data); ~ErrorMessageData(); - ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = NULL, uint textref_stack_size = 0, const uint32 *textref_stack = NULL); + ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32 *textref_stack = nullptr); /** Check whether error window shall display a company manager face */ bool HasFace() const { return face != INVALID_COMPANY; } @@ -56,7 +56,7 @@ public: void ScheduleErrorMessage(const ErrorMessageData &data); -void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = NULL, uint textref_stack_size = 0, const uint32 *textref_stack = NULL); +void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = nullptr, uint textref_stack_size = 0, const uint32 *textref_stack = nullptr); void ClearErrorMessages(); void ShowFirstError(); void UnshowCriticalError(); diff --git a/src/error_gui.cpp b/src/error_gui.cpp index 1c59b7e8d0..807bd48e18 100644 --- a/src/error_gui.cpp +++ b/src/error_gui.cpp @@ -72,11 +72,15 @@ static WindowDesc _errmsg_face_desc( * Copy the given data into our instance. * @param data The data to copy. */ -ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) +ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) : + duration(data.duration), textref_stack_grffile(data.textref_stack_grffile), textref_stack_size(data.textref_stack_size), + summary_msg(data.summary_msg), detailed_msg(data.detailed_msg), position(data.position), face(data.face) { - *this = data; + memcpy(this->textref_stack, data.textref_stack, sizeof(this->textref_stack)); + memcpy(this->decode_params, data.decode_params, sizeof(this->decode_params)); + memcpy(this->strings, data.strings, sizeof(this->strings)); for (size_t i = 0; i < lengthof(this->strings); i++) { - if (this->strings[i] != NULL) { + if (this->strings[i] != nullptr) { this->strings[i] = stredup(this->strings[i]); this->decode_params[i] = (size_t)this->strings[i]; } @@ -180,7 +184,7 @@ public: this->InitNested(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_EM_MESSAGE: { @@ -208,7 +212,7 @@ public: } } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { /* Position (0, 0) given, center the window. */ if (this->position.x == 0 && this->position.y == 0) { @@ -244,18 +248,18 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { /* If company gets shut down, while displaying an error about it, remove the error message. */ if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) delete this; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_EM_CAPTION) CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_EM_FACE: { @@ -292,13 +296,13 @@ public: } } - virtual void OnMouseLoop() + void OnMouseLoop() override { /* Disallow closing the window too easily, if timeout is disabled */ if (_right_button_down && this->duration != 0) delete this; } - virtual void OnHundredthTick() + void OnHundredthTick() override { /* Timeout enabled? */ if (this->duration != 0) { @@ -313,7 +317,7 @@ public: if (_window_system_initialized) ShowFirstError(); } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { if (keycode != WKC_SPACE) return ES_NOT_HANDLED; delete this; @@ -357,7 +361,7 @@ void ShowFirstError() void UnshowCriticalError() { ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); - if (_window_system_initialized && w != NULL) { + if (_window_system_initialized && w != nullptr) { if (w->IsCritical()) _error_list.push_front(*w); _window_system_initialized = false; delete w; @@ -377,7 +381,7 @@ void UnshowCriticalError() */ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) { - assert(textref_stack_size == 0 || (textref_stack_grffile != NULL && textref_stack != NULL)); + assert(textref_stack_size == 0 || (textref_stack_grffile != nullptr && textref_stack != nullptr)); if (summary_msg == STR_NULL) summary_msg = STR_EMPTY; if (wl != WL_INFO) { @@ -408,7 +412,7 @@ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel data.CopyOutDParams(); ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); - if (w != NULL && w->IsCritical()) { + if (w != nullptr && w->IsCritical()) { /* A critical error is currently shown. */ if (wl == WL_CRITICAL) { /* Push another critical error in the queue of errors, diff --git a/src/fileio.cpp b/src/fileio.cpp index 0e6d86e3c7..a1a8db8d32 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -29,7 +29,7 @@ #include #ifdef WITH_XDG_BASEDIR -#include "basedir.h" +#include #endif #include "safeguards.h" @@ -99,7 +99,7 @@ void FioSeekTo(size_t pos, int mode) static void FioRestoreFile(int slot) { /* Do we still have the file open, or should we reopen it? */ - if (_fio.handles[slot] == NULL) { + if (_fio.handles[slot] == nullptr) { DEBUG(misc, 6, "Restoring file '%s' in slot '%d' from disk", _fio.filenames[slot], slot); FioOpenFile(slot, _fio.filenames[slot]); } @@ -120,7 +120,7 @@ void FioSeekToFile(uint8 slot, size_t pos) FioRestoreFile(slot); #endif /* LIMITED_FDS */ f = _fio.handles[slot]; - assert(f != NULL); + assert(f != nullptr); _fio.cur_fh = f; _fio.filename = _fio.filenames[slot]; FioSeekTo(pos, SEEK_SET); @@ -196,13 +196,13 @@ void FioReadBlock(void *ptr, size_t size) */ static inline void FioCloseFile(int slot) { - if (_fio.handles[slot] != NULL) { + if (_fio.handles[slot] != nullptr) { fclose(_fio.handles[slot]); free(_fio.shortnames[slot]); - _fio.shortnames[slot] = NULL; + _fio.shortnames[slot] = nullptr; - _fio.handles[slot] = NULL; + _fio.handles[slot] = nullptr; #if defined(LIMITED_FDS) _fio.open_handles--; #endif /* LIMITED_FDS */ @@ -229,7 +229,7 @@ static void FioFreeHandle() slot = -1; /* Find the file that is used the least */ for (i = 0; i < lengthof(_fio.handles); i++) { - if (_fio.handles[i] != NULL && _fio.usage_count[i] < count) { + if (_fio.handles[i] != nullptr && _fio.usage_count[i] < count) { count = _fio.usage_count[i]; slot = i; } @@ -255,7 +255,7 @@ void FioOpenFile(int slot, const char *filename, Subdirectory subdir) FioFreeHandle(); #endif /* LIMITED_FDS */ f = FioFOpenFile(filename, "rb", subdir); - if (f == NULL) usererror("Cannot open file '%s'", filename); + if (f == nullptr) usererror("Cannot open file '%s'", filename); long pos = ftell(f); if (pos < 0) usererror("Cannot read file '%s'", filename); @@ -265,9 +265,9 @@ void FioOpenFile(int slot, const char *filename, Subdirectory subdir) /* Store the filename without path and extension */ const char *t = strrchr(filename, PATHSEPCHAR); - _fio.shortnames[slot] = stredup(t == NULL ? filename : t); + _fio.shortnames[slot] = stredup(t == nullptr ? filename : t); char *t2 = strrchr(_fio.shortnames[slot], '.'); - if (t2 != NULL) *t2 = '\0'; + if (t2 != nullptr) *t2 = '\0'; strtolower(_fio.shortnames[slot]); #if defined(LIMITED_FDS) @@ -312,7 +312,7 @@ static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links bool FioCheckFileExists(const char *filename, Subdirectory subdir) { FILE *f = FioFOpenFile(filename, "rb", subdir); - if (f == NULL) return false; + if (f == nullptr) return false; FioFCloseFile(f); return true; @@ -351,7 +351,7 @@ char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory su * @param last End of the destination buffer. * @param subdir Subdirectory to try. * @param filename Filename to look for. - * @return \a buf containing the path if the path was found, else \c NULL. + * @return \a buf containing the path if the path was found, else \c nullptr. */ char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename) { @@ -369,7 +369,7 @@ char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const ch #endif } - return NULL; + return nullptr; } char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir) @@ -407,7 +407,7 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s wchar_t Lmode[5]; MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode)); #endif - FILE *f = NULL; + FILE *f = nullptr; char buf[MAX_PATH]; if (subdir == NO_DIRECTORY) { @@ -417,16 +417,16 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s } #if defined(_WIN32) - if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return NULL; + if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return nullptr; #endif f = fopen(buf, mode); #if !defined(_WIN32) - if (f == NULL && strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1))) { + if (f == nullptr && strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1))) { f = fopen(buf, mode); } #endif - if (f != NULL && filesize != NULL) { + if (f != nullptr && filesize != nullptr) { /* Find the size of the file */ fseek(f, 0, SEEK_END); *filesize = ftell(f); @@ -438,21 +438,21 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s /** * Opens a file from inside a tar archive. * @param entry The entry to open. - * @param[out] filesize If not \c NULL, size of the opened file. - * @return File handle of the opened file, or \c NULL if the file is not available. + * @param[out] filesize If not \c nullptr, size of the opened file. + * @return File handle of the opened file, or \c nullptr if the file is not available. * @note The file is read from within the tar file, and may not return \c EOF after reading the whole file. */ FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) { FILE *f = fopen(entry->tar_filename, "rb"); - if (f == NULL) return f; + if (f == nullptr) return f; if (fseek(f, entry->position, SEEK_SET) < 0) { fclose(f); - return NULL; + return nullptr; } - if (filesize != NULL) *filesize = entry->size; + if (filesize != nullptr) *filesize = entry->size; return f; } @@ -460,22 +460,22 @@ FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) * Opens a OpenTTD file somewhere in a personal or global directory. * @param filename Name of the file to open. * @param subdir Subdirectory to open. - * @return File handle of the opened file, or \c NULL if the file is not available. + * @return File handle of the opened file, or \c nullptr if the file is not available. */ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize) { - FILE *f = NULL; + FILE *f = nullptr; Searchpath sp; assert(subdir < NUM_SUBDIRS || subdir == NO_DIRECTORY); FOR_ALL_SEARCHPATHS(sp) { f = FioFOpenFileSp(filename, mode, sp, subdir, filesize); - if (f != NULL || subdir == NO_DIRECTORY) break; + if (f != nullptr || subdir == NO_DIRECTORY) break; } /* We can only use .tar in case of data-dir, and read-mode */ - if (f == NULL && mode[0] == 'r' && subdir != NO_DIRECTORY) { + if (f == nullptr && mode[0] == 'r' && subdir != NO_DIRECTORY) { static const uint MAX_RESOLVED_LENGTH = 2 * (100 + 100 + 155) + 1; // Enough space to hold two filenames plus link. See 'TarHeader'. char resolved_name[MAX_RESOLVED_LENGTH]; @@ -508,11 +508,11 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, /* Sometimes a full path is given. To support * the 'subdirectory' must be 'removed'. */ - if (f == NULL && subdir != NO_DIRECTORY) { + if (f == nullptr && subdir != NO_DIRECTORY) { switch (subdir) { case BASESET_DIR: f = FioFOpenFile(filename, mode, OLD_GM_DIR, filesize); - if (f != NULL) break; + if (f != nullptr) break; FALLTHROUGH; case NEWGRF_DIR: f = FioFOpenFile(filename, mode, OLD_DATA_DIR, filesize); @@ -536,19 +536,9 @@ void FioCreateDirectory(const char *name) /* Ignore directory creation errors; they'll surface later on, and most * of the time they are 'directory already exists' errors anyhow. */ #if defined(_WIN32) - CreateDirectory(OTTD2FS(name), NULL); + CreateDirectory(OTTD2FS(name), nullptr); #elif defined(OS2) && !defined(__INNOTEK_LIBC__) mkdir(OTTD2FS(name)); -#elif defined(__MORPHOS__) || defined(__AMIGAOS__) - char buf[MAX_PATH]; - strecpy(buf, name, lastof(buf)); - - size_t len = strlen(name) - 1; - if (buf[len] == '/') { - buf[len] = '\0'; // Kill pathsep, so mkdir() will not fail - } - - mkdir(OTTD2FS(buf), 0755); #else mkdir(OTTD2FS(name), 0755); #endif @@ -575,18 +565,6 @@ bool AppendPathSeparator(char *buf, const char *last) return true; } -/** - * Find the first directory in a tar archive. - * @param tarname the name of the tar archive to look in. - * @param subdir the subdirectory to look in. - */ -const char *FioTarFirstDir(const char *tarname, Subdirectory subdir) -{ - TarList::iterator it = _tar_list[subdir].find(tarname); - if (it == _tar_list[subdir].end()) return NULL; - return (*it).second.dirname; -} - static void TarAddLink(const std::string &srcParam, const std::string &destParam, Subdirectory subdir) { std::string src = srcParam; @@ -608,11 +586,6 @@ static void TarAddLink(const std::string &srcParam, const std::string &destParam } } -void FioTarAddLink(const char *src, const char *dest, Subdirectory subdir) -{ - TarAddLink(src, dest, subdir); -} - /** * Simplify filenames from tars. * Replace '/' by #PATHSEPCHAR, and force 'name' to lowercase. @@ -685,7 +658,7 @@ bool TarScanner::AddFile(Subdirectory sd, const char *filename) bool TarScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { /* No tar within tar. */ - assert(tar_filename == NULL); + assert(tar_filename == nullptr); /* The TAR-header, repeated for every file */ struct TarHeader { @@ -718,11 +691,11 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha * a number of reasons we cannot open the file. * Most common case is when we simply have not * been given read access. */ - if (f == NULL) return false; + if (f == nullptr) return false; const char *dupped_filename = stredup(filename); _tar_list[this->subdir][filename].filename = dupped_filename; - _tar_list[this->subdir][filename].dirname = NULL; + _tar_list[this->subdir][filename].dirname = nullptr; TarLinkList links; ///< Temporary list to collect links @@ -811,13 +784,13 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha * Note: The destination of links must not contain any directory-links. */ strecpy(dest, name, lastof(dest)); char *destpos = strrchr(dest, PATHSEPCHAR); - if (destpos == NULL) destpos = dest; + if (destpos == nullptr) destpos = dest; *destpos = '\0'; char *pos = link; while (*pos != '\0') { char *next = strchr(pos, PATHSEPCHAR); - if (next == NULL) { + if (next == nullptr) { next = pos + strlen(pos); } else { /* Terminate the substring up to the path separator character. */ @@ -836,7 +809,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Truncate 'dest' after last PATHSEPCHAR. * This assumes that the truncated part is a real directory and not a link. */ destpos = strrchr(dest, PATHSEPCHAR); - if (destpos == NULL) destpos = dest; + if (destpos == nullptr) destpos = dest; *destpos = '\0'; } else { /* Append at end of 'dest' */ @@ -866,7 +839,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Store the first directory name we detect */ DEBUG(misc, 6, "Found dir in tar: %s", name); - if (_tar_list[this->subdir][filename].dirname == NULL) _tar_list[this->subdir][filename].dirname = stredup(name); + if (_tar_list[this->subdir][filename].dirname == nullptr) _tar_list[this->subdir][filename].dirname = stredup(name); break; default: @@ -921,13 +894,13 @@ bool ExtractTar(const char *tar_filename, Subdirectory subdir) const char *dirname = (*it).second.dirname; /* The file doesn't have a sub directory! */ - if (dirname == NULL) return false; + if (dirname == nullptr) return false; char filename[MAX_PATH]; strecpy(filename, tar_filename, lastof(filename)); char *p = strrchr(filename, PATHSEPCHAR); /* The file's path does not have a separator? */ - if (p == NULL) return false; + if (p == nullptr) return false; p++; strecpy(p, dirname, lastof(filename)); @@ -944,14 +917,14 @@ bool ExtractTar(const char *tar_filename, Subdirectory subdir) /* First open the file in the .tar. */ size_t to_copy = 0; FILE *in = FioFOpenFileTar(&(*it2).second, &to_copy); - if (in == NULL) { + if (in == nullptr) { DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, tar_filename); return false; } /* Now open the 'output' file. */ FILE *out = fopen(filename, "wb"); - if (out == NULL) { + if (out == nullptr) { DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, filename); fclose(in); return false; @@ -1003,17 +976,13 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe) bool success = false; #ifdef WITH_COCOA char *app_bundle = strchr(tmp, '.'); - while (app_bundle != NULL && strncasecmp(app_bundle, ".app", 4) != 0) app_bundle = strchr(&app_bundle[1], '.'); + while (app_bundle != nullptr && strncasecmp(app_bundle, ".app", 4) != 0) app_bundle = strchr(&app_bundle[1], '.'); - if (app_bundle != NULL) *app_bundle = '\0'; + if (app_bundle != nullptr) *app_bundle = '\0'; #endif /* WITH_COCOA */ char *s = strrchr(tmp, PATHSEPCHAR); - if (s != NULL) { + if (s != nullptr) { *s = '\0'; -#if defined(__DJGPP__) - /* If we want to go to the root, we can't use cd C:, but we must use '/' */ - if (s > tmp && *(s - 1) == ':') chdir("/"); -#endif if (chdir(tmp) != 0) { DEBUG(misc, 0, "Directory with the binary does not exist?"); } else { @@ -1036,13 +1005,13 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe) bool DoScanWorkingDirectory() { /* No working directory, so nothing to do. */ - if (_searchpaths[SP_WORKING_DIR] == NULL) return false; + if (_searchpaths[SP_WORKING_DIR] == nullptr) return false; /* Working directory is root, so do nothing. */ if (strcmp(_searchpaths[SP_WORKING_DIR], PATHSEP) == 0) return false; /* No personal/home directory, so the working directory won't be that. */ - if (_searchpaths[SP_PERSONAL_DIR] == NULL) return true; + if (_searchpaths[SP_PERSONAL_DIR] == nullptr) return true; char tmp[MAX_PATH]; seprintf(tmp, lastof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR], PERSONAL_DIR); @@ -1058,7 +1027,7 @@ void DetermineBasePaths(const char *exe) { char tmp[MAX_PATH]; #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) - const char *xdg_data_home = xdgDataHome(NULL); + const char *xdg_data_home = xdgDataHome(nullptr); seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", xdg_data_home, PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); free(xdg_data_home); @@ -1066,8 +1035,8 @@ void DetermineBasePaths(const char *exe) AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_PERSONAL_DIR_XDG] = stredup(tmp); #endif -#if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) || !defined(WITH_PERSONAL_DIR) - _searchpaths[SP_PERSONAL_DIR] = NULL; +#if defined(OS2) || !defined(WITH_PERSONAL_DIR) + _searchpaths[SP_PERSONAL_DIR] = nullptr; #else #ifdef __HAIKU__ BPath path; @@ -1079,17 +1048,17 @@ void DetermineBasePaths(const char *exe) * variables in any way. It can also contain all kinds of * unvalidated data we rather not want internally. */ const char *homedir = getenv("HOME"); - if (homedir != NULL) { + if (homedir != nullptr) { homedir = stredup(homedir); } - if (homedir == NULL) { + if (homedir == nullptr) { const struct passwd *pw = getpwuid(getuid()); - homedir = (pw == NULL) ? NULL : stredup(pw->pw_dir); + homedir = (pw == nullptr) ? nullptr : stredup(pw->pw_dir); } #endif - if (homedir != NULL) { + if (homedir != nullptr) { ValidateString(homedir); seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", homedir, PERSONAL_DIR); AppendPathSeparator(tmp, lastof(tmp)); @@ -1097,7 +1066,7 @@ void DetermineBasePaths(const char *exe) _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); free(homedir); } else { - _searchpaths[SP_PERSONAL_DIR] = NULL; + _searchpaths[SP_PERSONAL_DIR] = nullptr; } #endif @@ -1106,37 +1075,33 @@ void DetermineBasePaths(const char *exe) AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_SHARED_DIR] = stredup(tmp); #else - _searchpaths[SP_SHARED_DIR] = NULL; + _searchpaths[SP_SHARED_DIR] = nullptr; #endif -#if defined(__MORPHOS__) || defined(__AMIGA__) - _searchpaths[SP_WORKING_DIR] = NULL; -#else - if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0'; + if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_WORKING_DIR] = stredup(tmp); -#endif _do_scan_working_directory = DoScanWorkingDirectory(); /* Change the working directory to that one of the executable */ if (ChangeWorkingDirectoryToExecutable(exe)) { - if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0'; + if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_BINARY_DIR] = stredup(tmp); } else { - _searchpaths[SP_BINARY_DIR] = NULL; + _searchpaths[SP_BINARY_DIR] = nullptr; } - if (_searchpaths[SP_WORKING_DIR] != NULL) { + if (_searchpaths[SP_WORKING_DIR] != nullptr) { /* Go back to the current working directory. */ if (chdir(_searchpaths[SP_WORKING_DIR]) != 0) { DEBUG(misc, 0, "Failed to return to working directory!"); } } -#if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) - _searchpaths[SP_INSTALLATION_DIR] = NULL; +#if !defined(GLOBAL_DATA_DIR) + _searchpaths[SP_INSTALLATION_DIR] = nullptr; #else seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR); AppendPathSeparator(tmp, lastof(tmp)); @@ -1146,7 +1111,7 @@ void DetermineBasePaths(const char *exe) extern void cocoaSetApplicationBundleDir(); cocoaSetApplicationBundleDir(); #else - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL; + _searchpaths[SP_APPLICATION_BUNDLE_DIR] = nullptr; #endif } #endif /* defined(_WIN32) */ @@ -1166,7 +1131,7 @@ void DeterminePaths(const char *exe) #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) char config_home[MAX_PATH]; - const char *xdg_config_home = xdgConfigHome(NULL); + const char *xdg_config_home = xdgConfigHome(nullptr); seprintf(config_home, lastof(config_home), "%s" PATHSEP "%s", xdg_config_home, PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); free(xdg_config_home); @@ -1181,19 +1146,19 @@ void DeterminePaths(const char *exe) } char *config_dir; - if (_config_file != NULL) { + if (_config_file != nullptr) { config_dir = stredup(_config_file); char *end = strrchr(config_dir, PATHSEPCHAR); - if (end == NULL) { + if (end == nullptr) { config_dir[0] = '\0'; } else { end[1] = '\0'; } } else { char personal_dir[MAX_PATH]; - if (FioFindFullPath(personal_dir, lastof(personal_dir), BASE_DIR, "openttd.cfg") != NULL) { + if (FioFindFullPath(personal_dir, lastof(personal_dir), BASE_DIR, "openttd.cfg") != nullptr) { char *end = strrchr(personal_dir, PATHSEPCHAR); - if (end != NULL) end[1] = '\0'; + if (end != nullptr) end[1] = '\0'; config_dir = stredup(personal_dir); _config_file = str_fmt("%sopenttd.cfg", config_dir); } else { @@ -1205,14 +1170,14 @@ void DeterminePaths(const char *exe) SP_PERSONAL_DIR, SP_BINARY_DIR, SP_WORKING_DIR, SP_SHARED_DIR, SP_INSTALLATION_DIR }; - config_dir = NULL; + config_dir = nullptr; for (uint i = 0; i < lengthof(new_openttd_cfg_order); i++) { if (IsValidSearchPath(new_openttd_cfg_order[i])) { config_dir = stredup(_searchpaths[new_openttd_cfg_order[i]]); break; } } - assert(config_dir != NULL); + assert(config_dir != nullptr); #endif _config_file = str_fmt("%sopenttd.cfg", config_dir); } @@ -1239,7 +1204,7 @@ void DeterminePaths(const char *exe) } /* Make the necessary folders */ -#if !defined(__MORPHOS__) && !defined(__AMIGA__) && defined(WITH_PERSONAL_DIR) +#if defined(WITH_PERSONAL_DIR) FioCreateDirectory(config_dir); if (config_dir != _personal_dir) FioCreateDirectory(_personal_dir); #endif @@ -1258,7 +1223,6 @@ void DeterminePaths(const char *exe) /* If we have network we make a directory for the autodownloading of content */ _searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir, "content_download" PATHSEP); -#ifdef ENABLE_NETWORK FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); /* Create the directory for each of the types of content */ @@ -1271,14 +1235,6 @@ void DeterminePaths(const char *exe) extern char *_log_file; _log_file = str_fmt("%sopenttd.log", _personal_dir); -#else /* ENABLE_NETWORK */ - /* If we don't have networking, we don't need to make the directory. But - * if it exists we keep it, otherwise remove it from the search paths. */ - if (!FileExists(_searchpaths[SP_AUTODOWNLOAD_DIR])) { - free(_searchpaths[SP_AUTODOWNLOAD_DIR]); - _searchpaths[SP_AUTODOWNLOAD_DIR] = NULL; - } -#endif /* ENABLE_NETWORK */ } /** @@ -1304,27 +1260,27 @@ void SanitizeFilename(char *filename) * @param filename Name of the file to load. * @param[out] lenp Length of loaded data. * @param maxsize Maximum size to load. - * @return Pointer to new memory containing the loaded data, or \c NULL if loading failed. + * @return Pointer to new memory containing the loaded data, or \c nullptr if loading failed. * @note If \a maxsize less than the length of the file, loading fails. */ void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) { FILE *in = fopen(filename, "rb"); - if (in == NULL) return NULL; + if (in == nullptr) return nullptr; fseek(in, 0, SEEK_END); size_t len = ftell(in); fseek(in, 0, SEEK_SET); if (len > maxsize) { fclose(in); - return NULL; + return nullptr; } byte *mem = MallocT(len + 1); mem[len] = 0; if (fread(mem, len, 1, in) != 1) { fclose(in); free(mem); - return NULL; + return nullptr; } fclose(in); @@ -1336,14 +1292,14 @@ void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) * Helper to see whether a given filename matches the extension. * @param extension The extension to look for. * @param filename The filename to look in for the extension. - * @return True iff the extension is NULL, or the filename ends with it. + * @return True iff the extension is nullptr, or the filename ends with it. */ static bool MatchesExtension(const char *extension, const char *filename) { - if (extension == NULL) return true; + if (extension == nullptr) return true; const char *ext = strrchr(filename, extension[0]); - return ext != NULL && strcasecmp(ext, extension) == 0; + return ext != nullptr && strcasecmp(ext, extension) == 0; } /** @@ -1364,9 +1320,9 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s struct dirent *dirent; DIR *dir; - if (path == NULL || (dir = ttd_opendir(path)) == NULL) return 0; + if (path == nullptr || (dir = ttd_opendir(path)) == nullptr) return 0; - while ((dirent = readdir(dir)) != NULL) { + while ((dirent = readdir(dir)) != nullptr) { const char *d_name = FS2OTTD(dirent->d_name); char filename[MAX_PATH]; @@ -1382,7 +1338,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s num += ScanPath(fs, extension, filename, basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { /* File */ - if (MatchesExtension(extension, filename) && fs->AddFile(filename, basepath_length, NULL)) num++; + if (MatchesExtension(extension, filename) && fs->AddFile(filename, basepath_length, nullptr)) num++; } } diff --git a/src/fileio_func.h b/src/fileio_func.h index f5ef58ac06..9c287d12c9 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -30,7 +30,7 @@ void FioSkipBytes(int n); /** * The search paths OpenTTD could search through. * At least one of the slots has to be filled with a path. - * NULL paths tell that there is no such path for the + * nullptr paths tell that there is no such path for the * current operating system. */ extern const char *_searchpaths[NUM_SEARCHPATHS]; @@ -42,14 +42,14 @@ extern const char *_searchpaths[NUM_SEARCHPATHS]; */ static inline bool IsValidSearchPath(Searchpath sp) { - return sp < NUM_SEARCHPATHS && _searchpaths[sp] != NULL; + return sp < NUM_SEARCHPATHS && _searchpaths[sp] != nullptr; } /** Iterator for all the search paths */ #define FOR_ALL_SEARCHPATHS(sp) for (sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) if (IsValidSearchPath(sp)) void FioFCloseFile(FILE *f); -FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = NULL); +FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr); bool FioCheckFileExists(const char *filename, Subdirectory subdir); char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename); char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename); @@ -64,8 +64,6 @@ bool AppendPathSeparator(char *buf, const char *last); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const char *filename); -const char *FioTarFirstDir(const char *tarname, Subdirectory subdir); -void FioTarAddLink(const char *src, const char *dest, Subdirectory subdir); bool ExtractTar(const char *tar_filename, Subdirectory subdir); extern const char *_personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. @@ -107,7 +105,7 @@ public: ALL = BASESET | NEWGRF | AI | SCENARIO | GAME, ///< Scan for everything. }; - /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = NULL); + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = nullptr) override; bool AddFile(Subdirectory sd, const char *filename); diff --git a/src/fios.cpp b/src/fios.cpp index c2727d2d5b..c717c1f4f7 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -13,11 +13,13 @@ */ #include "stdafx.h" -#include "fios.h" +#include "3rdparty/md5/md5.h" #include "fileio_func.h" -#include "tar_type.h" +#include "fios.h" +#include "network/network_content.h" #include "screenshot.h" #include "string_func.h" +#include "tar_type.h" #include #ifndef _WIN32 @@ -45,22 +47,20 @@ extern void GetOldSaveGameName(const char *file, char *title, const char *last); /** * Compare two FiosItem's. Used with sort when sorting the file list. - * @param da A pointer to the first FiosItem to compare. - * @param db A pointer to the second FiosItem to compare. - * @return -1, 0 or 1, depending on how the two items should be sorted. + * @param other The FiosItem to compare to. + * @return for ascending order: returns true if da < db. Vice versa for descending order. */ -int CDECL CompareFiosItems(const FiosItem *da, const FiosItem *db) +bool FiosItem::operator< (const FiosItem &other) const { - int r = 0; + int r = false; - if ((_savegame_sort_order & SORT_BY_NAME) == 0 && da->mtime != db->mtime) { - r = da->mtime < db->mtime ? -1 : 1; + if ((_savegame_sort_order & SORT_BY_NAME) == 0 && (*this).mtime != other.mtime) { + r = (*this).mtime - other.mtime; } else { - r = strnatcmp(da->title, db->title); + r = strnatcmp((*this).title, other.title); } - - if (_savegame_sort_order & SORT_DESCENDING) r = -r; - return r; + if (r == 0) return false; + return (_savegame_sort_order & SORT_DESCENDING) ? r > 0 : r < 0; } FileList::~FileList() @@ -103,7 +103,7 @@ void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperati * Find file information of a file by its name from the file list. * @param file The filename to return information about. Can be the actual name * or a numbered entry into the filename list. - * @return The information on the file, or \c NULL if the file is not available. + * @return The information on the file, or \c nullptr if the file is not available. */ const FiosItem *FileList::FindItem(const char *file) { @@ -128,14 +128,14 @@ const FiosItem *FileList::FindItem(const char *file) if (strcmp(long_file, item->title) == 0) return item; } - return NULL; + return nullptr; } /** * Get descriptive texts. Returns the path and free space * left on the device * @param path string describing the path - * @param total_free total free space in megabytes, optional (can be NULL) + * @param total_free total free space in megabytes, optional (can be nullptr) * @return StringID describing the path (free space or failure) */ StringID FiosGetDescText(const char **path, uint64 *total_free) @@ -147,7 +147,7 @@ StringID FiosGetDescText(const char **path, uint64 *total_free) /** * Browse to a new path based on the passed \a item, starting at #_fios_path. * @param *item Item telling us what to do. - * @return A filename w/path if we reached a file, otherwise \c NULL. + * @return A filename w/path if we reached a file, otherwise \c nullptr. */ const char *FiosBrowseTo(const FiosItem *item) { @@ -162,19 +162,14 @@ const char *FiosBrowseTo(const FiosItem *item) break; case FIOS_TYPE_PARENT: { - /* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */ + /* Check for possible nullptr ptr */ char *s = strrchr(_fios_path, PATHSEPCHAR); - if (s != NULL && s != _fios_path) { + if (s != nullptr && s != _fios_path) { s[0] = '\0'; // Remove last path separator character, so we can go up one level. } s = strrchr(_fios_path, PATHSEPCHAR); - if (s != NULL) { + if (s != nullptr) { s[1] = '\0'; // go up a directory -#if defined(__MORPHOS__) || defined(__AMIGAOS__) - /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ - } else if ((s = strrchr(_fios_path, ':')) != NULL) { - s[1] = '\0'; -#endif } break; } @@ -197,39 +192,31 @@ const char *FiosBrowseTo(const FiosItem *item) return item->name; } - return NULL; + return nullptr; } /** * Construct a filename from its components in destination buffer \a buf. * @param buf Destination buffer. - * @param path Directory path, may be \c NULL. + * @param path Directory path, may be \c nullptr. * @param name Filename. * @param ext Filename extension (use \c "" for no extension). * @param last Last element of buffer \a buf. */ static void FiosMakeFilename(char *buf, const char *path, const char *name, const char *ext, const char *last) { - const char *period; + if (path != nullptr) { + const char *buf_start = buf; + buf = strecpy(buf, path, last); + /* Remove trailing path separator, if present */ + if (buf > buf_start && buf[-1] == PATHSEPCHAR) buf--; + } /* Don't append the extension if it is already there */ - period = strrchr(name, '.'); - if (period != NULL && strcasecmp(period, ext) == 0) ext = ""; -#if defined(__MORPHOS__) || defined(__AMIGAOS__) - if (path != NULL) { - unsigned char sepchar = path[(strlen(path) - 1)]; + const char *period = strrchr(name, '.'); + if (period != nullptr && strcasecmp(period, ext) == 0) ext = ""; - if (sepchar != ':' && sepchar != '/') { - seprintf(buf, last, "%s" PATHSEP "%s%s", path, name, ext); - } else { - seprintf(buf, last, "%s%s%s", path, name, ext); - } - } else { - seprintf(buf, last, "%s%s", name, ext); - } -#else - seprintf(buf, last, "%s" PATHSEP "%s%s", path, name, ext); -#endif + seprintf(buf, last, PATHSEP "%s%s", name, ext); } /** @@ -293,7 +280,7 @@ public: fop(fop), callback_proc(callback_proc), file_list(file_list) {} - /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; }; /** @@ -305,7 +292,7 @@ public: bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { const char *ext = strrchr(filename, '.'); - if (ext == NULL) return false; + if (ext == nullptr) return false; char fios_title[64]; fios_title[0] = '\0'; // reset the title; @@ -353,7 +340,7 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons const char *t = fios_title; if (StrEmpty(fios_title)) { t = strrchr(filename, PATHSEPCHAR); - t = (t == NULL) ? filename : (t + 1); + t = (t == nullptr) ? filename : (t + 1); } strecpy(fios->title, t, lastof(fios->title)); str_validate(fios->title, lastof(fios->title)); @@ -375,7 +362,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c struct dirent *dirent; DIR *dir; FiosItem *fios; - int sort_start; + size_t sort_start; char d_name[sizeof(fios->name)]; file_list.Clear(); @@ -390,8 +377,8 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c } /* Show subdirectories */ - if ((dir = ttd_opendir(_fios_path)) != NULL) { - while ((dirent = readdir(dir)) != NULL) { + if ((dir = ttd_opendir(_fios_path)) != nullptr) { + while ((dirent = readdir(dir)) != nullptr) { strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ @@ -413,7 +400,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c { SortingBits order = _savegame_sort_order; _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; - QSortT(file_list.files.Begin(), file_list.files.Length(), CompareFiosItems); + std::sort(file_list.files.begin(), file_list.files.end()); _savegame_sort_order = order; } @@ -423,12 +410,12 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c /* Show files */ FiosFileScanner scanner(fop, callback_proc, file_list); if (subdir == NO_DIRECTORY) { - scanner.Scan(NULL, _fios_path, false); + scanner.Scan(nullptr, _fios_path, false); } else { - scanner.Scan(NULL, subdir, true, true); + scanner.Scan(nullptr, subdir, true, true); } - QSortT(file_list.Get(sort_start), file_list.Length() - sort_start, CompareFiosItems); + std::sort(file_list.files.begin() + sort_start, file_list.files.end()); /* Show drives */ FiosGetDrives(file_list); @@ -451,7 +438,7 @@ static void GetFileTitle(const char *file, char *title, const char *last, Subdir strecat(buf, ".title", lastof(buf)); FILE *f = FioFOpenFile(buf, "r", subdir); - if (f == NULL) return; + if (f == nullptr) return; size_t read = fread(title, 1, last - title, f); assert(title + read <= last); @@ -465,8 +452,8 @@ static void GetFileTitle(const char *file, char *title, const char *last, Subdir * @param fop Purpose of collecting the list. * @param file Name of the file to check. * @param ext A pointer to the extension identifier inside file - * @param title Buffer if a callback wants to lookup the title of the file; NULL to skip the lookup - * @param last Last available byte in buffer (to prevent buffer overflows); not used when title == NULL + * @param title Buffer if a callback wants to lookup the title of the file; nullptr to skip the lookup + * @param last Last available byte in buffer (to prevent buffer overflows); not used when title == nullptr * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame * @see FiosGetFileList * @see FiosGetSavegameList @@ -480,7 +467,7 @@ FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, co * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */ /* Don't crash if we supply no extension */ - if (ext == NULL) return FIOS_TYPE_INVALID; + if (ext == nullptr) return FIOS_TYPE_INVALID; if (strcasecmp(ext, ".sav") == 0) { GetFileTitle(file, title, last, SAVE_DIR); @@ -490,7 +477,7 @@ FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, co if (fop == SLO_LOAD) { if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 || strcasecmp(ext, ".sv2") == 0) { - if (title != NULL) GetOldSaveGameName(file, title, last); + if (title != nullptr) GetOldSaveGameName(file, title, last); return FIOS_TYPE_OLDFILE; } } @@ -506,10 +493,10 @@ FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, co */ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_save_path = NULL; - static char *fios_save_path_last = NULL; + static char *fios_save_path = nullptr; + static char *fios_save_path_last = nullptr; - if (fios_save_path == NULL) { + if (fios_save_path == nullptr) { fios_save_path = MallocT(MAX_PATH); fios_save_path_last = fios_save_path + MAX_PATH - 1; FioGetDirectory(fios_save_path, fios_save_path_last, SAVE_DIR); @@ -561,11 +548,11 @@ static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *f */ void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_scn_path = NULL; - static char *fios_scn_path_last = NULL; + static char *fios_scn_path = nullptr; + static char *fios_scn_path_last = nullptr; /* Copy the default path on first run or on 'New Game' */ - if (fios_scn_path == NULL) { + if (fios_scn_path == nullptr) { fios_scn_path = MallocT(MAX_PATH); fios_scn_path_last = fios_scn_path + MAX_PATH - 1; FioGetDirectory(fios_scn_path, fios_scn_path_last, SCENARIO_DIR); @@ -632,10 +619,10 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char * */ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_hmap_path = NULL; - static char *fios_hmap_path_last = NULL; + static char *fios_hmap_path = nullptr; + static char *fios_hmap_path_last = nullptr; - if (fios_hmap_path == NULL) { + if (fios_hmap_path == nullptr) { fios_hmap_path = MallocT(MAX_PATH); fios_hmap_path_last = fios_hmap_path + MAX_PATH - 1; FioGetDirectory(fios_hmap_path, fios_hmap_path_last, HEIGHTMAP_DIR); @@ -657,9 +644,9 @@ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list) */ const char *FiosGetScreenshotDir() { - static char *fios_screenshot_path = NULL; + static char *fios_screenshot_path = nullptr; - if (fios_screenshot_path == NULL) { + if (fios_screenshot_path == nullptr) { fios_screenshot_path = MallocT(MAX_PATH); FioGetDirectory(fios_screenshot_path, fios_screenshot_path + MAX_PATH - 1, SCREENSHOT_DIR); } @@ -667,10 +654,6 @@ const char *FiosGetScreenshotDir() return fios_screenshot_path; } -#if defined(ENABLE_NETWORK) -#include "network/network_content.h" -#include "3rdparty/md5/md5.h" - /** Basic data to distinguish a scenario. Used in the server list window */ struct ScenarioIdentifier { uint32 scenid; ///< ID for the scenario (generated by content). @@ -692,7 +675,7 @@ struct ScenarioIdentifier { /** * Scanner to find the unique IDs of scenarios */ -class ScenarioScanner : protected FileScanner, public SmallVector { +class ScenarioScanner : protected FileScanner, public std::vector { bool scanned; ///< Whether we've already scanned public: /** Initialise */ @@ -710,10 +693,10 @@ public: this->scanned = true; } - /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override { FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR); - if (f == NULL) return false; + if (f == nullptr) return false; ScenarioIdentifier id; int fret = fscanf(f, "%i", &id.scenid); @@ -732,7 +715,7 @@ public: strecpy(basename, filename, lastof(basename)); *strrchr(basename, '.') = '\0'; f = FioFOpenFile(basename, "rb", SCENARIO_DIR, &size); - if (f == NULL) return false; + if (f == nullptr) return false; /* calculate md5sum */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { @@ -743,7 +726,7 @@ public: FioFCloseFile(f); - this->Include(id); + include(*this, id); return true; } }; @@ -755,20 +738,20 @@ static ScenarioScanner _scanner; * Find a given scenario based on its unique ID. * @param ci The content info to compare it to. * @param md5sum Whether to look at the md5sum or the id. - * @return The filename of the file, else \c NULL. + * @return The filename of the file, else \c nullptr. */ const char *FindScenario(const ContentInfo *ci, bool md5sum) { _scanner.Scan(false); - for (ScenarioIdentifier *id = _scanner.Begin(); id != _scanner.End(); id++) { - if (md5sum ? (memcmp(id->md5sum, ci->md5sum, sizeof(id->md5sum)) == 0) - : (id->scenid == ci->unique_id)) { - return id->filename; + for (ScenarioIdentifier &id : _scanner) { + if (md5sum ? (memcmp(id.md5sum, ci->md5sum, sizeof(id.md5sum)) == 0) + : (id.scenid == ci->unique_id)) { + return id.filename; } } - return NULL; + return nullptr; } /** @@ -779,7 +762,7 @@ const char *FindScenario(const ContentInfo *ci, bool md5sum) */ bool HasScenario(const ContentInfo *ci, bool md5sum) { - return (FindScenario(ci, md5sum) != NULL); + return (FindScenario(ci, md5sum) != nullptr); } /** @@ -789,5 +772,3 @@ void ScanScenarios() { _scanner.Scan(true); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/fios.h b/src/fios.h index 24c9f370eb..7b10dea4ca 100644 --- a/src/fios.h +++ b/src/fios.h @@ -48,8 +48,8 @@ struct LoadCheckData { struct LoggedAction *gamelog_action; ///< Gamelog actions uint gamelog_actions; ///< Number of gamelog actions - LoadCheckData() : error_data(NULL), grfconfig(NULL), - grf_compatibility(GLC_NOT_FOUND), gamelog_action(NULL), gamelog_actions(0) + LoadCheckData() : error_data(nullptr), grfconfig(nullptr), + grf_compatibility(GLC_NOT_FOUND), gamelog_action(nullptr), gamelog_actions(0) { this->Clear(); } @@ -77,7 +77,7 @@ struct LoadCheckData { */ bool HasNewGrfs() { - return this->checkable && this->error == INVALID_STRING_ID && this->grfconfig != NULL; + return this->checkable && this->error == INVALID_STRING_ID && this->grfconfig != nullptr; } void Clear(); @@ -107,6 +107,7 @@ struct FiosItem { uint64 mtime; char title[64]; char name[MAX_PATH]; + bool operator< (const FiosItem &other) const; }; /** List of file information. */ @@ -120,16 +121,17 @@ public: */ inline FiosItem *Append() { - return this->files.Append(); + /*C++17: return &*/ this->files.emplace_back(); + return &this->files.back(); } /** * Get the number of files in the list. * @return The number of files stored in the list. */ - inline uint Length() const + inline size_t Length() const { - return this->files.Length(); + return this->files.size(); } /** @@ -138,7 +140,7 @@ public: */ inline const FiosItem *Begin() const { - return this->files.Begin(); + return this->files.data(); } /** @@ -147,28 +149,28 @@ public: */ inline const FiosItem *End() const { - return this->files.End(); + return this->Begin() + this->Length(); } /** * Get a pointer to the indicated file information. File information must exist. * @return Address of the indicated existing file information. */ - inline const FiosItem *Get(uint index) const + inline const FiosItem *Get(size_t index) const { - return this->files.Get(index); + return this->files.data() + index; } /** * Get a pointer to the indicated file information. File information must exist. * @return Address of the indicated existing file information. */ - inline FiosItem *Get(uint index) + inline FiosItem *Get(size_t index) { - return this->files.Get(index); + return this->files.data() + index; } - inline const FiosItem &operator[](uint index) const + inline const FiosItem &operator[](size_t index) const { return this->files[index]; } @@ -177,7 +179,7 @@ public: * Get a reference to the indicated file information. File information must exist. * @return The requested file information. */ - inline FiosItem &operator[](uint index) + inline FiosItem &operator[](size_t index) { return this->files[index]; } @@ -185,19 +187,19 @@ public: /** Remove all items from the list. */ inline void Clear() { - this->files.Clear(); + this->files.clear(); } /** Compact the list down to the smallest block size boundary. */ inline void Compact() { - this->files.Compact(); + this->files.shrink_to_fit(); } void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop); const FiosItem *FindItem(const char *file); - SmallVector files; ///< The list of files. + std::vector files; ///< The list of files. }; enum SortingBits { @@ -226,6 +228,4 @@ void FiosMakeSavegameName(char *buf, const char *name, const char *last); FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last); -int CDECL CompareFiosItems(const FiosItem *a, const FiosItem *b); - #endif /* FIOS_H */ diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 58242e71e2..754dc45350 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -51,20 +51,19 @@ void LoadCheckData::Clear() this->checkable = false; this->error = INVALID_STRING_ID; free(this->error_data); - this->error_data = NULL; + this->error_data = nullptr; this->map_size_x = this->map_size_y = 256; // Default for old savegames which do not store mapsize. this->current_date = 0; memset(&this->settings, 0, sizeof(this->settings)); - const CompanyPropertiesMap::iterator end = this->companies.End(); - for (CompanyPropertiesMap::iterator it = this->companies.Begin(); it != end; it++) { - delete it->second; + for (auto &pair : this->companies) { + delete pair.second; } - companies.Clear(); + companies.clear(); GamelogFree(this->gamelog_action, this->gamelog_actions); - this->gamelog_action = NULL; + this->gamelog_action = nullptr; this->gamelog_actions = 0; ClearGRFConfigList(&this->grfconfig); @@ -245,8 +244,8 @@ static const TextColour _fios_colours[] = { */ static void SortSaveGameList(FileList &file_list) { - uint sort_start = 0; - uint sort_end = 0; + size_t sort_start = 0; + size_t sort_end = 0; /* Directories are always above the files (FIOS_TYPE_DIR) * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE) @@ -261,8 +260,7 @@ static void SortSaveGameList(FileList &file_list) } } - uint s_amount = file_list.Length() - sort_start - sort_end; - QSortT(file_list.Get(sort_start), s_amount, CompareFiosItems); + std::sort(file_list.files.begin() + sort_start, file_list.files.end() - sort_end); } struct SaveLoadWindow : public Window { @@ -274,12 +272,12 @@ private: SaveLoadOperation fop; ///< File operation to perform. FileList fios_items; ///< Save game list. FiosItem o_dir; - const FiosItem *selected; ///< Selected game in #fios_items, or \c NULL. + const FiosItem *selected; ///< Selected game in #fios_items, or \c nullptr. Scrollbar *vscroll; StringFilter string_filter; ///< Filter for available games. QueryString filter_editbox; ///< Filter editbox; - SmallVector fios_items_shown; ///< Map of the filtered out fios items + std::vector fios_items_shown; ///< Map of the filtered out fios items static void SaveGameConfirmationCallback(Window *w, bool confirmed) { @@ -407,7 +405,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SL_SORT_BYNAME: @@ -418,7 +416,7 @@ public: break; case WID_SL_BACKGROUND: { - static const char *path = NULL; + static const char *path = nullptr; static StringID str = STR_ERROR_UNABLE_TO_READ_DRIVE; static uint64 tot = 0; @@ -462,7 +460,7 @@ public: r.right - WD_FRAMERECT_RIGHT, r.top + FONT_HEIGHT_NORMAL * 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, PC_GREY); DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL / 2 + WD_FRAMERECT_TOP, STR_SAVELOAD_DETAIL_CAPTION, TC_FROMSTRING, SA_HOR_CENTER); - if (this->selected == NULL) break; + if (this->selected == nullptr) break; uint y = r.top + FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; uint y_max = r.bottom - FONT_HEIGHT_NORMAL - WD_FRAMERECT_BOTTOM; @@ -518,7 +516,7 @@ public: if (y > y_max) break; /* NewGrf compatibility */ - SetDParam(0, _load_check_data.grfconfig == NULL ? STR_NEWGRF_LIST_NONE : + SetDParam(0, _load_check_data.grfconfig == nullptr ? STR_NEWGRF_LIST_NONE : STR_NEWGRF_LIST_ALL_FOUND + _load_check_data.grf_compatibility); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_GRFSTATUS); y += FONT_HEIGHT_NORMAL; @@ -531,11 +529,10 @@ public: if (y > y_max) break; /* Companies / AIs */ - CompanyPropertiesMap::const_iterator end = _load_check_data.companies.End(); - for (CompanyPropertiesMap::const_iterator it = _load_check_data.companies.Begin(); it != end; it++) { - SetDParam(0, it->first + 1); - const CompanyProperties &c = *it->second; - if (c.name != NULL) { + for (auto &pair : _load_check_data.companies) { + SetDParam(0, pair.first + 1); + const CompanyProperties &c = *pair.second; + if (c.name != nullptr) { SetDParam(1, STR_JUST_RAW_STRING); SetDParamStr(2, c.name); } else { @@ -553,7 +550,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SL_BACKGROUND: @@ -575,7 +572,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { if (_savegame_sort_dirty) { _savegame_sort_dirty = false; @@ -586,7 +583,7 @@ public: this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SL_SORT_BYNAME: // Sort save names by name @@ -608,24 +605,24 @@ public: this->InvalidateData(SLIWD_RESCAN_FILES); break; - case WID_SL_LOAD_BUTTON: - if (this->selected != NULL && !_load_check_data.HasErrors()) { - const char *name = FiosBrowseTo(this->selected); - _file_to_saveload.SetMode(this->selected->type); - _file_to_saveload.SetName(name); - _file_to_saveload.SetTitle(this->selected->title); + case WID_SL_LOAD_BUTTON: { + if (this->selected == nullptr || _load_check_data.HasErrors()) break; - if (this->abstract_filetype == FT_HEIGHTMAP) { - delete this; - ShowHeightmapLoad(); + const char *name = FiosBrowseTo(this->selected); + _file_to_saveload.SetMode(this->selected->type); + _file_to_saveload.SetName(name); + _file_to_saveload.SetTitle(this->selected->title); - } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { - _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; - ClearErrorMessages(); - delete this; - } + if (this->abstract_filetype == FT_HEIGHTMAP) { + delete this; + ShowHeightmapLoad(); + } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { + _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; + ClearErrorMessages(); + delete this; } break; + } case WID_SL_NEWGRF_INFO: if (_load_check_data.HasNewGrfs()) { @@ -637,9 +634,7 @@ public: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else if (_load_check_data.HasNewGrfs()) { -#if defined(ENABLE_NETWORK) ShowMissingContentWindow(_load_check_data.grfconfig); -#endif } break; @@ -656,43 +651,44 @@ public: const FiosItem *file = this->fios_items.Get(y); const char *name = FiosBrowseTo(file); - if (name != NULL) { - if (click_count == 1) { - if (this->selected != file) { - this->selected = file; - _load_check_data.Clear(); - - if (GetDetailedFileType(file->type) == DFT_GAME_FILE) { - /* Other detailed file types cannot be checked before. */ - SaveOrLoad(name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); - } - - this->InvalidateData(SLIWD_SELECTION_CHANGES); - } - if (this->fop == SLO_SAVE) { - /* Copy clicked name to editbox */ - this->filename_editbox.text.Assign(file->title); - this->SetWidgetDirty(WID_SL_SAVE_OSK_TITLE); - } - } else if (!_load_check_data.HasErrors()) { - this->selected = file; - if (this->fop == SLO_LOAD) { - if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) { - this->OnClick(pt, WID_SL_LOAD_BUTTON, 1); - } else { - assert(this->abstract_filetype == FT_HEIGHTMAP); - _file_to_saveload.SetMode(file->type); - _file_to_saveload.SetName(name); - _file_to_saveload.SetTitle(file->title); - - delete this; - ShowHeightmapLoad(); - } - } - } - } else { + if (name == nullptr) { /* Changed directory, need refresh. */ this->InvalidateData(SLIWD_RESCAN_FILES); + break; + } + + if (click_count == 1) { + if (this->selected != file) { + this->selected = file; + _load_check_data.Clear(); + + if (GetDetailedFileType(file->type) == DFT_GAME_FILE) { + /* Other detailed file types cannot be checked before. */ + SaveOrLoad(name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); + } + + this->InvalidateData(SLIWD_SELECTION_CHANGES); + } + if (this->fop == SLO_SAVE) { + /* Copy clicked name to editbox */ + this->filename_editbox.text.Assign(file->title); + this->SetWidgetDirty(WID_SL_SAVE_OSK_TITLE); + } + } else if (!_load_check_data.HasErrors()) { + this->selected = file; + if (this->fop == SLO_LOAD) { + if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) { + this->OnClick(pt, WID_SL_LOAD_BUTTON, 1); + } else { + assert(this->abstract_filetype == FT_HEIGHTMAP); + _file_to_saveload.SetMode(file->type); + _file_to_saveload.SetName(name); + _file_to_saveload.SetTitle(file->title); + + delete this; + ShowHeightmapLoad(); + } + } } break; } @@ -701,14 +697,12 @@ public: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { -#if defined(ENABLE_NETWORK) assert(this->fop == SLO_LOAD); switch (this->abstract_filetype) { default: NOT_REACHED(); - case FT_SCENARIO: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_SCENARIO); break; - case FT_HEIGHTMAP: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_HEIGHTMAP); break; + case FT_SCENARIO: ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_SCENARIO); break; + case FT_HEIGHTMAP: ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_HEIGHTMAP); break; } -#endif } break; @@ -722,7 +716,7 @@ public: } } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { if (keycode == WKC_ESC) { delete this; @@ -732,7 +726,7 @@ public: return ES_NOT_HANDLED; } - virtual void OnTimeout() + void OnTimeout() override { /* Widgets WID_SL_DELETE_SELECTION and WID_SL_SAVE_GAME only exist when saving to a file. */ if (this->fop != SLO_SAVE) return; @@ -767,7 +761,7 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SL_DRIVES_DIRECTORIES_LIST); } @@ -777,19 +771,19 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { switch (data) { case SLIWD_RESCAN_FILES: /* Rescan files */ - this->selected = NULL; + this->selected = nullptr; _load_check_data.Clear(); if (!gui_scope) break; _fios_path_changed = true; this->fios_items.BuildFileList(this->abstract_filetype, this->fop); - this->vscroll->SetCount(this->fios_items.Length()); - this->selected = NULL; + this->vscroll->SetCount((uint)this->fios_items.Length()); + this->selected = nullptr; _load_check_data.Clear(); /* We reset the files filtered */ @@ -805,12 +799,12 @@ public: switch (this->abstract_filetype) { case FT_HEIGHTMAP: - this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors()); + this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == nullptr || _load_check_data.HasErrors()); break; case FT_SAVEGAME: case FT_SCENARIO: { - bool disabled = this->selected == NULL || _load_check_data.HasErrors(); + bool disabled = this->selected == nullptr || _load_check_data.HasErrors(); if (!_settings_client.gui.UserIsAllowedToChangeNewGRFs()) { disabled |= _load_check_data.HasNewGrfs() && _load_check_data.grf_compatibility == GLC_NOT_FOUND; } @@ -828,7 +822,7 @@ public: case SLIWD_FILTER_CHANGES: /* Filter changes */ - this->fios_items_shown.Resize(this->fios_items.Length()); + this->fios_items_shown.resize(this->fios_items.Length()); uint items_shown_count = 0; ///< The number of items shown in the list /* We pass through every fios item */ for (uint i = 0; i < this->fios_items.Length(); i++) { @@ -845,7 +839,7 @@ public: if (&(this->fios_items[i]) == this->selected && this->fios_items_shown[i] == false) { /* The selected element has been filtered out */ - this->selected = NULL; + this->selected = nullptr; this->OnInvalidateData(SLIWD_SELECTION_CHANGES); } } @@ -855,7 +849,7 @@ public: } } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { if (wid == WID_SL_FILTER) { this->string_filter.SetFilterTerm(this->filter_editbox.text.buf); diff --git a/src/fontcache.cpp b/src/fontcache.cpp index 2811f17989..d63b90e86a 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -19,6 +19,7 @@ #include "zoom_type.h" #include "gfx_layout.h" #include "zoom_func.h" +#include "fileio_func.h" #include "table/sprites.h" #include "table/control_codes.h" @@ -41,7 +42,7 @@ FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs), height(_ ascender(_default_font_ascender[fs]), descender(_default_font_ascender[fs] - _default_font_height[fs]), units_per_em(1) { - assert(this->parent == NULL || this->fs == this->parent->fs); + assert(this->parent == nullptr || this->fs == this->parent->fs); FontCache::caches[this->fs] = this; Layouter::ResetFontCache(this->fs); } @@ -84,7 +85,7 @@ public: virtual int GetHeight() const; virtual bool GetDrawGlyphShadow(); virtual GlyphID MapCharToGlyph(WChar key) { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } - virtual const void *GetFontTable(uint32 tag, size_t &length) { length = 0; return NULL; } + virtual const void *GetFontTable(uint32 tag, size_t &length) { length = 0; return nullptr; } virtual const char *GetFontName() { return "sprite"; } virtual bool IsBuiltInFont() { return true; } }; @@ -93,7 +94,7 @@ public: * Create a new sprite font cache. * @param fs The font size to create the cache for. */ -SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(NULL) +SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(nullptr) { this->InitializeUnicodeGlyphMap(); } @@ -108,14 +109,14 @@ SpriteFontCache::~SpriteFontCache() SpriteID SpriteFontCache::GetUnicodeGlyph(GlyphID key) { - if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) return 0; + if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) return 0; return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)]; } void SpriteFontCache::SetUnicodeGlyph(GlyphID key, SpriteID sprite) { - if (this->glyph_to_spriteid_map == NULL) this->glyph_to_spriteid_map = CallocT(256); - if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT(256); + if (this->glyph_to_spriteid_map == nullptr) this->glyph_to_spriteid_map = CallocT(256); + if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == nullptr) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT(256); this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite; } @@ -159,13 +160,13 @@ void SpriteFontCache::InitializeUnicodeGlyphMap() */ void SpriteFontCache::ClearGlyphToSpriteMap() { - if (this->glyph_to_spriteid_map == NULL) return; + if (this->glyph_to_spriteid_map == nullptr) return; for (uint i = 0; i < 256; i++) { free(this->glyph_to_spriteid_map[i]); } free(this->glyph_to_spriteid_map); - this->glyph_to_spriteid_map = NULL; + this->glyph_to_spriteid_map = nullptr; } void SpriteFontCache::ClearFontCache() @@ -199,16 +200,16 @@ bool SpriteFontCache::GetDrawGlyphShadow() /* static */ FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) }; -#ifdef WITH_FREETYPE -#include -#include FT_FREETYPE_H -#include FT_GLYPH_H -#include FT_TRUETYPE_TABLES_H +#if defined(WITH_FREETYPE) || defined(_WIN32) -/** Font cache for fonts that are based on a freetype font. */ -class FreeTypeFontCache : public FontCache { -private: - FT_Face face; ///< The font face associated with this font. +FreeTypeSettings _freetype; + +static const byte FACE_COLOUR = 1; +static const byte SHADOW_COLOUR = 2; + +/** Font cache for fonts that are based on a TrueType font. */ +class TrueTypeFontCache : public FontCache { +protected: int req_size; ///< Requested font size. int used_size; ///< Used font size. @@ -239,31 +240,233 @@ private: GlyphEntry *GetGlyphPtr(GlyphID key); void SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate = false); - void SetFontSize(FontSize fs, FT_Face face, int pixels); + + virtual const void *InternalGetFontTable(uint32 tag, size_t &length) = 0; + virtual const Sprite *InternalGetGlyph(GlyphID key, bool aa) = 0; public: - FreeTypeFontCache(FontSize fs, FT_Face face, int pixels); - ~FreeTypeFontCache(); + TrueTypeFontCache(FontSize fs, int pixels); + virtual ~TrueTypeFontCache(); virtual int GetFontSize() const { return this->used_size; } virtual SpriteID GetUnicodeGlyph(WChar key) { return this->parent->GetUnicodeGlyph(key); } virtual void SetUnicodeGlyph(WChar key, SpriteID sprite) { this->parent->SetUnicodeGlyph(key, sprite); } virtual void InitializeUnicodeGlyphMap() { this->parent->InitializeUnicodeGlyphMap(); } - virtual void ClearFontCache(); virtual const Sprite *GetGlyph(GlyphID key); + virtual const void *GetFontTable(uint32 tag, size_t &length); + virtual void ClearFontCache(); virtual uint GetGlyphWidth(GlyphID key); virtual bool GetDrawGlyphShadow(); + virtual bool IsBuiltInFont() { return false; } +}; + +/** + * Create a new TrueTypeFontCache. + * @param fs The font size that is going to be cached. + * @param pixels The number of pixels this font should be high. + */ +TrueTypeFontCache::TrueTypeFontCache(FontSize fs, int pixels) : FontCache(fs), req_size(pixels), glyph_to_sprite(nullptr) +{ +} + +/** + * Free everything that was allocated for this font cache. + */ +TrueTypeFontCache::~TrueTypeFontCache() +{ + this->ClearFontCache(); + + for (auto &iter : this->font_tables) { + free(iter.second.second); + } +} + +/** + * Reset cached glyphs. + */ +void TrueTypeFontCache::ClearFontCache() +{ + if (this->glyph_to_sprite == nullptr) return; + + for (int i = 0; i < 256; i++) { + if (this->glyph_to_sprite[i] == nullptr) continue; + + for (int j = 0; j < 256; j++) { + if (this->glyph_to_sprite[i][j].duplicate) continue; + free(this->glyph_to_sprite[i][j].sprite); + } + + free(this->glyph_to_sprite[i]); + } + + free(this->glyph_to_sprite); + this->glyph_to_sprite = nullptr; + + Layouter::ResetFontCache(this->fs); +} + + +TrueTypeFontCache::GlyphEntry *TrueTypeFontCache::GetGlyphPtr(GlyphID key) +{ + if (this->glyph_to_sprite == nullptr) return nullptr; + if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) return nullptr; + return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)]; +} + +void TrueTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate) +{ + if (this->glyph_to_sprite == nullptr) { + DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs); + this->glyph_to_sprite = CallocT(256); + } + + if (this->glyph_to_sprite[GB(key, 8, 8)] == nullptr) { + DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs); + this->glyph_to_sprite[GB(key, 8, 8)] = CallocT(256); + } + + DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs); + this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite; + this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width; + this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate; +} + +static void *AllocateFont(size_t size) +{ + return MallocT(size); +} + + +/* Check if a glyph should be rendered with anti-aliasing. */ +static bool GetFontAAState(FontSize size) +{ + /* AA is only supported for 32 bpp */ + if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false; + + switch (size) { + default: NOT_REACHED(); + case FS_NORMAL: return _freetype.medium.aa; + case FS_SMALL: return _freetype.small.aa; + case FS_LARGE: return _freetype.large.aa; + case FS_MONO: return _freetype.mono.aa; + } +} + +bool TrueTypeFontCache::GetDrawGlyphShadow() +{ + return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL); +} + +uint TrueTypeFontCache::GetGlyphWidth(GlyphID key) +{ + if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key); + + GlyphEntry *glyph = this->GetGlyphPtr(key); + if (glyph == nullptr || glyph->sprite == nullptr) { + this->GetGlyph(key); + glyph = this->GetGlyphPtr(key); + } + + return glyph->width; +} + +const Sprite *TrueTypeFontCache::GetGlyph(GlyphID key) +{ + if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyph(key); + + /* Check for the glyph in our cache */ + GlyphEntry *glyph = this->GetGlyphPtr(key); + if (glyph != nullptr && glyph->sprite != nullptr) return glyph->sprite; + + if (key == 0) { + GlyphID question_glyph = this->MapCharToGlyph('?'); + if (question_glyph == 0) { + /* The font misses the '?' character. Use built-in sprite. + * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */ +#define CPSET { 0, 0, 0, 0, 1 } +#define CP___ { 0, 0, 0, 0, 0 } + static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = { + CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___, + CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___, + CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, + CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, + CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, + CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, + CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, + CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, + CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, + CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, + }; +#undef CPSET +#undef CP___ + static const SpriteLoader::Sprite builtin_questionmark = { + 10, // height + 8, // width + 0, // x_offs + 0, // y_offs + ST_FONT, + builtin_questionmark_data + }; + + Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont); + assert(spr != nullptr); + GlyphEntry new_glyph; + new_glyph.sprite = spr; + new_glyph.width = spr->width + (this->fs != FS_NORMAL); + this->SetGlyphPtr(key, &new_glyph, false); + return new_glyph.sprite; + } else { + /* Use '?' for missing characters. */ + this->GetGlyph(question_glyph); + glyph = this->GetGlyphPtr(question_glyph); + this->SetGlyphPtr(key, glyph, true); + return glyph->sprite; + } + } + + return this->InternalGetGlyph(key, GetFontAAState(this->fs)); +} + +const void *TrueTypeFontCache::GetFontTable(uint32 tag, size_t &length) +{ + const FontTable::iterator iter = this->font_tables.Find(tag); + if (iter != this->font_tables.data() + this->font_tables.size()) { + length = iter->second.first; + return iter->second.second; + } + + const void *result = this->InternalGetFontTable(tag, length); + + this->font_tables.Insert(tag, SmallPair(length, result)); + return result; +} + + +#ifdef WITH_FREETYPE +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H +#include FT_TRUETYPE_TABLES_H + +/** Font cache for fonts that are based on a freetype font. */ +class FreeTypeFontCache : public TrueTypeFontCache { +private: + FT_Face face; ///< The font face associated with this font. + + void SetFontSize(FontSize fs, FT_Face face, int pixels); + virtual const void *InternalGetFontTable(uint32 tag, size_t &length); + virtual const Sprite *InternalGetGlyph(GlyphID key, bool aa); + +public: + FreeTypeFontCache(FontSize fs, FT_Face face, int pixels); + ~FreeTypeFontCache(); + virtual void ClearFontCache(); virtual GlyphID MapCharToGlyph(WChar key); - virtual const void *GetFontTable(uint32 tag, size_t &length); virtual const char *GetFontName() { return face->family_name; } virtual bool IsBuiltInFont() { return false; } }; -FT_Library _library = NULL; +FT_Library _library = nullptr; -FreeTypeSettings _freetype; - -static const byte FACE_COLOUR = 1; -static const byte SHADOW_COLOUR = 2; /** * Create a new FreeTypeFontCache. @@ -271,9 +474,9 @@ static const byte SHADOW_COLOUR = 2; * @param face The font that has to be loaded. * @param pixels The number of pixels this font should be high. */ -FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : FontCache(fs), face(face), req_size(pixels), glyph_to_sprite(NULL) +FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : TrueTypeFontCache(fs, pixels), face(face) { - assert(face != NULL); + assert(face != nullptr); this->SetFontSize(fs, face, pixels); } @@ -286,7 +489,7 @@ void FreeTypeFontCache::SetFontSize(FontSize fs, FT_Face face, int pixels) pixels = scaled_height; TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head); - if (head != NULL) { + if (head != nullptr) { /* Font height is minimum height plus the difference between the default * height for this font size and the small size. */ int diff = scaled_height - ScaleFontTrad(_default_font_height[FS_SMALL]); @@ -338,7 +541,7 @@ void FreeTypeFontCache::SetFontSize(FontSize fs, FT_Face face, int pixels) */ static void LoadFreeTypeFont(FontSize fs) { - FreeTypeSubSetting *settings = NULL; + FreeTypeSubSetting *settings = nullptr; switch (fs) { default: NOT_REACHED(); case FS_SMALL: settings = &_freetype.small; break; @@ -349,7 +552,7 @@ static void LoadFreeTypeFont(FontSize fs) if (StrEmpty(settings->font)) return; - if (_library == NULL) { + if (_library == nullptr) { if (FT_Init_FreeType(&_library) != FT_Err_Ok) { ShowInfoF("Unable to initialize FreeType, using sprite fonts instead"); return; @@ -358,7 +561,7 @@ static void LoadFreeTypeFont(FontSize fs) DEBUG(freetype, 2, "Initialized"); } - FT_Face face = NULL; + FT_Face face = nullptr; FT_Error error = FT_New_Face(_library, settings->font, 0, &face); if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face); @@ -384,7 +587,7 @@ static void LoadFreeTypeFont(FontSize fs) } } - if (found != NULL) { + if (found != nullptr) { error = FT_Set_Charmap(face, found); if (error == FT_Err_Ok) goto found_face; } @@ -408,12 +611,8 @@ found_face: FreeTypeFontCache::~FreeTypeFontCache() { FT_Done_Face(this->face); - this->face = NULL; + this->face = nullptr; this->ClearFontCache(); - - for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) { - free(iter->second.second); - } } /** @@ -422,132 +621,16 @@ FreeTypeFontCache::~FreeTypeFontCache() void FreeTypeFontCache::ClearFontCache() { /* Font scaling might have changed, determine font size anew if it was automatically selected. */ - if (this->face != NULL) this->SetFontSize(this->fs, this->face, this->req_size); + if (this->face != nullptr) this->SetFontSize(this->fs, this->face, this->req_size); - if (this->glyph_to_sprite == NULL) return; - - for (int i = 0; i < 256; i++) { - if (this->glyph_to_sprite[i] == NULL) continue; - - for (int j = 0; j < 256; j++) { - if (this->glyph_to_sprite[i][j].duplicate) continue; - free(this->glyph_to_sprite[i][j].sprite); - } - - free(this->glyph_to_sprite[i]); - } - - free(this->glyph_to_sprite); - this->glyph_to_sprite = NULL; - - Layouter::ResetFontCache(this->fs); -} - -FreeTypeFontCache::GlyphEntry *FreeTypeFontCache::GetGlyphPtr(GlyphID key) -{ - if (this->glyph_to_sprite == NULL) return NULL; - if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) return NULL; - return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)]; + this->TrueTypeFontCache::ClearFontCache(); } -void FreeTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate) +const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa) { - if (this->glyph_to_sprite == NULL) { - DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs); - this->glyph_to_sprite = CallocT(256); - } - - if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) { - DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs); - this->glyph_to_sprite[GB(key, 8, 8)] = CallocT(256); - } - - DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs); - this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite; - this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width; - this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate; -} - -static void *AllocateFont(size_t size) -{ - return MallocT(size); -} - - -/* Check if a glyph should be rendered with antialiasing */ -static bool GetFontAAState(FontSize size) -{ - /* AA is only supported for 32 bpp */ - if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false; - - switch (size) { - default: NOT_REACHED(); - case FS_NORMAL: return _freetype.medium.aa; - case FS_SMALL: return _freetype.small.aa; - case FS_LARGE: return _freetype.large.aa; - case FS_MONO: return _freetype.mono.aa; - } -} - - -const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key) -{ - if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyph(key); - - /* Check for the glyph in our cache */ - GlyphEntry *glyph = this->GetGlyphPtr(key); - if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite; - FT_GlyphSlot slot = this->face->glyph; - bool aa = GetFontAAState(this->fs); - - GlyphEntry new_glyph; - if (key == 0) { - GlyphID question_glyph = this->MapCharToGlyph('?'); - if (question_glyph == 0) { - /* The font misses the '?' character. Use built-in sprite. - * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */ -#define CPSET { 0, 0, 0, 0, 1 } -#define CP___ { 0, 0, 0, 0, 0 } - static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = { - CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___, - CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___, - CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, - CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, - CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, - CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, - CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, - CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, - CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, - CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, - }; -#undef CPSET -#undef CP___ - static const SpriteLoader::Sprite builtin_questionmark = { - 10, // height - 8, // width - 0, // x_offs - 0, // y_offs - ST_FONT, - builtin_questionmark_data - }; - - Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont); - assert(spr != NULL); - new_glyph.sprite = spr; - new_glyph.width = spr->width + (this->fs != FS_NORMAL); - this->SetGlyphPtr(key, &new_glyph, false); - return new_glyph.sprite; - } else { - /* Use '?' for missing characters. */ - this->GetGlyph(question_glyph); - glyph = this->GetGlyphPtr(question_glyph); - this->SetGlyphPtr(key, glyph, true); - return glyph->sprite; - } - } FT_Load_Glyph(this->face, key, aa ? FT_LOAD_TARGET_NORMAL : FT_LOAD_TARGET_MONO); FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); @@ -591,6 +674,7 @@ const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key) } } + GlyphEntry new_glyph; new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont); new_glyph.width = slot->advance.x >> 6; @@ -600,25 +684,6 @@ const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key) } -bool FreeTypeFontCache::GetDrawGlyphShadow() -{ - return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL); -} - - -uint FreeTypeFontCache::GetGlyphWidth(GlyphID key) -{ - if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key); - - GlyphEntry *glyph = this->GetGlyphPtr(key); - if (glyph == NULL || glyph->sprite == NULL) { - this->GetGlyph(key); - glyph = this->GetGlyphPtr(key); - } - - return glyph->width; -} - GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key) { assert(IsPrintable(key)); @@ -630,31 +695,340 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key) return FT_Get_Char_Index(this->face, key); } -const void *FreeTypeFontCache::GetFontTable(uint32 tag, size_t &length) +const void *FreeTypeFontCache::InternalGetFontTable(uint32 tag, size_t &length) { - const FontTable::iterator iter = this->font_tables.Find(tag); - if (iter != this->font_tables.End()) { - length = iter->second.first; - return iter->second.second; - } - FT_ULong len = 0; - FT_Byte *result = NULL; + FT_Byte *result = nullptr; - FT_Load_Sfnt_Table(this->face, tag, 0, NULL, &len); + FT_Load_Sfnt_Table(this->face, tag, 0, nullptr, &len); if (len > 0) { result = MallocT(len); FT_Load_Sfnt_Table(this->face, tag, 0, result, &len); } - length = len; - this->font_tables.Insert(tag, SmallPair(length, result)); + length = len; return result; } +#elif defined(_WIN32) + +#include "os/windows/win32.h" +#ifndef ANTIALIASED_QUALITY +#define ANTIALIASED_QUALITY 4 +#endif + +/** Font cache for fonts that are based on a Win32 font. */ +class Win32FontCache : public TrueTypeFontCache { +private: + LOGFONT logfont; ///< Logical font information for selecting the font face. + HFONT font = nullptr; ///< The font face associated with this font. + HDC dc = nullptr; ///< Cached GDI device context. + HGDIOBJ old_font; ///< Old font selected into the GDI context. + SIZE glyph_size; ///< Maximum size of regular glyphs. + + void SetFontSize(FontSize fs, int pixels); + virtual const void *InternalGetFontTable(uint32 tag, size_t &length); + virtual const Sprite *InternalGetGlyph(GlyphID key, bool aa); + +public: + Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels); + ~Win32FontCache(); + virtual void ClearFontCache(); + virtual GlyphID MapCharToGlyph(WChar key); + virtual const char *GetFontName() { return WIDE_TO_MB(this->logfont.lfFaceName); } + virtual bool IsBuiltInFont() { return false; } + virtual void *GetOSHandle() { return &this->logfont; } +}; + + +/** + * Create a new Win32FontCache. + * @param fs The font size that is going to be cached. + * @param logfont The font that has to be loaded. + * @param pixels The number of pixels this font should be high. + */ +Win32FontCache::Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels) : TrueTypeFontCache(fs, pixels), logfont(logfont) +{ + this->dc = CreateCompatibleDC(nullptr); + this->SetFontSize(fs, pixels); +} + +Win32FontCache::~Win32FontCache() +{ + this->ClearFontCache(); + DeleteDC(this->dc); + DeleteObject(this->font); +} + +void Win32FontCache::SetFontSize(FontSize fs, int pixels) +{ + if (pixels == 0) { + /* Try to determine a good height based on the minimal height recommended by the font. */ + int scaled_height = ScaleFontTrad(_default_font_height[this->fs]); + pixels = scaled_height; + + HFONT temp = CreateFontIndirect(&this->logfont); + if (temp != nullptr) { + HGDIOBJ old = SelectObject(this->dc, temp); + + UINT size = GetOutlineTextMetrics(this->dc, 0, nullptr); + LPOUTLINETEXTMETRIC otm = (LPOUTLINETEXTMETRIC)AllocaM(BYTE, size); + GetOutlineTextMetrics(this->dc, size, otm); + + /* Font height is minimum height plus the difference between the default + * height for this font size and the small size. */ + int diff = scaled_height - ScaleFontTrad(_default_font_height[FS_SMALL]); + pixels = Clamp(min(otm->otmusMinimumPPEM, 20) + diff, scaled_height, MAX_FONT_SIZE); + + SelectObject(dc, old); + DeleteObject(temp); + } + } else { + pixels = ScaleFontTrad(pixels); + } + this->used_size = pixels; + + /* Create GDI font handle. */ + this->logfont.lfHeight = -pixels; + this->logfont.lfWidth = 0; + this->logfont.lfOutPrecision = ANTIALIASED_QUALITY; + + if (this->font != nullptr) { + SelectObject(dc, this->old_font); + DeleteObject(this->font); + } + this->font = CreateFontIndirect(&this->logfont); + this->old_font = SelectObject(this->dc, this->font); + + /* Query the font metrics we needed. */ + UINT otmSize = GetOutlineTextMetrics(this->dc, 0, nullptr); + POUTLINETEXTMETRIC otm = (POUTLINETEXTMETRIC)AllocaM(BYTE, otmSize); + GetOutlineTextMetrics(this->dc, otmSize, otm); + + this->units_per_em = otm->otmEMSquare; + this->ascender = otm->otmTextMetrics.tmAscent; + this->descender = otm->otmTextMetrics.tmDescent; + this->height = this->ascender + this->descender; + this->glyph_size.cx = otm->otmTextMetrics.tmMaxCharWidth; + this->glyph_size.cy = otm->otmTextMetrics.tmHeight; + + DEBUG(freetype, 2, "Loaded font '%s' with size %d", FS2OTTD((LPTSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)), pixels); +} + +/** + * Reset cached glyphs. + */ +void Win32FontCache::ClearFontCache() +{ + /* GUI scaling might have changed, determine font size anew if it was automatically selected. */ + if (this->font != nullptr) this->SetFontSize(this->fs, this->req_size); + + this->TrueTypeFontCache::ClearFontCache(); +} + +/* virtual */ const Sprite *Win32FontCache::InternalGetGlyph(GlyphID key, bool aa) +{ + GLYPHMETRICS gm; + MAT2 mat = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; + + /* Make a guess for the needed memory size. */ + DWORD size = this->glyph_size.cy * Align(aa ? this->glyph_size.cx : max(this->glyph_size.cx / 8l, 1l), 4); // Bitmap data is DWORD-aligned rows. + byte *bmp = AllocaM(byte, size); + size = GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat); + + if (size == GDI_ERROR) { + /* No dice with the guess. First query size of needed glyph memory, then allocate the + * memory and query again. This dance is necessary as some glyphs will only render with + * the exact matching size; e.g. the space glyph has no pixels and must be requested + * with size == 0, anything else fails. Unfortunately, a failed call doesn't return any + * info about the size and thus the triple GetGlyphOutline()-call. */ + size = GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, 0, nullptr, &mat); + if (size == GDI_ERROR) usererror("Unable to render font glyph"); + bmp = AllocaM(byte, size); + GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat); + } + + /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel. */ + uint width = max(1U, (uint)gm.gmBlackBoxX + (this->fs == FS_NORMAL)); + uint height = max(1U, (uint)gm.gmBlackBoxY + (this->fs == FS_NORMAL)); + + /* Limit glyph size to prevent overflows later on. */ + if (width > 256 || height > 256) usererror("Font glyph is too large"); + + /* GDI has rendered the glyph, now we allocate a sprite and copy the image into it. */ + SpriteLoader::Sprite sprite; + sprite.AllocateData(ZOOM_LVL_NORMAL, width * height); + sprite.type = ST_FONT; + sprite.width = width; + sprite.height = height; + sprite.x_offs = gm.gmptGlyphOrigin.x; + sprite.y_offs = this->ascender - gm.gmptGlyphOrigin.y; + + if (size > 0) { + /* All pixel data returned by GDI is in the form of DWORD-aligned rows. + * For a non anti-aliased glyph, the returned bitmap has one bit per pixel. + * For anti-aliased rendering, GDI uses the strange value range of 0 to 64, + * inclusively. To map this to 0 to 255, we shift left by two and then + * subtract one. */ + uint pitch = Align(aa ? gm.gmBlackBoxX : max(gm.gmBlackBoxX / 8u, 1u), 4); + + /* Draw shadow for medium size. */ + if (this->fs == FS_NORMAL && !aa) { + for (uint y = 0; y < gm.gmBlackBoxY; y++) { + for (uint x = 0; x < gm.gmBlackBoxX; x++) { + if (aa ? (bmp[x + y * pitch] > 0) : HasBit(bmp[(x / 8) + y * pitch], 7 - (x % 8))) { + sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR; + sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? (bmp[x + y * pitch] << 2) - 1 : 0xFF; + } + } + } + } + + for (uint y = 0; y < gm.gmBlackBoxY; y++) { + for (uint x = 0; x < gm.gmBlackBoxX; x++) { + if (aa ? (bmp[x + y * pitch] > 0) : HasBit(bmp[(x / 8) + y * pitch], 7 - (x % 8))) { + sprite.data[x + y * sprite.width].m = FACE_COLOUR; + sprite.data[x + y * sprite.width].a = aa ? (bmp[x + y * pitch] << 2) - 1 : 0xFF; + } + } + } + } + + GlyphEntry new_glyph; + new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont); + new_glyph.width = gm.gmCellIncX; + + this->SetGlyphPtr(key, &new_glyph); + + return new_glyph.sprite; +} + +/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(WChar key) +{ + assert(IsPrintable(key)); + + if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { + return this->parent->MapCharToGlyph(key); + } + + /* Convert characters outside of the BMP into surrogate pairs. */ + WCHAR chars[2]; + if (key >= 0x010000U) { + chars[0] = (WCHAR)(((key - 0x010000U) >> 10) + 0xD800); + chars[1] = (WCHAR)(((key - 0x010000U) & 0x3FF) + 0xDC00); + } else { + chars[0] = (WCHAR)(key & 0xFFFF); + } + + WORD glyphs[2] = {0, 0}; + GetGlyphIndicesW(this->dc, chars, key >= 0x010000U ? 2 : 1, glyphs, GGI_MARK_NONEXISTING_GLYPHS); + + return glyphs[0] != 0xFFFF ? glyphs[0] : 0; +} + +/* virtual */ const void *Win32FontCache::InternalGetFontTable(uint32 tag, size_t &length) +{ + DWORD len = GetFontData(this->dc, tag, 0, nullptr, 0); + + void *result = nullptr; + if (len != GDI_ERROR && len > 0) { + result = MallocT(len); + GetFontData(this->dc, tag, 0, result, len); + } + + length = len; + return result; +} + +/** + * Loads the GDI font. + * If a GDI font description is present, e.g. from the automatic font + * fallback search, use it. Otherwise, try to resolve it by font name. + * @param fs The font size to load. + */ +static void LoadWin32Font(FontSize fs) +{ + static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" }; + + FreeTypeSubSetting *settings = nullptr; + switch (fs) { + default: NOT_REACHED(); + case FS_SMALL: settings = &_freetype.small; break; + case FS_NORMAL: settings = &_freetype.medium; break; + case FS_LARGE: settings = &_freetype.large; break; + case FS_MONO: settings = &_freetype.mono; break; + } + + if (StrEmpty(settings->font)) return; + + LOGFONT logfont; + MemSetT(&logfont, 0); + logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH; + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_OUTLINE_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + + if (settings->os_handle != nullptr) { + logfont = *(const LOGFONT *)settings->os_handle; + } else if (strchr(settings->font, '.') != nullptr && FileExists(settings->font)) { + /* Might be a font file name, try load it. */ + TCHAR fontPath[MAX_PATH]; + convert_to_fs(settings->font, fontPath, lengthof(fontPath), false); + + if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) { + /* Try a nice little undocumented function first for getting the internal font name. + * Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */ + typedef BOOL(WINAPI * PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD); +#ifdef UNICODE + static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoW"); +#else + static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoA"); +#endif + + if (GetFontResourceInfo != nullptr) { + /* Try to query an array of LOGFONTs that describe the file. */ + DWORD len = 0; + if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) { + LOGFONT *buf = (LOGFONT *)AllocaM(byte, len); + if (GetFontResourceInfo(fontPath, &len, buf, 2)) { + logfont = *buf; // Just use first entry. + } + } + } + + /* No dice yet. Use the file name as the font face name, hoping it matches. */ + if (logfont.lfFaceName[0] == 0) { + TCHAR fname[_MAX_FNAME]; + _tsplitpath(fontPath, nullptr, nullptr, fname, nullptr); + + _tcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE); + logfont.lfWeight = strcasestr(settings->font, " bold") != nullptr || strcasestr(settings->font, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. + } + } else { + ShowInfoF("Unable to load file '%s' for %s font, using default windows font selection instead", settings->font, SIZE_TO_NAME[fs]); + } + } + + if (logfont.lfFaceName[0] == 0) { + logfont.lfWeight = strcasestr(settings->font, " bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. + convert_to_fs(settings->font, logfont.lfFaceName, lengthof(logfont.lfFaceName), false); + } + + HFONT font = CreateFontIndirect(&logfont); + if (font == nullptr) { + ShowInfoF("Unable to use '%s' for %s font, Win32 reported error 0x%lX, using sprite font instead", settings->font, SIZE_TO_NAME[fs], GetLastError()); + return; + } + DeleteObject(font); + + new Win32FontCache(fs, logfont, settings->size); +} + #endif /* WITH_FREETYPE */ +#endif /* defined(WITH_FREETYPE) || defined(_WIN32) */ + /** * (Re)initialize the freetype related things, i.e. load the non-sprite fonts. * @param monospace Whether to initialise the monospace or regular fonts. @@ -669,6 +1043,8 @@ void InitFreeType(bool monospace) #ifdef WITH_FREETYPE LoadFreeTypeFont(fs); +#elif defined(_WIN32) + LoadWin32Font(fs); #endif } } @@ -685,6 +1061,6 @@ void UninitFreeType() #ifdef WITH_FREETYPE FT_Done_FreeType(_library); - _library = NULL; + _library = nullptr; #endif /* WITH_FREETYPE */ } diff --git a/src/fontcache.h b/src/fontcache.h index 1f5e56d924..7416103953 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -125,6 +125,15 @@ public: */ virtual const void *GetFontTable(uint32 tag, size_t &length) = 0; + /** + * Get the native OS font handle, if there is one. + * @return Opaque OS font handle. + */ + virtual void *GetOSHandle() + { + return nullptr; + } + /** * Get the name of this font. * @return The name of the font. @@ -147,7 +156,7 @@ public: */ inline bool HasParent() { - return this->parent != NULL; + return this->parent != nullptr; } /** @@ -202,13 +211,15 @@ static inline bool GetDrawGlyphShadow(FontSize size) return FontCache::Get(size)->GetDrawGlyphShadow(); } -#ifdef WITH_FREETYPE +#if defined(WITH_FREETYPE) || defined(_WIN32) /** Settings for a single freetype font. */ struct FreeTypeSubSetting { char font[MAX_PATH]; ///< The name of the font, or path to the font. uint size; ///< The (requested) size of the font. bool aa; ///< Whether to do anti aliasing or not. + + const void *os_handle = nullptr; ///< Optional native OS font info. }; /** Settings for the freetype fonts. */ @@ -221,7 +232,7 @@ struct FreeTypeSettings { extern FreeTypeSettings _freetype; -#endif /* WITH_FREETYPE */ +#endif /* defined(WITH_FREETYPE) || defined(_WIN32) */ void InitFreeType(bool monospace); void UninitFreeType(); diff --git a/src/fontdetection.cpp b/src/fontdetection.cpp index 012dd00b33..19a7e3104a 100644 --- a/src/fontdetection.cpp +++ b/src/fontdetection.cpp @@ -9,7 +9,7 @@ /** @file fontdetection.cpp Detection of the right font. */ -#ifdef WITH_FREETYPE +#if defined(WITH_FREETYPE) || defined(_WIN32) #include "stdafx.h" #include "debug.h" @@ -17,7 +17,9 @@ #include "string_func.h" #include "strings_func.h" +#ifdef WITH_FREETYPE extern FT_Library _library; +#endif /* WITH_FREETYPE */ /** * Get the font loaded into a Freetype face by using a font-name. @@ -37,6 +39,7 @@ extern FT_Library _library; #include "safeguards.h" +#ifdef WITH_FREETYPE /** * Get the short DOS 8.3 format for paths. * FreeType doesn't support Unicode filenames and Windows' fopen (as used @@ -53,7 +56,7 @@ const char *GetShortPath(const TCHAR *long_path) #ifdef UNICODE WCHAR short_path_w[MAX_PATH]; GetShortPathName(long_path, short_path_w, lengthof(short_path_w)); - WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), nullptr, nullptr); #else /* Technically not needed, but do it for consistency. */ GetShortPathName(long_path, short_path, lengthof(short_path)); @@ -101,7 +104,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) DWORD vbuflen = lengthof(vbuffer); DWORD dbuflen = lengthof(dbuffer); - ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, NULL, NULL, (byte*)dbuffer, &dbuflen); + ret = RegEnumValue(hKey, index, vbuffer, &vbuflen, nullptr, nullptr, (byte*)dbuffer, &dbuflen); if (ret != ERROR_SUCCESS) goto registry_no_font_found; /* The font names in the registry are of the following 3 forms: @@ -114,16 +117,16 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) * by '&'. Our best bet will be to do substr match for the fontname * and then let FreeType figure out which index to load */ s = _tcschr(vbuffer, _T('(')); - if (s != NULL) s[-1] = '\0'; + if (s != nullptr) s[-1] = '\0'; - if (_tcschr(vbuffer, _T('&')) == NULL) { + if (_tcschr(vbuffer, _T('&')) == nullptr) { if (_tcsicmp(vbuffer, font_namep) == 0) break; } else { - if (_tcsstr(vbuffer, font_namep) != NULL) break; + if (_tcsstr(vbuffer, font_namep) != nullptr) break; } } - if (!SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, vbuffer))) { + if (!SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, vbuffer))) { DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory"); goto folder_error; } @@ -175,7 +178,7 @@ registry_no_font_found: static const char *GetEnglishFontName(const ENUMLOGFONTEX *logfont) { static char font_name[MAX_PATH]; - const char *ret_font_name = NULL; + const char *ret_font_name = nullptr; uint pos = 0; HDC dc; HGDIOBJ oldfont; @@ -184,11 +187,11 @@ static const char *GetEnglishFontName(const ENUMLOGFONTEX *logfont) uint16 format, count, stringOffset, platformId, encodingId, languageId, nameId, length, offset; HFONT font = CreateFontIndirect(&logfont->elfLogFont); - if (font == NULL) goto err1; + if (font == nullptr) goto err1; - dc = GetDC(NULL); + dc = GetDC(nullptr); oldfont = SelectObject(dc, font); - dw = GetFontData(dc, 'eman', 0, NULL, 0); + dw = GetFontData(dc, 'eman', 0, nullptr, 0); if (dw == GDI_ERROR) goto err2; buf = MallocT(dw); @@ -236,11 +239,12 @@ err3: free(buf); err2: SelectObject(dc, oldfont); - ReleaseDC(NULL, dc); + ReleaseDC(nullptr, dc); DeleteObject(font); err1: - return ret_font_name == NULL ? WIDE_TO_MB((const TCHAR*)logfont->elfFullName) : ret_font_name; + return ret_font_name == nullptr ? WIDE_TO_MB((const TCHAR*)logfont->elfFullName) : ret_font_name; } +#endif /* WITH_FREETYPE */ class FontList { protected: @@ -249,10 +253,10 @@ protected: uint capacity; public: - FontList() : fonts(NULL), items(0), capacity(0) { }; + FontList() : fonts(nullptr), items(0), capacity(0) { }; ~FontList() { - if (this->fonts == NULL) return; + if (this->fonts == nullptr) return; for (uint i = 0; i < this->items; i++) { free(this->fonts[i]); @@ -303,12 +307,12 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT FONTSIGNATURE fs; memset(&fs, 0, sizeof(fs)); HFONT font = CreateFontIndirect(&logfont->elfLogFont); - if (font != NULL) { - HDC dc = GetDC(NULL); + if (font != nullptr) { + HDC dc = GetDC(nullptr); HGDIOBJ oldfont = SelectObject(dc, font); GetTextCharsetInfo(dc, &fs, 0); SelectObject(dc, oldfont); - ReleaseDC(NULL, dc); + ReleaseDC(nullptr, dc); DeleteObject(font); } if ((fs.fsCsb[0] & info->locale.lsCsbSupported[0]) == 0 && (fs.fsCsb[1] & info->locale.lsCsbSupported[1]) == 0) return 1; @@ -317,12 +321,13 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT char font_name[MAX_PATH]; convert_from_fs((const TCHAR *)logfont->elfFullName, font_name, lengthof(font_name)); +#ifdef WITH_FREETYPE /* Add english name after font name */ const char *english_name = GetEnglishFontName(logfont); strecpy(font_name + strlen(font_name) + 1, english_name, lastof(font_name)); /* Check whether we can actually load the font. */ - bool ft_init = _library != NULL; + bool ft_init = _library != nullptr; bool found = false; FT_Face face; /* Init FreeType if needed. */ @@ -333,13 +338,18 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT if (!ft_init) { /* Uninit FreeType if we did the init. */ FT_Done_FreeType(_library); - _library = NULL; + _library = nullptr; } if (!found) return 1; +#else + const char *english_name = font_name; +#endif /* WITH_FREETYPE */ - info->callback->SetFontNames(info->settings, font_name); - if (info->callback->FindMissingGlyphs(NULL)) return 1; + PLOGFONT os_data = MallocT(1); + *os_data = logfont->elfLogFont; + info->callback->SetFontNames(info->settings, font_name, os_data); + if (info->callback->FindMissingGlyphs(nullptr)) return 1; DEBUG(freetype, 1, "Fallback font: %s (%s)", font_name, english_name); return 0; // stop enumerating } @@ -362,9 +372,9 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i font.lfFaceName[0] = '\0'; font.lfPitchAndFamily = 0; - HDC dc = GetDC(NULL); + HDC dc = GetDC(nullptr); int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0); - ReleaseDC(NULL, dc); + ReleaseDC(nullptr, dc); return ret == 0; } @@ -389,7 +399,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) if (MacOSVersionIsAtLeast(10, 6, 0)) { /* Simply creating the font using CTFontCreateWithNameAndSize will *always* return - * something, no matter the name. As such, we can't use it to check for existance. + * something, no matter the name. As such, we can't use it to check for existence. * We instead query the list of all font descriptors that match the given name which * does not do this stupid name fallback. */ CTFontDescriptorRef name_desc = CTFontDescriptorCreateWithNameAndSize(name, 0.0); @@ -400,14 +410,14 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) CFRelease(name); /* Loop over all matches until we can get a path for one of them. */ - for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs) && os_err != noErr; i++) { - CTFontRef font = CTFontCreateWithFontDescriptor((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i), 0.0, NULL); + for (CFIndex i = 0; descs != nullptr && i < CFArrayGetCount(descs) && os_err != noErr; i++) { + CTFontRef font = CTFontCreateWithFontDescriptor((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i), 0.0, nullptr); CFURLRef fontURL = (CFURLRef)CTFontCopyAttribute(font, kCTFontURLAttribute); if (CFURLGetFileSystemRepresentation(fontURL, true, file_path, lengthof(file_path))) os_err = noErr; CFRelease(font); CFRelease(fontURL); } - if (descs != NULL) CFRelease(descs); + if (descs != nullptr) CFRelease(descs); } else #endif { @@ -467,7 +477,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i /* Just copy the first part of the isocode. */ strecpy(lang, language_isocode, lastof(lang)); char *sep = strchr(lang, '_'); - if (sep != NULL) *sep = '\0'; + if (sep != nullptr) *sep = '\0'; } /* Create a font descriptor matching the wanted language and latin (english) glyphs. */ @@ -487,7 +497,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i CFRelease(mandatory_attribs); CFRelease(lang_desc); - for (CFIndex i = 0; descs != NULL && i < CFArrayGetCount(descs); i++) { + for (CFIndex i = 0; descs != nullptr && i < CFArrayGetCount(descs); i++) { CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs, i); /* Get font traits. */ @@ -515,13 +525,13 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i /* Save result. */ callback->SetFontNames(settings, name); - if (!callback->FindMissingGlyphs(NULL)) { + if (!callback->FindMissingGlyphs(nullptr)) { DEBUG(freetype, 2, "CT-Font for %s: %s", language_isocode, name); result = true; break; } } - if (descs != NULL) CFRelease(descs); + if (descs != nullptr) CFRelease(descs); } else #endif { @@ -530,7 +540,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i * are available to the application. */ ATSFontIterator itr; ATSFontRef font; - ATSFontIteratorCreate(kATSFontContextLocal, NULL, NULL, kATSOptionFlagsDefaultScope, &itr); + ATSFontIteratorCreate(kATSFontContextLocal, nullptr, nullptr, kATSOptionFlagsDefaultScope, &itr); while (!result && ATSFontIteratorNext(itr, &font) == noErr) { /* Get font name. */ char name[128]; @@ -545,14 +555,14 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i if (monospace != callback->Monospace()) continue; /* We only want the base font and not bold or italic variants. */ - if (strstr(name, "Italic") != NULL || strstr(name, "Bold")) continue; + if (strstr(name, "Italic") != nullptr || strstr(name, "Bold")) continue; /* Skip some inappropriate or ugly looking fonts that have better alternatives. */ if (name[0] == '.' || strncmp(name, "Apple Symbols", 13) == 0 || strncmp(name, "LastResort", 10) == 0) continue; /* Save result. */ callback->SetFontNames(settings, name); - if (!callback->FindMissingGlyphs(NULL)) { + if (!callback->FindMissingGlyphs(nullptr)) { DEBUG(freetype, 2, "ATS-Font for %s: %s", language_isocode, name); result = true; break; @@ -566,10 +576,10 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i /* For some OS versions, the font 'Arial Unicode MS' does not report all languages it * supports. If we didn't find any other font, just try it, maybe we get lucky. */ callback->SetFontNames(settings, "Arial Unicode MS"); - result = !callback->FindMissingGlyphs(NULL); + result = !callback->FindMissingGlyphs(nullptr); } - callback->FindMissingGlyphs(NULL); + callback->FindMissingGlyphs(nullptr); return result; } @@ -599,7 +609,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) /* Split & strip the font's style */ font_family = stredup(font_name); font_style = strchr(font_family, ','); - if (font_style != NULL) { + if (font_style != nullptr) { font_style[0] = '\0'; font_style++; while (*font_style == ' ' || *font_style == '\t') font_style++; @@ -607,13 +617,13 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) /* Resolve the name and populate the information structure */ pat = FcNameParse((FcChar8*)font_family); - if (font_style != NULL) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style); + if (font_style != nullptr) FcPatternAddString(pat, FC_STYLE, (FcChar8*)font_style); FcConfigSubstitute(0, pat, FcMatchPattern); FcDefaultSubstitute(pat); fs = FcFontSetCreate(); match = FcFontMatch(0, pat, &result); - if (fs != NULL && match != NULL) { + if (fs != nullptr && match != nullptr) { int i; FcChar8 *family; FcChar8 *style; @@ -627,7 +637,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) FcPatternGetString(fs->fonts[i], FC_STYLE, 0, &style) == FcResultMatch) { /* The correct style? */ - if (font_style != NULL && strcasecmp(font_style, (char*)style) != 0) continue; + if (font_style != nullptr && strcasecmp(font_style, (char*)style) != 0) continue; /* Font config takes the best shot, which, if the family name is spelled * wrongly a 'random' font, so check whether the family name is the @@ -660,29 +670,29 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i char lang[16]; seprintf(lang, lastof(lang), ":lang=%s", language_isocode); char *split = strchr(lang, '_'); - if (split != NULL) *split = '\0'; + if (split != nullptr) *split = '\0'; /* First create a pattern to match the wanted language. */ FcPattern *pat = FcNameParse((FcChar8*)lang); /* We only want to know the filename. */ - FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SPACING, FC_SLANT, FC_WEIGHT, NULL); + FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SPACING, FC_SLANT, FC_WEIGHT, nullptr); /* Get the list of filenames matching the wanted language. */ - FcFontSet *fs = FcFontList(NULL, pat, os); + FcFontSet *fs = FcFontList(nullptr, pat, os); /* We don't need these anymore. */ FcObjectSetDestroy(os); FcPatternDestroy(pat); - if (fs != NULL) { + if (fs != nullptr) { int best_weight = -1; - const char *best_font = NULL; + const char *best_font = nullptr; for (int i = 0; i < fs->nfont; i++) { FcPattern *font = fs->fonts[i]; - FcChar8 *file = NULL; + FcChar8 *file = nullptr; FcResult res = FcPatternGetString(font, FC_FILE, 0, &file); - if (res != FcResultMatch || file == NULL) { + if (res != FcResultMatch || file == nullptr) { continue; } @@ -701,7 +711,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i callback->SetFontNames(settings, (const char*)file); - bool missing = callback->FindMissingGlyphs(NULL); + bool missing = callback->FindMissingGlyphs(nullptr); DEBUG(freetype, 1, "Font \"%s\" misses%s glyphs", file, missing ? "" : " no"); if (!missing) { @@ -710,7 +720,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i } } - if (best_font != NULL) { + if (best_font != nullptr) { ret = true; callback->SetFontNames(settings, best_font); InitFreeType(callback->Monospace()); diff --git a/src/fontdetection.h b/src/fontdetection.h index edb961e6d3..01e0223cd6 100644 --- a/src/fontdetection.h +++ b/src/fontdetection.h @@ -27,6 +27,9 @@ */ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face); +#endif /* WITH_FREETYPE */ + +#if defined(WITH_FREETYPE) || defined(_WIN32) /** * We would like to have a fallback font as the current one * doesn't contain all characters we need. @@ -39,6 +42,6 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face); */ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, int winlangid, class MissingGlyphSearcher *callback); -#endif /* WITH_FREETYPE */ +#endif /* defined(WITH_FREETYPE) || defined(WIN32)*/ #endif diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index 7a5650dfc0..951b3ab7b9 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -22,6 +22,9 @@ #include "guitimer_func.h" #include "company_base.h" #include "ai/ai_info.hpp" +#include "ai/ai_instance.hpp" +#include "game/game.hpp" +#include "game/game_instance.hpp" #include "widgets/framerate_widget.h" #include "safeguards.h" @@ -365,6 +368,9 @@ static const NWidgetPart _framerate_window_widgets[] = { NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_TIMES_NAMES), SetScrollbar(WID_FRW_SCROLLBAR), NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_TIMES_CURRENT), SetScrollbar(WID_FRW_SCROLLBAR), NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_TIMES_AVERAGE), SetScrollbar(WID_FRW_SCROLLBAR), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_FRW_SEL_MEMORY), + NWidget(WWT_EMPTY, COLOUR_GREY, WID_FRW_ALLOCSIZE), SetScrollbar(WID_FRW_SCROLLBAR), + EndContainer(), EndContainer(), NWidget(WWT_TEXT, COLOUR_GREY, WID_FRW_INFO_DATA_POINTS), SetDataTip(STR_FRAMERATE_DATA_POINTS, 0x0), EndContainer(), @@ -378,6 +384,7 @@ static const NWidgetPart _framerate_window_widgets[] = { struct FramerateWindow : Window { bool small; + bool showing_memory; GUITimer next_update; int num_active; int num_displayed; @@ -424,6 +431,7 @@ struct FramerateWindow : Window { { this->InitNested(number); this->small = this->IsShaded(); + this->showing_memory = true; this->UpdateData(); this->num_displayed = this->num_active; this->next_update.SetInterval(100); @@ -432,7 +440,7 @@ struct FramerateWindow : Window { ResizeWindow(this, 0, (max(MIN_ELEMENTS, this->num_displayed) - MIN_ELEMENTS) * FONT_HEIGHT_NORMAL); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { bool elapsed = this->next_update.Elapsed(delta_ms); @@ -453,6 +461,7 @@ struct FramerateWindow : Window { void UpdateData() { double gl_rate = _pf_data[PFE_GAMELOOP].GetRate(); + bool have_script = false; this->rate_gameloop.SetRate(gl_rate, _pf_data[PFE_GAMELOOP].expected_rate); this->speed_gameloop.SetRate(gl_rate / _pf_data[PFE_GAMELOOP].expected_rate, 1.0); if (this->small) return; // in small mode, this is everything needed @@ -463,7 +472,16 @@ struct FramerateWindow : Window { for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) { this->times_shortterm[e].SetTime(_pf_data[e].GetAverageDurationMilliseconds(8), MILLISECONDS_PER_TICK); this->times_longterm[e].SetTime(_pf_data[e].GetAverageDurationMilliseconds(NUM_FRAMERATE_POINTS), MILLISECONDS_PER_TICK); - if (_pf_data[e].num_valid > 0) new_active++; + if (_pf_data[e].num_valid > 0) { + new_active++; + if (e == PFE_GAMESCRIPT || e >= PFE_AI0) have_script = true; + } + } + + if (this->showing_memory != have_script) { + NWidgetStacked *plane = this->GetWidget(WID_FRW_SEL_MEMORY); + plane->SetDisplayedPlane(have_script ? 0 : SZSP_VERTICAL); + this->showing_memory = have_script; } if (new_active != this->num_active) { @@ -475,7 +493,7 @@ struct FramerateWindow : Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_FRW_CAPTION: @@ -503,7 +521,7 @@ struct FramerateWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_FRW_RATE_GAMELOOP: @@ -545,7 +563,8 @@ struct FramerateWindow : Window { } case WID_FRW_TIMES_CURRENT: - case WID_FRW_TIMES_AVERAGE: { + case WID_FRW_TIMES_AVERAGE: + case WID_FRW_ALLOCSIZE: { *size = GetStringBoundingBox(STR_FRAMERATE_CURRENT + (widget - WID_FRW_TIMES_CURRENT)); SetDParam(0, 999999); SetDParam(1, 2); @@ -582,7 +601,38 @@ struct FramerateWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawElementAllocationsColumn(const Rect &r) const + { + const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR); + uint16 skip = sb->GetPosition(); + int drawable = this->num_displayed; + int y = r.top; + DrawString(r.left, r.right, y, STR_FRAMERATE_MEMORYUSE, TC_FROMSTRING, SA_CENTER, true); + y += FONT_HEIGHT_NORMAL + VSPACING; + for (PerformanceElement e : DISPLAY_ORDER_PFE) { + if (_pf_data[e].num_valid == 0) continue; + if (skip > 0) { + skip--; + } else if (e == PFE_GAMESCRIPT || e >= PFE_AI0) { + if (e == PFE_GAMESCRIPT) { + SetDParam(0, Game::GetInstance()->GetAllocatedMemory()); + } else { + SetDParam(0, Company::Get(e - PFE_AI0)->ai_instance->GetAllocatedMemory()); + } + DrawString(r.left, r.right, y, STR_FRAMERATE_BYTES_GOOD, TC_FROMSTRING, SA_RIGHT); + y += FONT_HEIGHT_NORMAL; + drawable--; + if (drawable == 0) break; + } else { + /* skip non-script */ + y += FONT_HEIGHT_NORMAL; + drawable--; + if (drawable == 0) break; + } + } + } + + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_FRW_TIMES_NAMES: { @@ -618,10 +668,13 @@ struct FramerateWindow : Window { /* Render averages of all recorded values */ DrawElementTimesColumn(r, STR_FRAMERATE_AVERAGE, this->times_longterm); break; + case WID_FRW_ALLOCSIZE: + DrawElementAllocationsColumn(r); + break; } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_FRW_TIMES_NAMES: @@ -646,7 +699,7 @@ struct FramerateWindow : Window { } } - virtual void OnResize() + void OnResize() override { auto *wid = this->GetWidget(WID_FRW_TIMES_NAMES); this->num_displayed = (wid->current_y - wid->min_y - VSPACING) / FONT_HEIGHT_NORMAL - 1; // subtract 1 for headings @@ -694,7 +747,7 @@ struct FrametimeGraphWindow : Window { this->InitNested(number); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_FGW_CAPTION: @@ -709,7 +762,7 @@ struct FrametimeGraphWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_FGW_GRAPH) { SetDParam(0, 100); @@ -807,7 +860,7 @@ struct FrametimeGraphWindow : Window { this->SelectVerticalScale(peak_value); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { this->SetDirty(); @@ -826,7 +879,7 @@ struct FrametimeGraphWindow : Window { return (value - src_min) * dst_diff / src_diff + dst_min; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget == WID_FGW_GRAPH) { const TimingMeasurement *durations = _pf_data[this->element].durations; @@ -865,7 +918,7 @@ struct FrametimeGraphWindow : Window { } } } - /* Draw divison lines and labels for the horizontal axis */ + /* Draw division lines and labels for the horizontal axis */ for (uint division = horz_divisions; division > 0; division--) { int x = Scinterlate(x_zero, x_max, 0, (int)horz_divisions, (int)horz_divisions - (int)division); GfxDrawLine(x, y_max, x, y_zero, c_grid); diff --git a/src/game/game.hpp b/src/game/game.hpp index 329ba5e500..95d9aa0a13 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -112,11 +112,9 @@ public: */ static class GameInstance *GetInstance() { return Game::instance; } -#if defined(ENABLE_NETWORK) /** Wrapper function for GameScanner::HasGame */ static bool HasGame(const struct ContentInfo *ci, bool md5sum); static bool HasGameLibrary(const ContentInfo *ci, bool md5sum); -#endif /** Gets the ScriptScanner instance that is used to find Game scripts */ static GameScannerInfo *GetScannerInfo(); /** Gets the ScriptScanner instance that is used to find Game Libraries */ diff --git a/src/game/game_config.cpp b/src/game/game_config.cpp index 50cd5da4e0..f96985ef7e 100644 --- a/src/game/game_config.cpp +++ b/src/game/game_config.cpp @@ -25,7 +25,7 @@ } else { config = &_settings_game.game_config; } - if (*config == NULL) *config = new GameConfig(); + if (*config == nullptr) *config = new GameConfig(); return *config; } @@ -42,5 +42,5 @@ ScriptInfo *GameConfig::FindInfo(const char *name, int version, bool force_exact bool GameConfig::ResetInfo(bool force_exact_match) { this->info = (ScriptInfo *)Game::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); - return this->info != NULL; + return this->info != nullptr; } diff --git a/src/game/game_config.hpp b/src/game/game_config.hpp index e9ebdc38c1..dfae62c3a9 100644 --- a/src/game/game_config.hpp +++ b/src/game/game_config.hpp @@ -42,7 +42,7 @@ public: bool ResetInfo(bool force_exact_match); protected: - /* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match); + ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override; }; #endif /* GAME_CONFIG_HPP */ diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp index 10b079bee3..394b77fb83 100644 --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -25,10 +25,10 @@ #include "../safeguards.h" /* static */ uint Game::frame_counter = 0; -/* static */ GameInfo *Game::info = NULL; -/* static */ GameInstance *Game::instance = NULL; -/* static */ GameScannerInfo *Game::scanner_info = NULL; -/* static */ GameScannerLibrary *Game::scanner_library = NULL; +/* static */ GameInfo *Game::info = nullptr; +/* static */ GameInstance *Game::instance = nullptr; +/* static */ GameScannerInfo *Game::scanner_info = nullptr; +/* static */ GameScannerLibrary *Game::scanner_library = nullptr; /* static */ void Game::GameLoop() { @@ -36,7 +36,7 @@ PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT); return; } - if (Game::instance == NULL) { + if (Game::instance == nullptr) { PerformanceMeasurer::SetInactive(PFE_GAMESCRIPT); return; } @@ -45,7 +45,7 @@ Game::frame_counter++; - Backup cur_company(_current_company, FILE_LINE); + Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); Game::instance->GameLoop(); cur_company.Restore(); @@ -58,11 +58,11 @@ /* static */ void Game::Initialize() { - if (Game::instance != NULL) Game::Uninitialize(true); + if (Game::instance != nullptr) Game::Uninitialize(true); Game::frame_counter = 0; - if (Game::scanner_info == NULL) { + if (Game::scanner_info == nullptr) { TarScanner::DoScan(TarScanner::GAME); Game::scanner_info = new GameScannerInfo(); Game::scanner_info->Initialize(); @@ -73,18 +73,18 @@ /* static */ void Game::StartNew() { - if (Game::instance != NULL) return; + if (Game::instance != nullptr) return; /* Clients shouldn't start GameScripts */ if (_networking && !_network_server) return; GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); GameInfo *info = config->GetInfo(); - if (info == NULL) return; + if (info == nullptr) return; config->AnchorUnchangeableSettings(); - Backup cur_company(_current_company, FILE_LINE); + Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); Game::info = info; @@ -98,11 +98,11 @@ /* static */ void Game::Uninitialize(bool keepConfig) { - Backup cur_company(_current_company, FILE_LINE); + Backup cur_company(_current_company, FILE_LINE); delete Game::instance; - Game::instance = NULL; - Game::info = NULL; + Game::instance = nullptr; + Game::info = nullptr; cur_company.Restore(); @@ -111,33 +111,33 @@ } else { delete Game::scanner_info; delete Game::scanner_library; - Game::scanner_info = NULL; - Game::scanner_library = NULL; + Game::scanner_info = nullptr; + Game::scanner_library = nullptr; - if (_settings_game.game_config != NULL) { + if (_settings_game.game_config != nullptr) { delete _settings_game.game_config; - _settings_game.game_config = NULL; + _settings_game.game_config = nullptr; } - if (_settings_newgame.game_config != NULL) { + if (_settings_newgame.game_config != nullptr) { delete _settings_newgame.game_config; - _settings_newgame.game_config = NULL; + _settings_newgame.game_config = nullptr; } } } /* static */ void Game::Pause() { - if (Game::instance != NULL) Game::instance->Pause(); + if (Game::instance != nullptr) Game::instance->Pause(); } /* static */ void Game::Unpause() { - if (Game::instance != NULL) Game::instance->Unpause(); + if (Game::instance != nullptr) Game::instance->Unpause(); } /* static */ bool Game::IsPaused() { - return Game::instance != NULL? Game::instance->IsPaused() : false; + return Game::instance != nullptr? Game::instance->IsPaused() : false; } /* static */ void Game::NewEvent(ScriptEvent *event) @@ -152,13 +152,13 @@ } /* Check if Game instance is alive */ - if (Game::instance == NULL) { + if (Game::instance == nullptr) { event->Release(); return; } /* Queue the event */ - Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); + Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->InsertEvent(event); cur_company.Restore(); @@ -169,23 +169,23 @@ { /* Check for both newgame as current game if we can reload the GameInfo inside * the GameConfig. If not, remove the Game from the list. */ - if (_settings_game.game_config != NULL && _settings_game.game_config->HasScript()) { + if (_settings_game.game_config != nullptr && _settings_game.game_config->HasScript()) { if (!_settings_game.game_config->ResetInfo(true)) { DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game.game_config->GetName()); - _settings_game.game_config->Change(NULL); - if (Game::instance != NULL) { + _settings_game.game_config->Change(nullptr); + if (Game::instance != nullptr) { delete Game::instance; - Game::instance = NULL; - Game::info = NULL; + Game::instance = nullptr; + Game::info = nullptr; } - } else if (Game::instance != NULL) { + } else if (Game::instance != nullptr) { Game::info = _settings_game.game_config->GetInfo(); } } - if (_settings_newgame.game_config != NULL && _settings_newgame.game_config->HasScript()) { + if (_settings_newgame.game_config != nullptr && _settings_newgame.game_config->HasScript()) { if (!_settings_newgame.game_config->ResetInfo(false)) { DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName()); - _settings_newgame.game_config->Change(NULL); + _settings_newgame.game_config->Change(nullptr); } } } @@ -206,8 +206,8 @@ /* static */ void Game::Save() { - if (Game::instance != NULL && (!_networking || _network_server)) { - Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); + if (Game::instance != nullptr && (!_networking || _network_server)) { + Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->Save(); cur_company.Restore(); } else { @@ -217,8 +217,8 @@ /* static */ void Game::Load(int version) { - if (Game::instance != NULL && (!_networking || _network_server)) { - Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); + if (Game::instance != nullptr && (!_networking || _network_server)) { + Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->Load(version); cur_company.Restore(); } else { @@ -257,8 +257,6 @@ return Game::scanner_library->FindLibrary(library, version); } -#if defined(ENABLE_NETWORK) - /** * Check whether we have an Game (library) with the exact characteristics as ci. * @param ci the characteristics to search on (shortname and md5sum) @@ -275,8 +273,6 @@ return Game::scanner_library->HasScript(ci, md5sum); } -#endif /* defined(ENABLE_NETWORK) */ - /* static */ GameScannerInfo *Game::GetScannerInfo() { return Game::scanner_info; diff --git a/src/game/game_info.cpp b/src/game/game_info.cpp index f8c04608b7..d815e6fd20 100644 --- a/src/game/game_info.cpp +++ b/src/game/game_info.cpp @@ -26,7 +26,7 @@ static bool CheckAPIVersion(const char *api_version) { return 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; + strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0; } #if defined(_WIN32) @@ -55,8 +55,8 @@ template <> const char *GetClassName() { return "GSInfo"; } /* static */ SQInteger GameInfo::Constructor(HSQUIRRELVM vm) { /* Get the GameInfo */ - 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 GameInfo to RegisterGame"); + SQUserPointer instance = nullptr; + if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == nullptr) return sq_throwerror(vm, "Pass an instance of a child class of GameInfo to RegisterGame"); GameInfo *info = (GameInfo *)instance; SQInteger res = ScriptInfo::Constructor(vm, info); @@ -82,7 +82,7 @@ template <> const char *GetClassName() { return "GSInfo"; } } /* Remove the link to the real instance, else it might get deleted by RegisterGame() */ - sq_setinstanceup(vm, 2, NULL); + sq_setinstanceup(vm, 2, nullptr); /* Register the Game to the base system */ info->GetScanner()->RegisterScript(info); return 0; @@ -91,7 +91,7 @@ template <> const char *GetClassName() { return "GSInfo"; } GameInfo::GameInfo() : min_loadable_version(0), is_developer_only(false), - api_version(NULL) + api_version(nullptr) { } diff --git a/src/game/game_info.hpp b/src/game/game_info.hpp index f4fc5ed86b..8a2215d52f 100644 --- a/src/game/game_info.hpp +++ b/src/game/game_info.hpp @@ -40,7 +40,7 @@ public: */ const char *GetAPIVersion() const { return this->api_version; } - /* virtual */ bool IsDeveloperOnly() const { return this->is_developer_only; } + bool IsDeveloperOnly() const override { return this->is_developer_only; } private: int min_loadable_version; ///< The Game can load savegame data if the version is equal or greater than this. @@ -51,7 +51,7 @@ private: /** All static information from an Game library like name, version, etc. */ class GameLibrary : public ScriptInfo { public: - GameLibrary() : ScriptInfo(), category(NULL) {}; + GameLibrary() : ScriptInfo(), category(nullptr) {}; ~GameLibrary(); /** diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp index e9853f569e..8d4f5f2b22 100644 --- a/src/game/game_instance.cpp +++ b/src/game/game_instance.cpp @@ -64,6 +64,7 @@ #include "../script/api/game/game_rail.hpp.sq" #include "../script/api/game/game_railtypelist.hpp.sq" #include "../script/api/game/game_road.hpp.sq" +#include "../script/api/game/game_roadtypelist.hpp.sq" #include "../script/api/game/game_sign.hpp.sq" #include "../script/api/game/game_signlist.hpp.sq" #include "../script/api/game/game_station.hpp.sq" @@ -174,6 +175,7 @@ void GameInstance::RegisterAPI() SQGSRail_Register(this->engine); SQGSRailTypeList_Register(this->engine); SQGSRoad_Register(this->engine); + SQGSRoadTypeList_Register(this->engine); SQGSSign_Register(this->engine); SQGSSignList_Register(this->engine); SQGSStation_Register(this->engine); @@ -239,10 +241,10 @@ void GameInstance::Died() ShowAIDebugWindow(OWNER_DEITY); const GameInfo *info = Game::GetInfo(); - if (info != NULL) { + if (info != nullptr) { ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); - if (info->GetURL() != NULL) { + if (info->GetURL() != nullptr) { ScriptLog::Info("Please report the error to the following URL:"); ScriptLog::Info(info->GetURL()); } diff --git a/src/game/game_instance.hpp b/src/game/game_instance.hpp index 08ce344247..dd0e7950aa 100644 --- a/src/game/game_instance.hpp +++ b/src/game/game_instance.hpp @@ -25,14 +25,14 @@ public: */ void Initialize(class GameInfo *info); - /* virtual */ int GetSetting(const char *name); - /* virtual */ ScriptInfo *FindLibrary(const char *library, int version); + int GetSetting(const char *name) override; + ScriptInfo *FindLibrary(const char *library, int version) override; private: - /* virtual */ void RegisterAPI(); - /* virtual */ void Died(); - /* virtual */ CommandCallback *GetDoCommandCallback(); - /* virtual */ void LoadDummyScript() {} + void RegisterAPI() override; + void Died() override; + CommandCallback *GetDoCommandCallback() override; + void LoadDummyScript() override {} }; #endif /* GAME_INSTANCE_HPP */ diff --git a/src/game/game_scanner.cpp b/src/game/game_scanner.cpp index 38afdd1357..862c867cf4 100644 --- a/src/game/game_scanner.cpp +++ b/src/game/game_scanner.cpp @@ -35,14 +35,14 @@ void GameScannerInfo::RegisterAPI(class Squirrel *engine) GameInfo *GameScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match) { - if (this->info_list.size() == 0) return NULL; - if (nameParam == NULL) return NULL; + if (this->info_list.size() == 0) return nullptr; + if (nameParam == nullptr) return nullptr; char game_name[1024]; strecpy(game_name, nameParam, lastof(game_name)); strtolower(game_name); - GameInfo *info = NULL; + GameInfo *info = nullptr; int version = -1; if (versionParam == -1) { @@ -51,7 +51,7 @@ GameInfo *GameScannerInfo::FindInfo(const char *nameParam, int versionParam, boo /* If we didn't find a match Game script, maybe the user included a version */ char *e = strrchr(game_name, '.'); - if (e == NULL) return NULL; + if (e == nullptr) return nullptr; *e = '\0'; e++; versionParam = atoi(e); @@ -106,7 +106,7 @@ GameLibrary *GameScannerLibrary::FindLibrary(const char *library, int version) /* Check if the library + version exists */ ScriptInfoList::iterator iter = this->info_list.find(library_name); - if (iter == this->info_list.end()) return NULL; + if (iter == this->info_list.end()) return nullptr; return static_cast((*iter).second); } diff --git a/src/game/game_scanner.hpp b/src/game/game_scanner.hpp index 071d19d38d..2530ec792a 100644 --- a/src/game/game_scanner.hpp +++ b/src/game/game_scanner.hpp @@ -16,44 +16,44 @@ class GameScannerInfo : public ScriptScanner { public: - /* virtual */ void Initialize(); + void Initialize() override; /** * Check if we have a game by name and version available in our list. * @param nameParam The name of the game script. * @param versionParam The version of the game script, 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 game script that matched. + * @return nullptr if no match found, otherwise the game script that matched. */ class GameInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match); 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 GAME_DIR; } - /* virtual */ const char *GetScannerName() const { return "Game Scripts"; } - /* virtual */ void RegisterAPI(class Squirrel *engine); + void GetScriptName(ScriptInfo *info, char *name, const char *last) override; + const char *GetFileName() const override { return PATHSEP "info.nut"; } + Subdirectory GetDirectory() const override { return GAME_DIR; } + const char *GetScannerName() const override { return "Game Scripts"; } + void RegisterAPI(class Squirrel *engine) override; }; class GameScannerLibrary : public ScriptScanner { public: - /* virtual */ void Initialize(); + void Initialize() override; /** * 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. + * @return The library if found, nullptr otherwise. */ class GameLibrary *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 GAME_LIBRARY_DIR; } - /* virtual */ const char *GetScannerName() const { return "GS Libraries"; } - /* virtual */ void RegisterAPI(class Squirrel *engine); + void GetScriptName(ScriptInfo *info, char *name, const char *last) override; + const char *GetFileName() const override { return PATHSEP "library.nut"; } + Subdirectory GetDirectory() const override { return GAME_LIBRARY_DIR; } + const char *GetScannerName() const override { return "GS Libraries"; } + void RegisterAPI(class Squirrel *engine) override; }; #endif /* GAME_SCANNER_HPP */ diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index c71483b391..b69b8f46be 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -23,6 +23,7 @@ #include "table/strings.h" #include +#include #include "../safeguards.h" @@ -62,11 +63,11 @@ void NORETURN CDECL strgen_fatal(const char *s, ...) /** * Create a new container for language strings. * @param language The language name. - * @param end If not NULL, terminate \a language at this position. + * @param end If not nullptr, terminate \a language at this position. */ LanguageStrings::LanguageStrings(const char *language, const char *end) { - this->language = stredup(language, end != NULL ? end - 1 : NULL); + this->language = stredup(language, end != nullptr ? end - 1 : nullptr); } /** Free everything. */ @@ -78,36 +79,31 @@ LanguageStrings::~LanguageStrings() /** * Read all the raw language strings from the given file. * @param file The file to read from. - * @return The raw strings, or NULL upon error. + * @return The raw strings, or nullptr upon error. */ -LanguageStrings *ReadRawLanguageStrings(const char *file) +std::unique_ptr ReadRawLanguageStrings(const char *file) { - LanguageStrings *ret = NULL; - FILE *fh = NULL; try { size_t to_read; - fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); - if (fh == NULL) { - return NULL; - } + FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); + if (fh == nullptr) return nullptr; + + FileCloser fhClose(fh); const char *langname = strrchr(file, PATHSEPCHAR); - if (langname == NULL) { + if (langname == nullptr) { langname = file; } else { langname++; } /* Check for invalid empty filename */ - if (*langname == '.' || *langname == 0) { - fclose(fh); - return NULL; - } + if (*langname == '.' || *langname == 0) return nullptr; - ret = new LanguageStrings(langname, strchr(langname, '.')); + std::unique_ptr ret(new LanguageStrings(langname, strchr(langname, '.'))); char buffer[2048]; - while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != NULL) { + while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != nullptr) { size_t len = strlen(buffer); /* Remove trailing spaces/newlines from the string. */ @@ -115,7 +111,7 @@ LanguageStrings *ReadRawLanguageStrings(const char *file) while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--; buffer[i] = '\0'; - *ret->lines.Append() = stredup(buffer, buffer + to_read - 1); + ret->lines.emplace_back(buffer, i); if (len > to_read) { to_read = 0; @@ -124,20 +120,17 @@ LanguageStrings *ReadRawLanguageStrings(const char *file) } } - fclose(fh); return ret; } catch (...) { - if (fh != NULL) fclose(fh); - delete ret; - return NULL; + return nullptr; } } /** A reader that simply reads using fopen. */ struct StringListReader : StringReader { - const char * const *p; ///< The current location of the iteration. - const char * const *end; ///< The end of the iteration. + StringList::const_iterator p; ///< The current location of the iteration. + StringList::const_iterator end; ///< The end of the iteration. /** * Create the reader. @@ -146,16 +139,16 @@ struct StringListReader : StringReader { * @param master Are we reading the master file? * @param translation Are we reading a translation? */ - StringListReader(StringData &data, const LanguageStrings *strings, bool master, bool translation) : - StringReader(data, strings->language, master, translation), p(strings->lines.Begin()), end(strings->lines.End()) + StringListReader(StringData &data, const LanguageStrings &strings, bool master, bool translation) : + StringReader(data, strings.language, master, translation), p(strings.lines.begin()), end(strings.lines.end()) { } - /* virtual */ char *ReadLine(char *buffer, const char *last) + char *ReadLine(char *buffer, const char *last) override { - if (this->p == this->end) return NULL; + if (this->p == this->end) return nullptr; - strecpy(buffer, *this->p, last); + strecpy(buffer, this->p->c_str(), last); this->p++; return buffer; @@ -164,13 +157,13 @@ struct StringListReader : StringReader { /** Class for writing an encoded language. */ struct TranslationWriter : LanguageWriter { - StringList *strings; ///< The encoded strings. + StringList &strings; ///< The encoded strings. /** * Writer for the encoded data. * @param strings The string table to add the strings to. */ - TranslationWriter(StringList *strings) : strings(strings) + TranslationWriter(StringList &strings) : strings(strings) { } @@ -191,28 +184,25 @@ struct TranslationWriter : LanguageWriter { void Write(const byte *buffer, size_t length) { - char *dest = MallocT(length + 1); - memcpy(dest, buffer, length); - dest[length] = '\0'; - *this->strings->Append() = dest; + this->strings.emplace_back((const char *)buffer, length); } }; /** Class for writing the string IDs. */ struct StringNameWriter : HeaderWriter { - StringList *strings; ///< The string names. + StringList &strings; ///< The string names. /** * Writer for the string names. * @param strings The string table to add the strings to. */ - StringNameWriter(StringList *strings) : strings(strings) + StringNameWriter(StringList &strings) : strings(strings) { } void WriteStringID(const char *name, int stringid) { - if (stringid == (int)this->strings->Length()) *this->strings->Append() = stredup(name); + if (stringid == (int)this->strings.size()) this->strings.emplace_back(name); } void Finalise(const StringData &data) @@ -242,11 +232,14 @@ public: this->FileScanner::Scan(".txt", directory, false); } - /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override { if (strcmp(filename, exclude) == 0) return true; - *gs->raw_strings.Append() = ReadRawLanguageStrings(filename); + auto ls = ReadRawLanguageStrings(filename); + if (ls == nullptr) return false; + + gs->raw_strings.push_back(std::move(ls)); return true; } }; @@ -261,15 +254,18 @@ GameStrings *LoadTranslations() char filename[512]; strecpy(filename, info->GetMainScript(), lastof(filename)); char *e = strrchr(filename, PATHSEPCHAR); - if (e == NULL) return NULL; + if (e == nullptr) return nullptr; e++; // Make 'e' point after the PATHSEPCHAR strecpy(e, "lang" PATHSEP "english.txt", lastof(filename)); - if (!FioCheckFileExists(filename, GAME_DIR)) return NULL; + if (!FioCheckFileExists(filename, GAME_DIR)) return nullptr; + + auto ls = ReadRawLanguageStrings(filename); + if (ls == nullptr) return nullptr; GameStrings *gs = new GameStrings(); try { - *gs->raw_strings.Append() = ReadRawLanguageStrings(filename); + gs->raw_strings.push_back(std::move(ls)); /* Scan for other language files */ LanguageScanner scanner(gs, filename); @@ -278,7 +274,7 @@ GameStrings *LoadTranslations() const char *tar_filename = info->GetTarFile(); TarList::iterator iter; - if (tar_filename != NULL && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { + if (tar_filename != nullptr && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { /* The main script is in a tar file, so find all files that * are in the same tar and add them to the langfile scanner. */ TarFileList::iterator tar; @@ -301,7 +297,7 @@ GameStrings *LoadTranslations() return gs; } catch (...) { delete gs; - return NULL; + return nullptr; } } @@ -309,29 +305,29 @@ GameStrings *LoadTranslations() void GameStrings::Compile() { StringData data(32); - StringListReader master_reader(data, this->raw_strings[0], true, false); + StringListReader master_reader(data, *this->raw_strings[0], true, false); master_reader.ParseFile(); if (_errors != 0) throw std::exception(); this->version = data.Version(); - StringNameWriter id_writer(&this->string_names); + StringNameWriter id_writer(this->string_names); id_writer.WriteHeader(data); - for (LanguageStrings **p = this->raw_strings.Begin(); p != this->raw_strings.End(); p++) { + for (const auto &p : this->raw_strings) { data.FreeTranslation(); - StringListReader translation_reader(data, *p, false, strcmp((*p)->language, "english") != 0); + StringListReader translation_reader(data, *p, false, strcmp(p->language, "english") != 0); translation_reader.ParseFile(); if (_errors != 0) throw std::exception(); - LanguageStrings *compiled = *this->compiled_strings.Append() = new LanguageStrings((*p)->language); - TranslationWriter writer(&compiled->lines); + this->compiled_strings.emplace_back(new LanguageStrings(p->language)); + TranslationWriter writer(this->compiled_strings.back()->lines); writer.WriteLang(data); } } /** The currently loaded game strings. */ -GameStrings *_current_data = NULL; +GameStrings *_current_data = nullptr; /** * Get the string pointer of a particular game string. @@ -340,8 +336,8 @@ GameStrings *_current_data = NULL; */ const char *GetGameStringPtr(uint id) { - if (id >= _current_data->cur_language->lines.Length()) return GetStringPtr(STR_UNDEFINED); - return _current_data->cur_language->lines[id]; + if (id >= _current_data->cur_language->lines.size()) return GetStringPtr(STR_UNDEFINED); + return _current_data->cur_language->lines[id].c_str(); } /** @@ -352,7 +348,7 @@ void RegisterGameTranslation(Squirrel *engine) { delete _current_data; _current_data = LoadTranslations(); - if (_current_data == NULL) return; + if (_current_data == nullptr) return; HSQUIRRELVM vm = engine->GetVM(); sq_pushroottable(vm); @@ -360,10 +356,11 @@ void RegisterGameTranslation(Squirrel *engine) if (SQ_FAILED(sq_get(vm, -2))) return; int idx = 0; - for (const char * const *p = _current_data->string_names.Begin(); p != _current_data->string_names.End(); p++, idx++) { - sq_pushstring(vm, *p, -1); + for (const auto &p : _current_data->string_names) { + sq_pushstring(vm, p.c_str(), -1); sq_pushinteger(vm, idx); sq_rawset(vm, -3); + idx++; } sq_pop(vm, 2); @@ -376,24 +373,24 @@ void RegisterGameTranslation(Squirrel *engine) */ void ReconsiderGameScriptLanguage() { - if (_current_data == NULL) return; + if (_current_data == nullptr) return; char temp[MAX_PATH]; strecpy(temp, _current_language->file, lastof(temp)); /* Remove the extension */ char *l = strrchr(temp, '.'); - assert(l != NULL); + assert(l != nullptr); *l = '\0'; /* Skip the path */ char *language = strrchr(temp, PATHSEPCHAR); - assert(language != NULL); + assert(language != nullptr); language++; - for (LanguageStrings **p = _current_data->compiled_strings.Begin(); p != _current_data->compiled_strings.End(); p++) { - if (strcmp((*p)->language, language) == 0) { - _current_data->cur_language = *p; + for (auto &p : _current_data->compiled_strings) { + if (strcmp(p->language, language) == 0) { + _current_data->cur_language = p; return; } } diff --git a/src/game/game_text.hpp b/src/game/game_text.hpp index 14da7d9b2e..c662e28f4b 100644 --- a/src/game/game_text.hpp +++ b/src/game/game_text.hpp @@ -23,18 +23,18 @@ struct LanguageStrings { const char *language; ///< Name of the language (base filename). StringList lines; ///< The lines of the file to pass into the parser/encoder. - LanguageStrings(const char *language, const char *end = NULL); + LanguageStrings(const char *language, const char *end = nullptr); ~LanguageStrings(); }; /** Container for all the game strings. */ struct GameStrings { - uint version; ///< The version of the language strings. - LanguageStrings *cur_language; ///< The current (compiled) language. + uint version; ///< The version of the language strings. + std::shared_ptr cur_language; ///< The current (compiled) language. - AutoDeleteSmallVector raw_strings; ///< The raw strings per language, first must be English/the master language!. - AutoDeleteSmallVector compiled_strings; ///< The compiled strings per language, first must be English/the master language!. - StringList string_names; ///< The names of the compiled strings. + std::vector> raw_strings; ///< The raw strings per language, first must be English/the master language!. + std::vector> compiled_strings; ///< The compiled strings per language, first must be English/the master language!. + StringList string_names; ///< The names of the compiled strings. void Compile(); }; diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 29910d7ad1..025d2ab8dd 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -34,9 +34,9 @@ extern byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! static GamelogActionType _gamelog_action_type = GLAT_NONE; ///< action to record if anything changes -LoggedAction *_gamelog_action = NULL; ///< first logged action +LoggedAction *_gamelog_action = nullptr; ///< first logged action uint _gamelog_actions = 0; ///< number of actions -static LoggedAction *_current_action = NULL; ///< current action we are logging, NULL when there is no action active +static LoggedAction *_current_action = nullptr; ///< current action we are logging, nullptr when there is no action active /** @@ -81,9 +81,9 @@ void GamelogStopAction() { assert(_gamelog_action_type != GLAT_NONE); // nobody should try to stop if there is no action in progress - bool print = _current_action != NULL; + bool print = _current_action != nullptr; - _current_action = NULL; + _current_action = nullptr; _gamelog_action_type = GLAT_NONE; if (print) GamelogPrintDebug(5); @@ -114,9 +114,9 @@ void GamelogReset() assert(_gamelog_action_type == GLAT_NONE); GamelogFree(_gamelog_action, _gamelog_actions); - _gamelog_action = NULL; + _gamelog_action = nullptr; _gamelog_actions = 0; - _current_action = NULL; + _current_action = nullptr; } /** @@ -132,18 +132,18 @@ static char *PrintGrfInfo(char *buf, const char *last, uint grfid, const uint8 * { char txt[40]; - if (md5sum != NULL) { + if (md5sum != nullptr) { md5sumToString(txt, lastof(txt), md5sum); buf += seprintf(buf, last, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt); } else { buf += seprintf(buf, last, "GRF ID %08X", BSWAP32(grfid)); } - if (gc != NULL) { + if (gc != nullptr) { buf += seprintf(buf, last, ", filename: %s (md5sum matches)", gc->filename); } else { gc = FindGRFConfig(grfid, FGCM_ANY); - if (gc != NULL) { + if (gc != nullptr) { buf += seprintf(buf, last, ", filename: %s (matches GRFID only)", gc->filename); } else { buf += seprintf(buf, last, ", unknown GRF"); @@ -178,6 +178,7 @@ struct GRFPresence{ bool was_missing; ///< Grf was missing during some gameload in the past GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {} + GRFPresence() = default; }; typedef SmallMap GrfIDMapping; @@ -272,7 +273,7 @@ void GamelogPrint(GamelogPrintProc *proc) case GLCT_GRFREM: { GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), la->at == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: "); - buf = PrintGrfInfo(buf, lastof(buffer), lc->grfrem.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); + buf = PrintGrfInfo(buf, lastof(buffer), lc->grfrem.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); if (gm == grf_names.End()) { buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); } else { @@ -298,7 +299,7 @@ void GamelogPrint(GamelogPrintProc *proc) case GLCT_GRFPARAM: { GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), "GRF parameter changed: "); - buf = PrintGrfInfo(buf, lastof(buffer), lc->grfparam.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); + buf = PrintGrfInfo(buf, lastof(buffer), lc->grfparam.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); break; } @@ -307,7 +308,7 @@ void GamelogPrint(GamelogPrintProc *proc) GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), "GRF order changed: %08X moved %d places %s", BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" ); - buf = PrintGrfInfo(buf, lastof(buffer), lc->grfmove.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); + buf = PrintGrfInfo(buf, lastof(buffer), lc->grfmove.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); break; } @@ -320,7 +321,7 @@ void GamelogPrint(GamelogPrintProc *proc) buf += seprintf(buf, lastof(buffer), "Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(lc->grfbug.grfid), (uint)lc->grfbug.data); break; } - buf = PrintGrfInfo(buf, lastof(buffer), lc->grfbug.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); + buf = PrintGrfInfo(buf, lastof(buffer), lc->grfbug.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); break; } @@ -371,21 +372,21 @@ void GamelogPrintDebug(int level) /** * Allocates new LoggedChange and new LoggedAction if needed. - * If there is no action active, NULL is returned. + * If there is no action active, nullptr is returned. * @param ct type of change - * @return new LoggedChange, or NULL if there is no action active + * @return new LoggedChange, or nullptr if there is no action active */ static LoggedChange *GamelogChange(GamelogChangeType ct) { - if (_current_action == NULL) { - if (_gamelog_action_type == GLAT_NONE) return NULL; + if (_current_action == nullptr) { + if (_gamelog_action_type == GLAT_NONE) return nullptr; _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1); _current_action = &_gamelog_action[_gamelog_actions++]; _current_action->at = _gamelog_action_type; _current_action->tick = _tick_counter; - _current_action->change = NULL; + _current_action->change = nullptr; _current_action->changes = 0; } @@ -415,7 +416,7 @@ void GamelogEmergency() */ bool GamelogTestEmergency() { - const LoggedChange *emergency = NULL; + const LoggedChange *emergency = nullptr; const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { @@ -425,7 +426,7 @@ bool GamelogTestEmergency() } } - return (emergency != NULL); + return (emergency != nullptr); } /** @@ -436,7 +437,7 @@ void GamelogRevision() assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD); LoggedChange *lc = GamelogChange(GLCT_REVISION); - if (lc == NULL) return; + if (lc == nullptr) return; memset(lc->revision.text, 0, sizeof(lc->revision.text)); strecpy(lc->revision.text, GetGamelogRevisionString(), lastof(lc->revision.text)); @@ -453,7 +454,7 @@ void GamelogMode() assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_CHEAT); LoggedChange *lc = GamelogChange(GLCT_MODE); - if (lc == NULL) return; + if (lc == nullptr) return; lc->mode.mode = _game_mode; lc->mode.landscape = _settings_game.game_creation.landscape; @@ -467,7 +468,7 @@ void GamelogOldver() assert(_gamelog_action_type == GLAT_LOAD); LoggedChange *lc = GamelogChange(GLCT_OLDVER); - if (lc == NULL) return; + if (lc == nullptr) return; lc->oldver.type = _savegame_type; lc->oldver.version = (_savegame_type == SGT_OTTD ? ((uint32)_sl_version << 8 | _sl_minor_version) : _ttdp_version); @@ -484,7 +485,7 @@ void GamelogSetting(const char *name, int32 oldval, int32 newval) assert(_gamelog_action_type == GLAT_SETTING); LoggedChange *lc = GamelogChange(GLCT_SETTING); - if (lc == NULL) return; + if (lc == nullptr) return; lc->setting.name = stredup(name); lc->setting.oldval = oldval; @@ -498,7 +499,7 @@ void GamelogSetting(const char *name, int32 oldval, int32 newval) */ void GamelogTestRevision() { - const LoggedChange *rev = NULL; + const LoggedChange *rev = nullptr; const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { @@ -508,7 +509,7 @@ void GamelogTestRevision() } } - if (rev == NULL || strcmp(rev->revision.text, GetGamelogRevisionString()) != 0 || + if (rev == nullptr || strcmp(rev->revision.text, GetGamelogRevisionString()) != 0 || rev->revision.modified != _openttd_revision_modified || rev->revision.newgrf != _openttd_newgrf_version) { GamelogRevision(); @@ -521,7 +522,7 @@ void GamelogTestRevision() */ void GamelogTestMode() { - const LoggedChange *mode = NULL; + const LoggedChange *mode = nullptr; const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { @@ -531,7 +532,7 @@ void GamelogTestMode() } } - if (mode == NULL || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) GamelogMode(); + if (mode == nullptr || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) GamelogMode(); } @@ -546,7 +547,7 @@ static void GamelogGRFBug(uint32 grfid, byte bug, uint64 data) assert(_gamelog_action_type == GLAT_GRFBUG); LoggedChange *lc = GamelogChange(GLCT_GRFBUG); - if (lc == NULL) return; + if (lc == nullptr) return; lc->grfbug.data = data; lc->grfbug.grfid = grfid; @@ -602,7 +603,7 @@ void GamelogGRFRemove(uint32 grfid) assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFREM); - if (lc == NULL) return; + if (lc == nullptr) return; lc->grfrem.grfid = grfid; } @@ -618,7 +619,7 @@ void GamelogGRFAdd(const GRFConfig *newg) if (!IsLoggableGrfConfig(newg)) return; LoggedChange *lc = GamelogChange(GLCT_GRFADD); - if (lc == NULL) return; + if (lc == nullptr) return; lc->grfadd = newg->ident; } @@ -633,7 +634,7 @@ void GamelogGRFCompatible(const GRFIdentifier *newg) assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFCOMPAT); - if (lc == NULL) return; + if (lc == nullptr) return; lc->grfcompat = *newg; } @@ -648,7 +649,7 @@ static void GamelogGRFMove(uint32 grfid, int32 offset) assert(_gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFMOVE); - if (lc == NULL) return; + if (lc == nullptr) return; lc->grfmove.grfid = grfid; lc->grfmove.offset = offset; @@ -664,7 +665,7 @@ static void GamelogGRFParameters(uint32 grfid) assert(_gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFPARAM); - if (lc == NULL) return; + if (lc == nullptr) return; lc->grfparam.grfid = grfid; } @@ -678,7 +679,7 @@ void GamelogGRFAddList(const GRFConfig *newg) { assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD); - for (; newg != NULL; newg = newg->next) { + for (; newg != nullptr; newg = newg->next) { GamelogGRFAdd(newg); } } @@ -696,14 +697,14 @@ struct GRFList { static GRFList *GenerateGRFList(const GRFConfig *grfc) { uint n = 0; - for (const GRFConfig *g = grfc; g != NULL; g = g->next) { + for (const GRFConfig *g = grfc; g != nullptr; g = g->next) { if (IsLoggableGrfConfig(g)) n++; } GRFList *list = (GRFList*)MallocT(sizeof(GRFList) + n * sizeof(GRFConfig*)); list->n = 0; - for (const GRFConfig *g = grfc; g != NULL; g = g->next) { + for (const GRFConfig *g = grfc; g != nullptr; g = g->next) { if (IsLoggableGrfConfig(g)) list->grf[list->n++] = g; } diff --git a/src/genworld.cpp b/src/genworld.cpp index 25d6a7bd9d..6aaf1a6fe0 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -34,6 +34,7 @@ #include "game/game.hpp" #include "game/game_instance.hpp" #include "string_func.h" +#include "thread.h" #include "safeguards.h" @@ -81,8 +82,8 @@ static void CleanupGeneration() /* Show all vital windows again, because we have hidden them */ if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows(); SetModalProgress(false); - _gw.proc = NULL; - _gw.abortp = NULL; + _gw.proc = nullptr; + _gw.abortp = nullptr; _gw.threaded = false; DeleteWindowByClass(WC_MODAL_PROGRESS); @@ -93,14 +94,15 @@ static void CleanupGeneration() /** * The internal, real, generate function. */ -static void _GenerateWorld(void *) +static void _GenerateWorld() { /* Make sure everything is done via OWNER_NONE. */ - Backup _cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup _cur_company(_current_company, OWNER_NONE, FILE_LINE); + std::unique_lock lock(_modal_progress_work_mutex, std::defer_lock); try { _generating_world = true; - _modal_progress_work_mutex->BeginCritical(); + lock.lock(); if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait..."); /* Set the Random() seed to generation_seed so we produce the same map with the same seed */ if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom(); @@ -169,7 +171,7 @@ static void _GenerateWorld(void *) if (_game_mode != GM_EDITOR) { Game::StartNew(); - if (Game::GetInstance() != NULL) { + if (Game::GetInstance() != nullptr) { SetGeneratingWorldProgress(GWP_RUNSCRIPT, 2500); _generating_world = true; for (i = 0; i < 2500; i++) { @@ -190,11 +192,11 @@ static void _GenerateWorld(void *) SetGeneratingWorldProgress(GWP_GAME_START, 1); /* Call any callback */ - if (_gw.proc != NULL) _gw.proc(); + if (_gw.proc != nullptr) _gw.proc(); IncreaseGeneratingWorldProgress(GWP_GAME_START); CleanupGeneration(); - _modal_progress_work_mutex->EndCritical(); + lock.unlock(); ShowNewGRFError(); @@ -210,7 +212,6 @@ static void _GenerateWorld(void *) BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true); if (_cur_company.IsValid()) _cur_company.Restore(); _generating_world = false; - _modal_progress_work_mutex->EndCritical(); throw; } } @@ -241,17 +242,15 @@ void GenerateWorldSetAbortCallback(GWAbortProc *proc) */ void WaitTillGeneratedWorld() { - if (_gw.thread == NULL) return; + if (!_gw.thread.joinable()) return; - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.unlock(); _gw.quit_thread = true; - _gw.thread->Join(); - delete _gw.thread; - _gw.thread = NULL; + _gw.thread.join(); _gw.threaded = false; - _modal_progress_work_mutex->BeginCritical(); - _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_work_mutex.lock(); + _modal_progress_paint_mutex.lock(); } /** @@ -279,11 +278,11 @@ void HandleGeneratingWorldAbortion() /* Clean up - in SE create an empty map, otherwise, go to intro menu */ _switch_mode = (_game_mode == GM_EDITOR) ? SM_EDITOR : SM_MENU; - if (_gw.abortp != NULL) _gw.abortp(); + if (_gw.abortp != nullptr) _gw.abortp(); CleanupGeneration(); - if (_gw.thread != NULL) _gw.thread->Exit(); + if (_gw.thread.joinable() && _gw.thread.get_id() == std::this_thread::get_id()) throw OTTDThreadExitSignal(); SwitchToMode(_switch_mode); } @@ -303,7 +302,7 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti _gw.size_y = size_y; SetModalProgress(true); _gw.abort = false; - _gw.abortp = NULL; + _gw.abortp = nullptr; _gw.lc = _local_company; _gw.quit_thread = false; _gw.threaded = true; @@ -325,18 +324,14 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti SetupColoursAndInitialWindow(); SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); - if (_gw.thread != NULL) { - _gw.thread->Join(); - delete _gw.thread; - _gw.thread = NULL; - } + if (_gw.thread.joinable()) _gw.thread.join(); - if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread, "ottd:genworld")) { + if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(&_gw.thread, "ottd:genworld", &_GenerateWorld)) { DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode"); _gw.threaded = false; - _modal_progress_work_mutex->EndCritical(); - _GenerateWorld(NULL); - _modal_progress_work_mutex->BeginCritical(); + _modal_progress_work_mutex.unlock(); + _GenerateWorld(); + _modal_progress_work_mutex.lock(); return; } @@ -350,7 +345,7 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti ShowGenerateWorldProgress(); /* Centre the view on the map */ - if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) { + if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) { ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true); } } diff --git a/src/genworld.h b/src/genworld.h index 1b1c806e09..56664bc0c6 100644 --- a/src/genworld.h +++ b/src/genworld.h @@ -13,6 +13,7 @@ #define GENWORLD_H #include "company_type.h" +#include /** Constants related to world generation */ enum LandscapeGenerator { @@ -59,9 +60,9 @@ struct GenWorldInfo { CompanyID lc; ///< The local_company before generating uint size_x; ///< X-size of the map uint size_y; ///< Y-size of the map - GWDoneProc *proc; ///< Proc that is called when done (can be NULL) - GWAbortProc *abortp; ///< Proc that is called when aborting (can be NULL) - class ThreadObject *thread; ///< The thread we are in (can be NULL) + GWDoneProc *proc; ///< Proc that is called when done (can be nullptr) + GWAbortProc *abortp; ///< Proc that is called when aborting (can be nullptr) + std::thread thread; ///< The thread we are in (joinable if a thread was created) }; /** Current stage of world generation process */ diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index b22ba5287e..550a193d79 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -282,14 +282,14 @@ static void LandscapeGenerationCallback(Window *w, bool confirmed) if (confirmed) StartGeneratingLandscape((GenerateLandscapeWindowMode)w->window_number); } -static DropDownList *BuildMapsizeDropDown() +static DropDownList BuildMapsizeDropDown() { - DropDownList *list = new DropDownList(); + DropDownList list; for (uint i = MIN_MAP_SIZE_BITS; i <= MAX_MAP_SIZE_BITS; i++) { DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false); item->SetParam(0, 1LL << i); - *list->Append() = item; + list.emplace_back(item); } return list; @@ -332,7 +332,7 @@ struct GenerateLandscapeWindow : public Window { } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_GL_START_DATE_TEXT: SetDParam(0, ConvertYMDToDate(_settings_newgame.game_creation.starting_year, 0, 1)); break; @@ -393,7 +393,7 @@ struct GenerateLandscapeWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* Update the climate buttons */ @@ -440,9 +440,9 @@ struct GenerateLandscapeWindow : public Window { } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { - const StringID *strs = NULL; + const StringID *strs = nullptr; switch (widget) { case WID_GL_MAX_HEIGHTLEVEL_TEXT: SetDParam(0, MAX_TILE_HEIGHT); @@ -509,7 +509,7 @@ struct GenerateLandscapeWindow : public Window { default: return; } - if (strs != NULL) { + if (strs != nullptr) { while (*strs != INVALID_STRING_ID) { *size = maxdim(*size, GetStringBoundingBox(*strs++)); } @@ -518,7 +518,7 @@ struct GenerateLandscapeWindow : public Window { size->height = max(size->height, (uint)(FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM)); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_GL_HEIGHTMAP_NAME_TEXT: { @@ -528,7 +528,7 @@ struct GenerateLandscapeWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_GL_TEMPERATE: @@ -703,7 +703,7 @@ struct GenerateLandscapeWindow : public Window { } } - virtual void OnTimeout() + void OnTimeout() override { static const int raise_widgets[] = {WID_GL_MAX_HEIGHTLEVEL_DOWN, WID_GL_MAX_HEIGHTLEVEL_UP, WID_GL_START_DATE_DOWN, WID_GL_START_DATE_UP, WID_GL_SNOW_LEVEL_UP, WID_GL_SNOW_LEVEL_DOWN, WIDGET_LIST_END}; for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) { @@ -714,7 +714,7 @@ struct GenerateLandscapeWindow : public Window { } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_GL_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break; @@ -758,10 +758,10 @@ struct GenerateLandscapeWindow : public Window { this->InvalidateData(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { /* Was 'cancel' pressed? */ - if (str == NULL) return; + if (str == nullptr) return; int32 value; if (!StrEmpty(str)) { @@ -808,14 +808,14 @@ struct GenerateLandscapeWindow : public Window { }; static WindowDesc _generate_landscape_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, _nested_generate_landscape_widgets, lengthof(_nested_generate_landscape_widgets) ); static WindowDesc _heightmap_load_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, _nested_heightmap_load_widgets, lengthof(_nested_heightmap_load_widgets) @@ -888,7 +888,7 @@ struct CreateScenarioWindow : public Window this->LowerWidget(_settings_newgame.game_creation.landscape + WID_CS_TEMPERATE); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_CS_START_DATE_TEXT: @@ -909,7 +909,7 @@ struct CreateScenarioWindow : public Window } } - virtual void OnPaint() + void OnPaint() override { this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_CS_START_DATE_UP, _settings_newgame.game_creation.starting_year >= MAX_YEAR); @@ -924,7 +924,7 @@ struct CreateScenarioWindow : public Window this->DrawWidgets(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { StringID str = STR_JUST_INT; switch (widget) { @@ -950,7 +950,7 @@ struct CreateScenarioWindow : public Window size->height += padding.height; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_CS_TEMPERATE: @@ -1015,7 +1015,7 @@ struct CreateScenarioWindow : public Window } } - virtual void OnTimeout() + void OnTimeout() override { static const int raise_widgets[] = {WID_CS_START_DATE_DOWN, WID_CS_START_DATE_UP, WID_CS_FLAT_LAND_HEIGHT_DOWN, WID_CS_FLAT_LAND_HEIGHT_UP, WIDGET_LIST_END}; for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) { @@ -1026,7 +1026,7 @@ struct CreateScenarioWindow : public Window } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_CS_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break; @@ -1035,7 +1035,7 @@ struct CreateScenarioWindow : public Window this->SetDirty(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (!StrEmpty(str)) { int32 value = atoi(str); @@ -1110,7 +1110,7 @@ static const NWidgetPart _nested_create_scenario_widgets[] = { }; static WindowDesc _create_scenario_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, _nested_create_scenario_widgets, lengthof(_nested_create_scenario_widgets) @@ -1138,7 +1138,7 @@ static const NWidgetPart _nested_generate_progress_widgets[] = { static WindowDesc _generate_progress_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, _nested_generate_progress_widgets, lengthof(_nested_generate_progress_widgets) @@ -1187,7 +1187,7 @@ struct GenerateProgressWindow : public Window { this->InitNested(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_GP_ABORT: @@ -1202,7 +1202,7 @@ struct GenerateProgressWindow : public Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_GP_PROGRESS_BAR: { @@ -1223,7 +1223,7 @@ struct GenerateProgressWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_GP_PROGRESS_BAR: @@ -1321,10 +1321,10 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin * paint thread. The 'other' thread already has the paint thread rights so * this ensures us that we are waiting until the paint thread is done * before we reacquire the mapgen rights */ - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); - _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.lock(); + _modal_progress_work_mutex.lock(); + _modal_progress_paint_mutex.unlock(); _gws.timer = _realtime_tick; } diff --git a/src/gfx.cpp b/src/gfx.cpp index 2327070a6b..3c0b38dac9 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -21,6 +21,7 @@ #include "network/network_func.h" #include "window_func.h" #include "newgrf_debug.h" +#include "thread.h" #include "table/palettes.h" #include "table/string_colours.h" @@ -46,20 +47,20 @@ bool _screen_disable_anim = false; ///< Disable palette animation (important f bool _exit_game; GameMode _game_mode; SwitchMode _switch_mode; ///< The next mainloop command. -PauseModeByte _pause_mode; +PauseMode _pause_mode; Palette _cur_palette; static byte _stringwidth_table[FS_END][224]; ///< Cache containing width of often used characters. @see GetCharacterWidth() DrawPixelInfo *_cur_dpi; byte _colour_gradient[COLOUR_END][8]; -static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE); -static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE, ZoomLevel zoom = ZOOM_LVL_NORMAL); +static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = nullptr, SpriteID sprite_id = SPR_CURSOR_MOUSE); +static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = nullptr, SpriteID sprite_id = SPR_CURSOR_MOUSE, ZoomLevel zoom = ZOOM_LVL_NORMAL); static ReusableBuffer _cursor_backup; -ZoomLevelByte _gui_zoom; ///< GUI Zoom level -ZoomLevelByte _font_zoom; ///< Font Zoom level +ZoomLevel _gui_zoom; ///< GUI Zoom level +ZoomLevel _font_zoom; ///< Font Zoom level /** * The rect for repaint. @@ -76,7 +77,7 @@ static const uint DIRTY_BLOCK_HEIGHT = 8; static const uint DIRTY_BLOCK_WIDTH = 64; static uint _dirty_bytes_per_line = 0; -static byte *_dirty_blocks = NULL; +static byte *_dirty_blocks = nullptr; extern uint _dirty_block_colour; void GfxScroll(int left, int top, int width, int height, int xo, int yo) @@ -87,9 +88,7 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo) if (_cursor.visible) UndrawMouseCursor(); -#ifdef ENABLE_NETWORK if (_networking) NetworkUndrawChatMessage(); -#endif /* ENABLE_NETWORK */ blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo); /* This part of the screen is now dirty. */ @@ -214,7 +213,7 @@ static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int * work the blitter has to do by shortening the effective line segment. * However, in order to get that right and prevent the flickering effects * of rounding errors so much additional code has to be run here that in - * the general case the effect is not noticable. */ + * the general case the effect is not noticeable. */ blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash); } @@ -342,12 +341,12 @@ static void SetColourRemap(TextColour colour) * @return In case of left or center alignment the right most pixel we have drawn to. * In case of right alignment the left most pixel we have drawn to. */ -static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, int right, StringAlignment align, bool underline, bool truncation) +static int DrawLayoutLine(const ParagraphLayouter::Line &line, int y, int left, int right, StringAlignment align, bool underline, bool truncation) { - if (line->CountRuns() == 0) return 0; + if (line.CountRuns() == 0) return 0; - int w = line->GetWidth(); - int h = line->GetLeading(); + int w = line.GetWidth(); + int h = line.GetLeading(); /* * The following is needed for truncation. @@ -369,7 +368,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, truncation &= max_w < w; // Whether we need to do truncation. int dot_width = 0; // Cache for the width of the dot. - const Sprite *dot_sprite = NULL; // Cache for the sprite of the dot. + const Sprite *dot_sprite = nullptr; // Cache for the sprite of the dot. if (truncation) { /* @@ -378,7 +377,7 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, * another size would be chosen it won't have truncated too little for * the truncation dots. */ - FontCache *fc = ((const Font*)line->GetVisualRun(0)->GetFont())->fc; + FontCache *fc = ((const Font*)line.GetVisualRun(0).GetFont())->fc; GlyphID dot_glyph = fc->MapCharToGlyph('.'); dot_width = fc->GetGlyphWidth(dot_glyph); dot_sprite = fc->GetGlyph(dot_glyph); @@ -423,9 +422,9 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, TextColour colour = TC_BLACK; bool draw_shadow = false; - for (int run_index = 0; run_index < line->CountRuns(); run_index++) { - const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); - const Font *f = (const Font*)run->GetFont(); + for (int run_index = 0; run_index < line.CountRuns(); run_index++) { + const ParagraphLayouter::VisualRun &run = line.GetVisualRun(run_index); + const Font *f = (const Font*)run.GetFont(); FontCache *fc = f->fc; colour = f->colour; @@ -437,15 +436,15 @@ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, draw_shadow = fc->GetDrawGlyphShadow() && (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK; - for (int i = 0; i < run->GetGlyphCount(); i++) { - GlyphID glyph = run->GetGlyphs()[i]; + for (int i = 0; i < run.GetGlyphCount(); i++) { + GlyphID glyph = run.GetGlyphs()[i]; /* Not a valid glyph (empty) */ if (glyph == 0xFFFF) continue; - int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x; - int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1; - int top = (int)run->GetPositions()[i * 2 + 1] + y; + int begin_x = (int)run.GetPositions()[i * 2] + left - offset_x; + int end_x = (int)run.GetPositions()[i * 2 + 2] + left - offset_x - 1; + int top = (int)run.GetPositions()[i * 2 + 1] + y; /* Truncated away. */ if (truncation && (begin_x < min_x || end_x > max_x)) continue; @@ -512,9 +511,9 @@ int DrawString(int left, int right, int top, const char *str, TextColour colour, } Layouter layout(str, INT32_MAX, colour, fontsize); - if (layout.Length() == 0) return 0; + if (layout.size() == 0) return 0; - return DrawLayoutLine(*layout.Begin(), top, left, right, align, underline, true); + return DrawLayoutLine(*layout.front(), top, left, right, align, underline, true); } /** @@ -577,7 +576,7 @@ int GetStringLineCount(StringID str, int maxw) GetString(buffer, str, lastof(buffer)); Layouter layout(buffer, maxw); - return layout.Length(); + return (uint)layout.size(); } /** @@ -650,15 +649,14 @@ int DrawStringMultiLine(int left, int right, int top, int bottom, const char *st int last_line = top; int first_line = bottom; - for (const ParagraphLayouter::Line **iter = layout.Begin(); iter != layout.End(); iter++) { - const ParagraphLayouter::Line *line = *iter; + for (const auto &line : layout) { int line_height = line->GetLeading(); if (y >= top && y < bottom) { last_line = y + line_height; if (first_line > y) first_line = y; - DrawLayoutLine(line, y, left, right, align, underline, false); + DrawLayoutLine(*line, y, left, right, align, underline, false); } y += line_height; } @@ -737,11 +735,11 @@ Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsiz * @param str String to test. * @param x Position relative to the start of the string. * @param start_fontsize Font size to start the text with. - * @return Pointer to the character at the position or NULL if there is no character at the position. + * @return Pointer to the character at the position or nullptr if there is no character at the position. */ const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize) { - if (x < 0) return NULL; + if (x < 0) return nullptr; Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); return layout.GetCharAtPosition(x); @@ -771,7 +769,7 @@ Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom) { const Sprite *sprite = GetSprite(sprid, ST_NORMAL); - if (offset != NULL) { + if (offset != nullptr) { offset->x = UnScaleByZoom(sprite->x_offs, zoom); offset->y = UnScaleByZoom(sprite->y_offs, zoom); } @@ -877,7 +875,7 @@ static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mo x += sprite->x_offs; y += sprite->y_offs; - if (sub == NULL) { + if (sub == nullptr) { /* No clipping. */ bp.skip_left = 0; bp.skip_top = 0; @@ -971,7 +969,7 @@ static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mo if (topleft <= clicked && clicked <= bottomright) { uint offset = (((size_t)clicked - (size_t)topleft) / (blitter->GetScreenDepth() / 8)) % bp.pitch; if (offset < (uint)bp.width) { - _newgrf_debug_sprite_picker.sprites.Include(sprite_id); + include(_newgrf_debug_sprite_picker.sprites, sprite_id); } } } @@ -1014,7 +1012,7 @@ void DoPaletteAnimations() uint i; uint j; - if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { + if (blitter != nullptr && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { palette_animation_counter = 0; } @@ -1099,7 +1097,7 @@ void DoPaletteAnimations() if (j >= EPV_CYCLES_GLITTER_WATER) j -= EPV_CYCLES_GLITTER_WATER; } - if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { + if (blitter != nullptr && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { palette_animation_counter = old_tc; } else { if (memcmp(old_val, &_cur_palette.palette[PALETTE_ANIM_START], sizeof(old_val)) != 0 && _cur_palette.count_dirty == 0) { @@ -1206,7 +1204,7 @@ void ScreenSizeChanged() void UndrawMouseCursor() { /* Don't undraw the mouse cursor if the screen is not ready */ - if (_screen.dst_ptr == NULL) return; + if (_screen.dst_ptr == nullptr) return; if (_cursor.visible) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); @@ -1219,7 +1217,7 @@ void UndrawMouseCursor() void DrawMouseCursor() { /* Don't draw the mouse cursor if the screen is not ready */ - if (_screen.dst_ptr == NULL) return; + if (_screen.dst_ptr == nullptr) return; Blitter *blitter = BlitterFactory::GetCurrentBlitter(); @@ -1289,9 +1287,7 @@ void RedrawScreenRect(int left, int top, int right, int bottom) } } -#ifdef ENABLE_NETWORK if (_networking) NetworkUndrawChatMessage(); -#endif /* ENABLE_NETWORK */ DrawOverlappedWindowForAll(left, top, right, bottom); @@ -1314,8 +1310,8 @@ void DrawDirtyBlocks() if (HasModalProgress()) { /* We are generating the world, so release our rights to the map and * painting while we are waiting a bit. */ - _modal_progress_paint_mutex->EndCritical(); - _modal_progress_work_mutex->EndCritical(); + _modal_progress_paint_mutex.unlock(); + _modal_progress_work_mutex.unlock(); /* Wait a while and update _realtime_tick so we are given the rights */ if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT); @@ -1323,9 +1319,9 @@ void DrawDirtyBlocks() /* Modal progress thread may need blitter access while we are waiting for it. */ VideoDriver::GetInstance()->ReleaseBlitterLock(); - _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_paint_mutex.lock(); VideoDriver::GetInstance()->AcquireBlitterLock(); - _modal_progress_work_mutex->BeginCritical(); + _modal_progress_work_mutex.lock(); /* When we ended with the modal progress, do not draw the blocks. * Simply let the next run do so, otherwise we would be loading @@ -1583,7 +1579,7 @@ static void SwitchAnimatedCursor() { const AnimCursor *cur = _cursor.animate_cur; - if (cur == NULL || cur->sprite == AnimCursor::LAST) cur = _cursor.animate_list; + if (cur == nullptr || cur->sprite == AnimCursor::LAST) cur = _cursor.animate_list; SetCursorSprite(cur->sprite, _cursor.sprite_seq[0].pal); @@ -1633,7 +1629,7 @@ void SetMouseCursor(CursorID sprite, PaletteID pal) void SetAnimatedMouseCursor(const AnimCursor *table) { _cursor.animate_list = table; - _cursor.animate_cur = NULL; + _cursor.animate_cur = nullptr; _cursor.sprite_seq[0].pal = PAL_NONE; SwitchAnimatedCursor(); } @@ -1674,7 +1670,7 @@ bool CursorVars::UpdateCursorPosition(int x, int y, bool queued_warp) if (this->delta.x != 0 || this->delta.y != 0) { /* Trigger warp. * Note: We also trigger warping again, if there is already a pending warp. - * This makes it more tolerant about the OS or other software inbetween + * This makes it more tolerant about the OS or other software in between * botchering the warp. */ this->queued_warp = queued_warp; need_warp = true; @@ -1696,20 +1692,13 @@ bool ChangeResInGame(int width, int height) bool ToggleFullScreen(bool fs) { bool result = VideoDriver::GetInstance()->ToggleFullscreen(fs); - if (_fullscreen != fs && _num_resolutions == 0) { + if (_fullscreen != fs && _resolutions.empty()) { DEBUG(driver, 0, "Could not find a suitable fullscreen resolution"); } return result; } -static int CDECL compare_res(const Dimension *pa, const Dimension *pb) +void SortResolutions() { - int x = pa->width - pb->width; - if (x != 0) return x; - return pa->height - pb->height; -} - -void SortResolutions(int count) -{ - QSortT(_resolutions, count, &compare_res); + std::sort(_resolutions.begin(), _resolutions.end()); } diff --git a/src/gfx_func.h b/src/gfx_func.h index 94a1aede57..83d4d45550 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -31,7 +31,7 @@ * VideoDriver::MakeDirty and it is truncated back to an empty rectangle. At some * later point (which is uninteresting, too) the video driver * repaints all these saved rectangle instead of the whole screen and drop the - * rectangle informations. Then a new round begins by marking objects "dirty". + * rectangle information. Then a new round begins by marking objects "dirty". * * @see VideoDriver::MakeDirty * @see _invalid_rect @@ -67,16 +67,14 @@ extern bool _right_button_clicked; extern DrawPixelInfo _screen; extern bool _screen_disable_anim; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) -extern int _num_resolutions; -extern Dimension _resolutions[32]; +extern std::vector _resolutions; extern Dimension _cur_resolution; extern Palette _cur_palette; ///< Current palette void HandleKeypress(uint keycode, WChar key); -void HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL); +void HandleTextInput(const char *str, bool marked = false, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr); void HandleCtrlChanged(); void HandleMouseEvents(); -void CSleep(int milliseconds); void UpdateWindows(); void DrawMouseCursor(); @@ -90,9 +88,9 @@ static const int DRAW_STRING_BUFFER = 2048; void RedrawScreenRect(int left, int top, int right, int bottom); void GfxScroll(int left, int top, int width, int height, int xo, int yo); -Dimension GetSpriteSize(SpriteID sprid, Point *offset = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); -void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL); -void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); +Dimension GetSpriteSize(SpriteID sprid, Point *offset = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI); +void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr); +void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI); /** How to align the to-be drawn text. */ enum StringAlignment { @@ -164,7 +162,7 @@ void SetAnimatedMouseCursor(const AnimCursor *table); void CursorTick(); void UpdateCursorSize(); bool ChangeResInGame(int w, int h); -void SortResolutions(int count); +void SortResolutions(); bool ToggleFullScreen(bool fs); /* gfx.cpp */ diff --git a/src/gfx_layout.cpp b/src/gfx_layout.cpp index 62e4831091..502eccbbc3 100644 --- a/src/gfx_layout.cpp +++ b/src/gfx_layout.cpp @@ -17,9 +17,9 @@ #include "table/control_codes.h" -#ifdef WITH_ICU_LAYOUT +#ifdef WITH_ICU_LX #include -#endif /* WITH_ICU_LAYOUT */ +#endif /* WITH_ICU_LX */ #ifdef WITH_UNISCRIBE #include "os/windows/string_uniscribe.h" @@ -50,7 +50,7 @@ Font::Font(FontSize size, TextColour colour) : assert(size < FS_END); } -#ifdef WITH_ICU_LAYOUT +#ifdef WITH_ICU_LX /* Implementation details of LEFontInstance */ le_int32 Font::getUnitsPerEM() const @@ -124,7 +124,7 @@ le_bool Font::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &poin /** * Wrapper for doing layouts with ICU. */ -class ICUParagraphLayout : public AutoDeleteSmallVector, public ParagraphLayouter { +class ICUParagraphLayout : public ParagraphLayouter { icu::ParagraphLayout *p; ///< The actual ICU paragraph layout. public: /** Visual run contains data about the bit of text with the same font. */ @@ -134,33 +134,33 @@ public: public: ICUVisualRun(const icu::ParagraphLayout::VisualRun *vr) : vr(vr) { } - const Font *GetFont() const { return (const Font*)vr->getFont(); } - int GetGlyphCount() const { return vr->getGlyphCount(); } - const GlyphID *GetGlyphs() const { return vr->getGlyphs(); } - const float *GetPositions() const { return vr->getPositions(); } - int GetLeading() const { return vr->getLeading(); } - const int *GetGlyphToCharMap() const { return vr->getGlyphToCharMap(); } + const Font *GetFont() const override { return (const Font*)vr->getFont(); } + int GetGlyphCount() const override { return vr->getGlyphCount(); } + const GlyphID *GetGlyphs() const override { return vr->getGlyphs(); } + const float *GetPositions() const override { return vr->getPositions(); } + int GetLeading() const override { return vr->getLeading(); } + const int *GetGlyphToCharMap() const override { return vr->getGlyphToCharMap(); } }; /** A single line worth of VisualRuns. */ - class ICULine : public AutoDeleteSmallVector, public ParagraphLayouter::Line { + class ICULine : public std::vector, public ParagraphLayouter::Line { icu::ParagraphLayout::Line *l; ///< The actual ICU line. public: ICULine(icu::ParagraphLayout::Line *l) : l(l) { for (int i = 0; i < l->countRuns(); i++) { - *this->Append() = new ICUVisualRun(l->getVisualRun(i)); + this->emplace_back(l->getVisualRun(i)); } } - ~ICULine() { delete l; } + ~ICULine() override { delete l; } - int GetLeading() const { return l->getLeading(); } - int GetWidth() const { return l->getWidth(); } - int CountRuns() const { return l->countRuns(); } - const ParagraphLayouter::VisualRun *GetVisualRun(int run) const { return *this->Get(run); } + int GetLeading() const override { return l->getLeading(); } + int GetWidth() const override { return l->getWidth(); } + int CountRuns() const override { return l->countRuns(); } + const ParagraphLayouter::VisualRun &GetVisualRun(int run) const override { return this->at(run); } - int GetInternalCharLength(WChar c) const + int GetInternalCharLength(WChar c) const override { /* ICU uses UTF-16 internally which means we need to account for surrogate pairs. */ return Utf8CharLen(c) < 4 ? 1 : 2; @@ -168,13 +168,13 @@ public: }; ICUParagraphLayout(icu::ParagraphLayout *p) : p(p) { } - ~ICUParagraphLayout() { delete p; } - void Reflow() { p->reflow(); } + ~ICUParagraphLayout() override { delete p; } + void Reflow() override { p->reflow(); } - ParagraphLayouter::Line *NextLine(int max_width) + std::unique_ptr NextLine(int max_width) override { icu::ParagraphLayout::Line *l = p->nextLine(max_width); - return l == NULL ? NULL : new ICULine(l); + return std::unique_ptr(l == nullptr ? nullptr : new ICULine(l)); } }; @@ -196,22 +196,22 @@ public: /* ICU's ParagraphLayout cannot handle empty strings, so fake one. */ buff[0] = ' '; length = 1; - fontMapping.End()[-1].first++; + fontMapping.back().first++; } /* Fill ICU's FontRuns with the right data. */ - icu::FontRuns runs(fontMapping.Length()); - for (FontMap::iterator iter = fontMapping.Begin(); iter != fontMapping.End(); iter++) { - runs.add(iter->second, iter->first); + icu::FontRuns runs(fontMapping.size()); + for (auto &pair : fontMapping) { + runs.add(pair.second, pair.first); } LEErrorCode status = LE_NO_ERROR; /* ParagraphLayout does not copy "buff", so it must stay valid. * "runs" is copied according to the ICU source, but the documentation does not specify anything, so this might break somewhen. */ - icu::ParagraphLayout *p = new icu::ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? 1 : 0, false, status); + icu::ParagraphLayout *p = new icu::ParagraphLayout(buff, length, &runs, nullptr, nullptr, nullptr, _current_text_dir == TD_RTL ? 1 : 0, false, status); if (status != LE_NO_ERROR) { delete p; - return NULL; + return nullptr; } return new ICUParagraphLayout(p); @@ -226,7 +226,7 @@ public: return length; } }; -#endif /* WITH_ICU_LAYOUT */ +#endif /* WITH_ICU_LX */ /*** Paragraph layout ***/ /** @@ -234,7 +234,7 @@ public: * visual runs. * * One constructs this class with the text that needs to be split into - * lines. Then nextLine is called with the maximum width until NULL is + * lines. Then nextLine is called with the maximum width until nullptr is * returned. Each nextLine call creates VisualRuns which contain the * length of text that are to be drawn with the same font. In other * words, the result of this class is a list of sub strings with their @@ -259,24 +259,25 @@ public: public: FallbackVisualRun(Font *font, const WChar *chars, int glyph_count, int x); - ~FallbackVisualRun(); - const Font *GetFont() const; - int GetGlyphCount() const; - const GlyphID *GetGlyphs() const; - const float *GetPositions() const; - int GetLeading() const; - const int *GetGlyphToCharMap() const; + FallbackVisualRun(FallbackVisualRun &&other) noexcept; + ~FallbackVisualRun() override; + const Font *GetFont() const override; + int GetGlyphCount() const override; + const GlyphID *GetGlyphs() const override; + const float *GetPositions() const override; + int GetLeading() const override; + const int *GetGlyphToCharMap() const override; }; /** A single line worth of VisualRuns. */ - class FallbackLine : public AutoDeleteSmallVector, public ParagraphLayouter::Line { + class FallbackLine : public std::vector, public ParagraphLayouter::Line { public: - int GetLeading() const; - int GetWidth() const; - int CountRuns() const; - const ParagraphLayouter::VisualRun *GetVisualRun(int run) const; + int GetLeading() const override; + int GetWidth() const override; + int CountRuns() const override; + const ParagraphLayouter::VisualRun &GetVisualRun(int run) const override; - int GetInternalCharLength(WChar c) const { return 1; } + int GetInternalCharLength(WChar c) const override { return 1; } }; const WChar *buffer_begin; ///< Begin of the buffer. @@ -284,8 +285,8 @@ public: FontMap &runs; ///< The fonts we have to use for this paragraph. FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs); - void Reflow(); - const ParagraphLayouter::Line *NextLine(int max_width); + void Reflow() override; + std::unique_ptr NextLine(int max_width) override; }; /** @@ -350,6 +351,18 @@ FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const } } +/** Move constructor for visual runs.*/ +FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(FallbackVisualRun &&other) noexcept : font(other.font), glyph_count(other.glyph_count) +{ + this->positions = other.positions; + this->glyph_to_char = other.glyph_to_char; + this->glyphs = other.glyphs; + + other.positions = nullptr; + other.glyph_to_char = nullptr; + other.glyphs = nullptr; +} + /** Free all data. */ FallbackParagraphLayout::FallbackVisualRun::~FallbackVisualRun() { @@ -419,8 +432,8 @@ int FallbackParagraphLayout::FallbackVisualRun::GetLeading() const int FallbackParagraphLayout::FallbackLine::GetLeading() const { int leading = 0; - for (const FallbackVisualRun * const *run = this->Begin(); run != this->End(); run++) { - leading = max(leading, (*run)->GetLeading()); + for (const auto &run : *this) { + leading = max(leading, run.GetLeading()); } return leading; @@ -432,15 +445,15 @@ int FallbackParagraphLayout::FallbackLine::GetLeading() const */ int FallbackParagraphLayout::FallbackLine::GetWidth() const { - if (this->Length() == 0) return 0; + if (this->size() == 0) return 0; /* * The last X position of a run contains is the end of that run. * Since there is no left-to-right support, taking this value of * the last run gives us the end of the line and thus the width. */ - const ParagraphLayouter::VisualRun *run = this->GetVisualRun(this->CountRuns() - 1); - return (int)run->GetPositions()[run->GetGlyphCount() * 2]; + const auto &run = this->GetVisualRun(this->CountRuns() - 1); + return (int)run.GetPositions()[run.GetGlyphCount() * 2]; } /** @@ -449,16 +462,16 @@ int FallbackParagraphLayout::FallbackLine::GetWidth() const */ int FallbackParagraphLayout::FallbackLine::CountRuns() const { - return this->Length(); + return (uint)this->size(); } /** * Get a specific visual run. * @return The visual run. */ -const ParagraphLayouter::VisualRun *FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const +const ParagraphLayouter::VisualRun &FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const { - return *this->Get(run); + return this->at(run); } /** @@ -483,27 +496,27 @@ void FallbackParagraphLayout::Reflow() /** * Construct a new line with a maximum width. * @param max_width The maximum width of the string. - * @return A Line, or NULL when at the end of the paragraph. + * @return A Line, or nullptr when at the end of the paragraph. */ -const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) +std::unique_ptr FallbackParagraphLayout::NextLine(int max_width) { /* Simple idea: * - split a line at a newline character, or at a space where we can break a line. * - split for a visual run whenever a new line happens, or the font changes. */ - if (this->buffer == NULL) return NULL; + if (this->buffer == nullptr) return nullptr; - FallbackLine *l = new FallbackLine(); + std::unique_ptr l(new FallbackLine()); if (*this->buffer == '\0') { /* Only a newline. */ - this->buffer = NULL; - *l->Append() = new FallbackVisualRun(this->runs.Begin()->second, this->buffer, 0, 0); + this->buffer = nullptr; + l->emplace_back(this->runs.front().second, this->buffer, 0, 0); return l; } int offset = this->buffer - this->buffer_begin; - FontMap::iterator iter = this->runs.Begin(); + FontMap::iterator iter = this->runs.data(); while (iter->first <= offset) { iter++; assert(iter != this->runs.End()); @@ -513,7 +526,7 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) const WChar *next_run = this->buffer_begin + iter->first; const WChar *begin = this->buffer; - const WChar *last_space = NULL; + const WChar *last_space = nullptr; const WChar *last_char; int width = 0; for (;;) { @@ -521,20 +534,20 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) last_char = this->buffer; if (c == '\0') { - this->buffer = NULL; + this->buffer = nullptr; break; } if (this->buffer == next_run) { int w = l->GetWidth(); - *l->Append() = new FallbackVisualRun(iter->second, begin, this->buffer - begin, w); + l->emplace_back(iter->second, begin, this->buffer - begin, w); iter++; assert(iter != this->runs.End()); next_run = this->buffer_begin + iter->first; begin = this->buffer; - last_space = NULL; + last_space = nullptr; } if (IsWhitespace(c)) last_space = this->buffer; @@ -548,11 +561,11 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) if (width == char_width) { /* The character is wider than allowed width; don't know * what to do with this case... bail out! */ - this->buffer = NULL; + this->buffer = nullptr; return l; } - if (last_space == NULL) { + if (last_space == nullptr) { /* No space has been found. Just terminate at our current * location. This usually happens for languages that do not * require spaces in strings, like Chinese, Japanese and @@ -572,9 +585,9 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) this->buffer++; } - if (l->Length() == 0 || last_char - begin != 0) { + if (l->size() == 0 || last_char - begin != 0) { int w = l->GetWidth(); - *l->Append() = new FallbackVisualRun(iter->second, begin, last_char - begin, w); + l->emplace_back(iter->second, begin, last_char - begin, w); } return l; } @@ -582,7 +595,7 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) /** * Helper for getting a ParagraphLayouter of the given type. * - * @note In case no ParagraphLayouter could be constructed, line.layout will be NULL. + * @note In case no ParagraphLayouter could be constructed, line.layout will be nullptr. * @param line The cache item to store our layouter in. * @param str The string to create a layouter for. * @param state The state of the font and color. @@ -591,7 +604,7 @@ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) template static inline void GetLayouter(Layouter::LineCacheItem &line, const char *&str, FontState &state) { - if (line.buffer != NULL) free(line.buffer); + if (line.buffer != nullptr) free(line.buffer); typename T::CharType *buff_begin = MallocT(DRAW_STRING_BUFFER); const typename T::CharType *buffer_last = buff_begin + DRAW_STRING_BUFFER; @@ -600,7 +613,7 @@ static inline void GetLayouter(Layouter::LineCacheItem &line, const char *&str, Font *f = Layouter::GetFont(state.fontsize, state.cur_colour); line.buffer = buff_begin; - fontMapping.Clear(); + fontMapping.clear(); /* * Go through the whole string while adding Font instances to the font map @@ -666,7 +679,7 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi } LineCacheItem& line = GetCachedParagraphLayout(str, lineend - str, state); - if (line.layout != NULL) { + if (line.layout != nullptr) { /* Line is in cache */ str = lineend + 1; state = line.state_after; @@ -674,13 +687,13 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi } else { /* Line is new, layout it */ FontState old_state = state; -#if defined(WITH_ICU_LAYOUT) || defined(WITH_UNISCRIBE) || defined(WITH_COCOA) +#if defined(WITH_ICU_LX) || defined(WITH_UNISCRIBE) || defined(WITH_COCOA) const char *old_str = str; #endif -#ifdef WITH_ICU_LAYOUT +#ifdef WITH_ICU_LX GetLayouter(line, str, state); - if (line.layout == NULL) { + if (line.layout == nullptr) { static bool warned = false; if (!warned) { DEBUG(misc, 0, "ICU layouter bailed on the font. Falling back to the fallback layouter"); @@ -693,9 +706,9 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi #endif #ifdef WITH_UNISCRIBE - if (line.layout == NULL) { + if (line.layout == nullptr) { GetLayouter(line, str, state); - if (line.layout == NULL) { + if (line.layout == nullptr) { state = old_state; str = old_str; } @@ -703,26 +716,26 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi #endif #ifdef WITH_COCOA - if (line.layout == NULL) { + if (line.layout == nullptr) { GetLayouter(line, str, state); - if (line.layout == NULL) { + if (line.layout == nullptr) { state = old_state; str = old_str; } } #endif - if (line.layout == NULL) { + if (line.layout == nullptr) { GetLayouter(line, str, state); } } - /* Copy all lines into a local cache so we can reuse them later on more easily. */ - const ParagraphLayouter::Line *l; - while ((l = line.layout->NextLine(maxw)) != NULL) { - *this->Append() = l; + /* Move all lines into a local cache so we can reuse them later on more easily. */ + for (;;) { + auto l = line.layout->NextLine(maxw); + if (l == nullptr) break; + this->push_back(std::move(l)); } - } while (c != '\0'); } @@ -733,9 +746,9 @@ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsi Dimension Layouter::GetBounds() { Dimension d = { 0, 0 }; - for (const ParagraphLayouter::Line **l = this->Begin(); l != this->End(); l++) { - d.width = max(d.width, (*l)->GetWidth()); - d.height += (*l)->GetLeading(); + for (const auto &l : *this) { + d.width = max(d.width, l->GetWidth()); + d.height += l->GetLeading(); } return d; } @@ -757,12 +770,12 @@ Point Layouter::GetCharPosition(const char *ch) const size_t len = Utf8Decode(&c, str); if (c == '\0' || c == '\n') break; str += len; - index += (*this->Begin())->GetInternalCharLength(c); + index += this->front()->GetInternalCharLength(c); } if (str == ch) { /* Valid character. */ - const ParagraphLayouter::Line *line = *this->Begin(); + const auto &line = this->front(); /* Pointer to the end-of-string/line marker? Return total line width. */ if (*ch == '\0' || *ch == '\n') { @@ -772,12 +785,12 @@ Point Layouter::GetCharPosition(const char *ch) const /* Scan all runs until we've found our code point index. */ for (int run_index = 0; run_index < line->CountRuns(); run_index++) { - const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); + const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index); - for (int i = 0; i < run->GetGlyphCount(); i++) { + for (int i = 0; i < run.GetGlyphCount(); i++) { /* Matching glyph? Return position. */ - if ((size_t)run->GetGlyphToCharMap()[i] == index) { - Point p = { (int)run->GetPositions()[i * 2], (int)run->GetPositions()[i * 2 + 1] }; + if ((size_t)run.GetGlyphToCharMap()[i] == index) { + Point p = { (int)run.GetPositions()[i * 2], (int)run.GetPositions()[i * 2 + 1] }; return p; } } @@ -791,25 +804,25 @@ Point Layouter::GetCharPosition(const char *ch) const /** * Get the character that is at a position. * @param x Position in the string. - * @return Pointer to the character at the position or NULL if no character is at the position. + * @return Pointer to the character at the position or nullptr if no character is at the position. */ const char *Layouter::GetCharAtPosition(int x) const { - const ParagraphLayouter::Line *line = *this->Begin(); + const auto &line = this->front(); for (int run_index = 0; run_index < line->CountRuns(); run_index++) { - const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); + const ParagraphLayouter::VisualRun &run = line->GetVisualRun(run_index); - for (int i = 0; i < run->GetGlyphCount(); i++) { + for (int i = 0; i < run.GetGlyphCount(); i++) { /* Not a valid glyph (empty). */ - if (run->GetGlyphs()[i] == 0xFFFF) continue; + if (run.GetGlyphs()[i] == 0xFFFF) continue; - int begin_x = (int)run->GetPositions()[i * 2]; - int end_x = (int)run->GetPositions()[i * 2 + 2]; + int begin_x = (int)run.GetPositions()[i * 2]; + int end_x = (int)run.GetPositions()[i * 2 + 2]; if (IsInsideMM(x, begin_x, end_x)) { /* Found our glyph, now convert to UTF-8 string index. */ - size_t index = run->GetGlyphToCharMap()[i]; + size_t index = run.GetGlyphToCharMap()[i]; size_t cur_idx = 0; for (const char *str = this->string; *str != '\0'; ) { @@ -822,7 +835,7 @@ const char *Layouter::GetCharAtPosition(int x) const } } - return NULL; + return nullptr; } /** @@ -834,7 +847,7 @@ Font *Layouter::GetFont(FontSize size, TextColour colour) if (it != fonts[size].End()) return it->second; Font *f = new Font(size, colour); - *fonts[size].Append() = FontColourMap::Pair(colour, f); + fonts[size].emplace_back(colour, f); return f; } @@ -844,10 +857,10 @@ Font *Layouter::GetFont(FontSize size, TextColour colour) */ void Layouter::ResetFontCache(FontSize size) { - for (FontColourMap::iterator it = fonts[size].Begin(); it != fonts[size].End(); ++it) { - delete it->second; + for (auto &pair : fonts[size]) { + delete pair.second; } - fonts[size].Clear(); + fonts[size].clear(); /* We must reset the linecache since it references the just freed fonts */ ResetLineCache(); @@ -870,7 +883,7 @@ void Layouter::ResetFontCache(FontSize size) */ Layouter::LineCacheItem &Layouter::GetCachedParagraphLayout(const char *str, size_t len, const FontState &state) { - if (linecache == NULL) { + if (linecache == nullptr) { /* Create linecache on first access to avoid trouble with initialisation order of static variables. */ linecache = new LineCache(); } @@ -886,7 +899,7 @@ Layouter::LineCacheItem &Layouter::GetCachedParagraphLayout(const char *str, siz */ void Layouter::ResetLineCache() { - if (linecache != NULL) linecache->clear(); + if (linecache != nullptr) linecache->clear(); } /** @@ -894,7 +907,7 @@ void Layouter::ResetLineCache() */ void Layouter::ReduceLineCache() { - if (linecache != NULL) { + if (linecache != nullptr) { /* TODO LRU cache would be fancy, but not exactly necessary */ if (linecache->size() > 4096) ResetLineCache(); } diff --git a/src/gfx_layout.h b/src/gfx_layout.h index 94cbac073a..0539376473 100644 --- a/src/gfx_layout.h +++ b/src/gfx_layout.h @@ -21,12 +21,12 @@ #include #include -#ifdef WITH_ICU_LAYOUT +#ifdef WITH_ICU_LX #include "layout/ParagraphLayout.h" #define ICU_FONTINSTANCE : public icu::LEFontInstance -#else /* WITH_ICU_LAYOUT */ +#else /* WITH_ICU_LX */ #define ICU_FONTINSTANCE -#endif /* WITH_ICU_LAYOUT */ +#endif /* WITH_ICU_LX */ /** * Text drawing parameters, which can change while drawing a line, but are kept between multiple parts @@ -89,7 +89,7 @@ public: Font(FontSize size, TextColour colour); -#ifdef WITH_ICU_LAYOUT +#ifdef WITH_ICU_LX /* Implementation details of LEFontInstance */ le_int32 getUnitsPerEM() const; @@ -105,7 +105,7 @@ public: LEGlyphID mapCharToGlyph(LEUnicode32 ch) const; void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const; le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const; -#endif /* WITH_ICU_LAYOUT */ +#endif /* WITH_ICU_LX */ }; /** Mapping from index to font. */ @@ -137,12 +137,12 @@ public: virtual int GetLeading() const = 0; virtual int GetWidth() const = 0; virtual int CountRuns() const = 0; - virtual const VisualRun *GetVisualRun(int run) const = 0; + virtual const VisualRun &GetVisualRun(int run) const = 0; virtual int GetInternalCharLength(WChar c) const = 0; }; virtual void Reflow() = 0; - virtual const Line *NextLine(int max_width) = 0; + virtual std::unique_ptr NextLine(int max_width) = 0; }; /** @@ -150,7 +150,7 @@ public: * * It also accounts for the memory allocations and frees. */ -class Layouter : public AutoDeleteSmallVector { +class Layouter : public std::vector> { const char *string; ///< Pointer to the original string. /** Key into the linecache */ @@ -177,7 +177,7 @@ public: FontState state_after; ///< Font state after the line. ParagraphLayouter *layout; ///< Layout of the line. - LineCacheItem() : buffer(NULL), layout(NULL) {} + LineCacheItem() : buffer(nullptr), layout(nullptr) {} ~LineCacheItem() { delete layout; free(buffer); } }; private: diff --git a/src/gfx_type.h b/src/gfx_type.h index e84684ac07..0fbce6134c 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -304,7 +304,7 @@ enum PaletteType { }; /** Types of sprites that might be loaded */ -enum SpriteType { +enum SpriteType : byte { ST_NORMAL = 0, ///< The most basic (normal) sprite ST_MAPGEN = 1, ///< Special sprite for the map generator ST_FONT = 2, ///< A sprite used for fonts diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index bd0f17a91b..677a442993 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -120,7 +120,7 @@ static void LoadGrfFileIndexed(const char *filename, const SpriteID *index_tbl, */ void CheckExternalFiles() { - if (BaseGraphics::GetUsedSet() == NULL || BaseSounds::GetUsedSet() == NULL) return; + if (BaseGraphics::GetUsedSet() == nullptr || BaseSounds::GetUsedSet() == nullptr) return; const GraphicsSet *used_set = BaseGraphics::GetUsedSet(); @@ -266,7 +266,7 @@ static bool SwitchNewGRFBlitter() */ uint depth_wanted_by_base = BaseGraphics::GetUsedSet()->blitter == BLT_32BPP ? 32 : 8; uint depth_wanted_by_grf = _support8bpp == S8BPP_NONE ? 32 : 8; - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND || HasBit(c->flags, GCF_INIT_ONLY)) continue; if (c->palette & GRFP_BLT_32BPP) depth_wanted_by_grf = 32; } @@ -308,18 +308,18 @@ static bool SwitchNewGRFBlitter() VideoDriver::GetInstance()->ReleaseBlitterLock(); return false; } - if (BlitterFactory::GetBlitterFactory(repl_blitter) == NULL) continue; + if (BlitterFactory::GetBlitterFactory(repl_blitter) == nullptr) continue; DEBUG(misc, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter); Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter); - if (new_blitter == NULL) NOT_REACHED(); + if (new_blitter == nullptr) NOT_REACHED(); DEBUG(misc, 1, "Successfully switched to %s.", repl_blitter); break; } if (!VideoDriver::GetInstance()->AfterBlitterChange()) { /* Failed to switch blitter, let's hope we can return to the old one. */ - if (BlitterFactory::SelectBlitter(cur_blitter) == NULL || !VideoDriver::GetInstance()->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config"); + if (BlitterFactory::SelectBlitter(cur_blitter) == nullptr || !VideoDriver::GetInstance()->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config"); } VideoDriver::GetInstance()->ReleaseBlitterLock(); @@ -363,7 +363,7 @@ bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *ful /* Get optional blitter information. */ item = metadata->GetItem("blitter", false); - this->blitter = (item != NULL && *item->value == '3') ? BLT_32BPP : BLT_8BPP; + this->blitter = (item != nullptr && *item->value == '3') ? BLT_32BPP : BLT_8BPP; } return ret; } @@ -381,7 +381,7 @@ bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *ful { size_t size = 0; FILE *f = FioFOpenFile(file->filename, "rb", subdir, &size); - if (f == NULL) return MD5File::CR_NO_FILE; + if (f == nullptr) return MD5File::CR_NO_FILE; size_t max = GRFGetSizeOfDataSection(f); @@ -405,7 +405,7 @@ MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir, size_t max_size) size_t size; FILE *f = FioFOpenFile(this->filename, "rb", subdir, &size); - if (f == NULL) return CR_NO_FILE; + if (f == nullptr) return CR_NO_FILE; size = min(size, max_size); @@ -435,14 +435,14 @@ template template /* static */ bool BaseMedia::DetermineBestSet() { - if (BaseMedia::used_set != NULL) return true; + if (BaseMedia::used_set != nullptr) return true; - const Tbase_set *best = NULL; - for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { + const Tbase_set *best = nullptr; + for (const Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { /* Skip unusable sets */ if (c->GetNumMissing() != 0) continue; - if (best == NULL || + if (best == nullptr || (best->fallback && !c->fallback) || best->valid_files < c->valid_files || (best->valid_files == c->valid_files && ( @@ -453,7 +453,7 @@ template } BaseMedia::used_set = best; - return BaseMedia::used_set != NULL; + return BaseMedia::used_set != nullptr; } template diff --git a/src/goal.cpp b/src/goal.cpp index 16d826222c..407b3a398b 100644 --- a/src/goal.cpp +++ b/src/goal.cpp @@ -79,7 +79,7 @@ CommandCost CmdCreateGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 case GT_STORY_PAGE: { if (!StoryPage::IsValidID(p2)) return CMD_ERROR; - CompanyByte story_company = StoryPage::Get(p2)->company; + CompanyID story_company = StoryPage::Get(p2)->company; if (company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != company) return CMD_ERROR; break; } @@ -93,7 +93,7 @@ CommandCost CmdCreateGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 g->dst = p2; g->company = company; g->text = stredup(text); - g->progress = NULL; + g->progress = nullptr; g->completed = false; if (g->company == INVALID_COMPANY) { @@ -187,7 +187,7 @@ CommandCost CmdSetGoalProgress(TileIndex tile, DoCommandFlag flags, uint32 p1, u Goal *g = Goal::Get(p1); free(g->progress); if (StrEmpty(text)) { - g->progress = NULL; + g->progress = nullptr; } else { g->progress = stredup(text); } @@ -248,9 +248,7 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint { uint16 uniqueid = (GoalType)GB(p1, 0, 16); CompanyID company = (CompanyID)GB(p1, 16, 8); -#ifdef ENABLE_NETWORK ClientID client = (ClientID)GB(p1, 16, 16); -#endif assert_compile(GOAL_QUESTION_BUTTON_COUNT < 29); uint32 button_mask = GB(p2, 0, GOAL_QUESTION_BUTTON_COUNT); @@ -260,11 +258,7 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint if (_current_company != OWNER_DEITY) return CMD_ERROR; if (StrEmpty(text)) return CMD_ERROR; if (is_client) { -#ifdef ENABLE_NETWORK if (NetworkClientInfo::GetByClientID(client) == nullptr) return CMD_ERROR; -#else - return CMD_ERROR; -#endif } else { if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; } @@ -273,9 +267,7 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint if (flags & DC_EXEC) { if (is_client) { -#ifdef ENABLE_NETWORK if (client != _network_own_client_id) return CommandCost(); -#endif } else { if (company == INVALID_COMPANY && !Company::IsValidID(_local_company)) return CommandCost(); if (company != INVALID_COMPANY && company != _local_company) return CommandCost(); diff --git a/src/goal_base.h b/src/goal_base.h index 7453196c8e..fee4ddce7b 100644 --- a/src/goal_base.h +++ b/src/goal_base.h @@ -21,12 +21,12 @@ extern GoalPool _goal_pool; /** Struct about goals, current and completed */ struct Goal : GoalPool::PoolItem<&_goal_pool> { - CompanyByte company; ///< Goal is for a specific company; INVALID_COMPANY if it is global - GoalTypeByte type; ///< Type of the goal - GoalTypeID dst; ///< Index of type - char *text; ///< Text of the goal. - char *progress; ///< Progress text of the goal. - bool completed; ///< Is the goal completed or not? + CompanyID company; ///< Goal is for a specific company; INVALID_COMPANY if it is global + GoalType type; ///< Type of the goal + GoalTypeID dst; ///< Index of type + char *text; ///< Text of the goal. + char *progress; ///< Progress text of the goal. + bool completed; ///< Is the goal completed or not? /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) @@ -34,7 +34,7 @@ struct Goal : GoalPool::PoolItem<&_goal_pool> { inline Goal() { } /** - * (Empty) destructor has to be defined else operator delete might be called with NULL parameter + * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter */ inline ~Goal() { free(this->text); free(this->progress); } }; diff --git a/src/goal_gui.cpp b/src/goal_gui.cpp index 93a2795ba6..0dc8a4095d 100644 --- a/src/goal_gui.cpp +++ b/src/goal_gui.cpp @@ -50,7 +50,7 @@ struct GoalListWindow : public Window { this->OnInvalidateData(0); } - /* virtual */ void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget != WID_GOAL_CAPTION) return; @@ -62,7 +62,7 @@ struct GoalListWindow : public Window { } } - /* virtual */ void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget != WID_GOAL_LIST) return; @@ -177,7 +177,7 @@ struct GoalListWindow : public Window { return 3 + num_global + num_company; } - /* virtual */ void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_GOAL_LIST) return; Dimension d = maxdim(GetStringBoundingBox(STR_GOALS_GLOBAL_TITLE), GetStringBoundingBox(STR_GOALS_COMPANY_TITLE)); @@ -231,7 +231,7 @@ struct GoalListWindow : public Window { } case GC_PROGRESS: - if (s->progress != NULL) { + if (s->progress != nullptr) { SetDParamStr(0, s->progress); StringID str = s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS; int progress_x = x; @@ -280,7 +280,7 @@ struct GoalListWindow : public Window { DrawPartialGoalList(pos, cap, x, y, right, progress_col_width, false, column); } - /* virtual */ void OnPaint() + void OnPaint() override { this->DrawWidgets(); @@ -290,7 +290,7 @@ struct GoalListWindow : public Window { uint max_width = 0; Goal *s; FOR_ALL_GOALS(s) { - if (s->progress != NULL) { + if (s->progress != nullptr) { SetDParamStr(0, s->progress); StringID str = s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS; uint str_width = GetStringBoundingBox(str).width; @@ -307,7 +307,7 @@ struct GoalListWindow : public Window { } - /* virtual */ void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_GOAL_LIST); } @@ -317,7 +317,7 @@ struct GoalListWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->vscroll->SetCount(this->CountLines()); @@ -396,7 +396,7 @@ struct GoalQuestionWindow : public Window { free(this->question); } - /* virtual */ void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_GQ_CAPTION: @@ -417,7 +417,7 @@ struct GoalQuestionWindow : public Window { } } - /* virtual */ void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_GQ_BUTTON_1: @@ -437,7 +437,7 @@ struct GoalQuestionWindow : public Window { } } - /* virtual */ void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_GQ_QUESTION) return; @@ -445,7 +445,7 @@ struct GoalQuestionWindow : public Window { size->height = GetStringHeight(STR_JUST_RAW_STRING, size->width) + WD_PAR_VSEP_WIDE; } - /* virtual */ void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_GQ_QUESTION) return; @@ -481,7 +481,7 @@ static const NWidgetPart _nested_goal_question_widgets[] = { }; static WindowDesc _goal_question_list_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_GOAL_QUESTION, WC_NONE, WDF_CONSTRUCTION, _nested_goal_question_widgets, lengthof(_nested_goal_question_widgets) diff --git a/src/goal_type.h b/src/goal_type.h index aa9dee349d..4321a42b7a 100644 --- a/src/goal_type.h +++ b/src/goal_type.h @@ -18,7 +18,7 @@ static const uint32 GOAL_QUESTION_BUTTON_COUNT = 18; ///< Amount of buttons avai static const byte GOAL_QUESTION_TYPE_COUNT = 4; ///< Amount of question types. /** Types of goal destinations */ -enum GoalType { +enum GoalType : byte { GT_NONE, ///< Destination is not linked GT_TILE, ///< Destination is a tile GT_INDUSTRY, ///< Destination is an industry @@ -26,7 +26,6 @@ enum GoalType { GT_COMPANY, ///< Destination is a company GT_STORY_PAGE, ///< Destination is a story page }; -typedef SimpleTinyEnumT GoalTypeByte; ///< The GoalType packed into a byte for savegame purposes. typedef uint32 GoalTypeID; ///< Contains either tile, industry ID, town ID or company ID (or INVALID_GOALTYPE) static const GoalTypeID INVALID_GOALTYPE = 0xFFFFFFFF; ///< Invalid/unknown index of GoalType diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 665de8315c..b840322b6e 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -56,7 +56,7 @@ struct GraphLegendWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (!IsInsideMM(widget, WID_GL_FIRST_COMPANY, MAX_COMPANIES + WID_GL_FIRST_COMPANY)) return; @@ -74,7 +74,7 @@ struct GraphLegendWindow : Window { DrawString(r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : (d.width + 4)), r.right - (rtl ? (d.width + 4) : (uint)WD_FRAMERECT_RIGHT), r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2, STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, cid) ? TC_BLACK : TC_WHITE); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (!IsInsideMM(widget, WID_GL_FIRST_COMPANY, MAX_COMPANIES + WID_GL_FIRST_COMPANY)) return; @@ -93,7 +93,7 @@ struct GraphLegendWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (Company::IsValidID(data)) return; @@ -485,7 +485,7 @@ protected: } public: - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != this->graph_widget) return; @@ -521,7 +521,7 @@ public: size->height = max(size->height, size->width / 3); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != this->graph_widget) return; @@ -533,13 +533,13 @@ public: return INVALID_DATAPOINT; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { /* Clicked on legend? */ if (widget == WID_CV_KEY_BUTTON) ShowGraphLegend(); } - virtual void OnGameTick() + void OnGameTick() override { this->UpdateStatistics(false); } @@ -549,7 +549,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->UpdateStatistics(true); @@ -595,7 +595,7 @@ public: int numd = 0; for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) { c = Company::GetIfValid(k); - if (c != NULL) { + if (c != nullptr) { this->colours[numd] = _colour_gradient[c->colour][6]; for (int j = this->num_on_x_axis, i = 0; --j >= 0;) { this->cost[numd][i] = (j >= c->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(c, j); @@ -771,7 +771,7 @@ struct OperatingProfitGraphWindow : BaseGraphWindow { this->InitializeWindow(window_number); } - virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) + OverflowSafeInt64 GetGraphData(const Company *c, int j) override { return c->old_economy[j].income + c->old_economy[j].expenses; } @@ -826,7 +826,7 @@ struct IncomeGraphWindow : ExcludingCargoBaseGraphWindow { this->FinishInitNested(window_number); } - virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) + OverflowSafeInt64 GetGraphData(const Company *c, int j) override { if(_legend_excluded_cargo == 0){ return c->old_economy[j].income; @@ -903,7 +903,7 @@ struct DeliveredCargoGraphWindow : ExcludingCargoBaseGraphWindow { this->FinishInitNested(window_number); } - virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) + OverflowSafeInt64 GetGraphData(const Company *c, int j) override { if(_legend_excluded_cargo == 0){ return c->old_economy[j].delivered_cargo.GetSum(); @@ -976,12 +976,12 @@ struct PerformanceHistoryGraphWindow : BaseGraphWindow { this->InitializeWindow(window_number); } - virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) + OverflowSafeInt64 GetGraphData(const Company *c, int j) override { return c->old_economy[j].performance_history; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget == WID_PHG_DETAILED_PERFORMANCE) ShowPerformanceRatingDetail(); this->BaseGraphWindow::OnClick(pt, widget, click_count); @@ -1032,7 +1032,7 @@ struct CompanyValueGraphWindow : BaseGraphWindow { this->InitializeWindow(window_number); } - virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) + OverflowSafeInt64 GetGraphData(const Company *c, int j) override { return c->old_economy[j].company_value; } @@ -1094,12 +1094,12 @@ struct PaymentRatesGraphWindow : ExcludingCargoBaseGraphWindow { this->FinishInitNested(window_number); } - virtual void OnGameTick() + void OnGameTick() override { /* Override default OnGameTick */ } - virtual void OnHundredthTick() + void OnHundredthTick() override { this->UpdateExcludedData(); @@ -1113,7 +1113,8 @@ struct PaymentRatesGraphWindow : ExcludingCargoBaseGraphWindow { i++; } this->num_dataset = i; - }}; + } +}; static const NWidgetPart _nested_cargo_payment_rates_widgets[] = { NWidget(NWID_HORIZONTAL), @@ -1209,21 +1210,21 @@ private: { if (!this->companies.NeedRebuild()) return; - this->companies.Clear(); + this->companies.clear(); const Company *c; FOR_ALL_COMPANIES(c) { - *this->companies.Append() = c; + this->companies.push_back(c); } - this->companies.Compact(); + this->companies.shrink_to_fit(); this->companies.RebuildDone(); } /** Sort the company league by performance history */ - static int CDECL PerformanceSorter(const Company * const *c1, const Company * const *c2) + static bool PerformanceSorter(const Company * const &c1, const Company * const &c2) { - return (*c2)->old_economy[0].performance_history - (*c1)->old_economy[0].performance_history; + return c2->old_economy[0].performance_history < c1->old_economy[0].performance_history; } public: @@ -1234,7 +1235,7 @@ public: this->companies.NeedResort(); } - virtual void OnPaint() + void OnPaint() override { this->BuildCompanyList(); this->companies.Sort(&PerformanceSorter); @@ -1242,7 +1243,7 @@ public: this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_CL_BACKGROUND) return; @@ -1256,7 +1257,7 @@ public: uint text_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_LEFT - this->text_width; uint text_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->text_width : r.right - WD_FRAMERECT_LEFT; - for (uint i = 0; i != this->companies.Length(); i++) { + for (uint i = 0; i != this->companies.size(); i++) { const Company *c = this->companies[i]; DrawString(ordinal_left, ordinal_right, y, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW); @@ -1270,7 +1271,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_CL_BACKGROUND) return; @@ -1309,7 +1310,7 @@ public: } - virtual void OnGameTick() + void OnGameTick() override { if (this->companies.NeedResort()) { this->SetDirty(); @@ -1321,7 +1322,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ @@ -1391,7 +1392,7 @@ struct PerformanceRatingDetailWindow : Window { uint score_detail_left; uint score_detail_right; - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_PRD_SCORE_FIRST: @@ -1449,7 +1450,7 @@ struct PerformanceRatingDetailWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { /* No need to draw when there's nothing to draw */ if (this->company == INVALID_COMPANY) return; @@ -1528,7 +1529,7 @@ struct PerformanceRatingDetailWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { /* Check which button is clicked */ if (IsInsideMM(widget, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST + 1)) { @@ -1542,7 +1543,7 @@ struct PerformanceRatingDetailWindow : Window { } } - virtual void OnGameTick() + void OnGameTick() override { /* Update the company score every 5 days */ if (--this->timeout == 0) { @@ -1556,7 +1557,7 @@ struct PerformanceRatingDetailWindow : Window { * @param data the company ID of the company that is going to be removed * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* Disable the companies who are not active */ @@ -1656,4 +1657,3 @@ void InitializeGraphGui() _legend_excluded_companies = 0; _legend_excluded_cargo = 0; } - diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 6fd8d77106..a7869d9589 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -28,9 +28,9 @@ void GroundVehicle::PowerChanged() uint32 total_power = 0; uint32 max_te = 0; uint32 number_of_parts = 0; - uint16 max_track_speed = v->GetDisplayMaxSpeed(); + uint16 max_track_speed = this->vcache.cached_max_speed; // Max track speed in internal units. - for (const T *u = v; u != NULL; u = u->Next()) { + for (const T *u = v; u != nullptr; u = u->Next()) { uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u); total_power += current_power; @@ -83,7 +83,7 @@ void GroundVehicle::CargoChanged() assert(this->First() == this); uint32 weight = 0; - for (T *u = T::From(this); u != NULL; u = u->Next()) { + for (T *u = T::From(this); u != nullptr; u = u->Next()) { uint32 current_weight = u->GetWeight(); weight += current_weight; /* Slope steepness is in percent, result in N. */ @@ -116,7 +116,7 @@ int GroundVehicle::GetAcceleration() const /* Power is stored in HP, we need it in watts. * Each vehicle can have U16 power, 128 vehicles, HP -> watt - * and km/h to m/s conversion below result in a maxium of + * and km/h to m/s conversion below result in a maximum of * about 1.1E11, way more than 4.3E9 of int32. */ int64 power = this->gcache.cached_power * 746ll; @@ -198,7 +198,7 @@ bool GroundVehicle::IsChainInDepot() const if (!IsDepotTypeTile(v->tile, (TransportType)Type) || v->cur_speed != 0) return false; /* Check whether the rest is also already trying to enter the depot. */ - for (; v != NULL; v = v->Next()) { + for (; v != nullptr; v = v->Next()) { if (!v->T::IsInDepot() || v->tile != this->tile) return false; } diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp index 56b97875fc..5268651348 100644 --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -36,7 +36,7 @@ struct GroundVehicleCache { uint16 cached_axle_resistance; ///< Resistance caused by the axles of the vehicle (valid only for the first engine). /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */ - uint16 cached_max_track_speed; ///< Maximum consist speed limited by track type (valid only for the first engine). + uint16 cached_max_track_speed; ///< Maximum consist speed (in internal units) limited by track type (valid only for the first engine). uint32 cached_power; ///< Total power of the consist (valid only for the first engine). uint32 cached_air_drag; ///< Air drag coefficient of the vehicle (valid only for the first engine). @@ -92,17 +92,17 @@ struct GroundVehicle : public SpecializedVehicle { void PowerChanged(); void CargoChanged(); int GetAcceleration() const; - bool IsChainInDepot() const; + bool IsChainInDepot() const override; /** * Common code executed for crashed ground vehicles * @param flooded was this vehicle flooded? * @return number of victims */ - /* virtual */ uint Crash(bool flooded) + uint Crash(bool flooded) override { /* Crashed vehicles aren't going up or down */ - for (T *v = T::From(this); v != NULL; v = v->Next()) { + for (T *v = T::From(this); v != nullptr; v = v->Next()) { ClrBit(v->gv_flags, GVF_GOINGUP_BIT); ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT); } @@ -117,7 +117,7 @@ struct GroundVehicle : public SpecializedVehicle { { int64 incl = 0; - for (const T *u = T::From(this); u != NULL; u = u->Next()) { + for (const T *u = T::From(this); u != nullptr; u = u->Next()) { if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) { incl += u->gcache.cached_slope_resistance; } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) { diff --git a/src/group.h b/src/group.h index ea4f7e130e..57488d394b 100644 --- a/src/group.h +++ b/src/group.h @@ -65,15 +65,17 @@ struct GroupStatistics { /** Group data. */ struct Group : GroupPool::PoolItem<&_group_pool> { - char *name; ///< Group Name - OwnerByte owner; ///< Group Owner - VehicleTypeByte vehicle_type; ///< Vehicle type of the group + char *name; ///< Group Name + Owner owner; ///< Group Owner + VehicleType vehicle_type; ///< Vehicle type of the group - bool replace_protection; ///< If set to true, the global autoreplace have no effect on the group - Livery livery; ///< Custom colour scheme for vehicles in this group - GroupStatistics statistics; ///< NOSAVE: Statistics and caches on the vehicles in the group. + bool replace_protection; ///< If set to true, the global autoreplace have no effect on the group + Livery livery; ///< Custom colour scheme for vehicles in this group + GroupStatistics statistics; ///< NOSAVE: Statistics and caches on the vehicles in the group. - GroupID parent; ///< Parent group + bool folded; ///< NOSAVE: Is this group folded in the group view? + + GroupID parent; ///< Parent group Group(CompanyID owner = INVALID_COMPANY); ~Group(); @@ -100,6 +102,9 @@ static inline bool IsAllGroupID(GroupID id_g) uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e); +uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type); +uint GetGroupNumProfitVehicle(CompanyID company, GroupID id_g, VehicleType type); +Money GetGroupProfitLastYear(CompanyID company, GroupID id_g, VehicleType type); void SetTrainGroupID(Train *v, GroupID grp); void UpdateTrainGroupID(Train *v); diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index 39a945102c..a9451ee8f8 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -225,7 +225,7 @@ void GroupStatistics::Clear() g->statistics.ClearAutoreplace(); } - for (EngineRenewList erl = c->engine_renew_list; erl != NULL; erl = erl->next) { + for (EngineRenewList erl = c->engine_renew_list; erl != nullptr; erl = erl->next) { const Engine *e = Engine::Get(erl->from); GroupStatistics &stats = GroupStatistics::Get(company, erl->group_id, e->type); if (!stats.autoreplace_defined) { @@ -277,7 +277,7 @@ void PropagateChildLivery(const Group *g) Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->group_id == g->index && (!v->IsGroundVehicle() || v->IsFrontEngine())) { - for (Vehicle *u = v; u != NULL; u = u->Next()) { + for (Vehicle *u = v; u != nullptr; u = u->Next()) { u->colourmap = PAL_NONE; u->InvalidateNewGRFCache(); } @@ -298,6 +298,7 @@ void PropagateChildLivery(const Group *g) Group::Group(Owner owner) { this->owner = owner; + this->folded = false; } Group::~Group() @@ -323,7 +324,7 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (!Group::CanAllocateItem()) return CMD_ERROR; const Group *pg = Group::GetIfValid(GB(p2, 0, 16)); - if (pg != NULL) { + if (pg != nullptr) { if (pg->owner != _current_company) return CMD_ERROR; if (pg->vehicle_type != vt) return CMD_ERROR; } @@ -334,7 +335,7 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 g->vehicle_type = vt; g->parent = INVALID_GROUP; - if (pg == NULL) { + if (pg == nullptr) { const Company *c = Company::Get(_current_company); g->livery.colour1 = c->livery[LS_DEFAULT].colour1; g->livery.colour2 = c->livery[LS_DEFAULT].colour2; @@ -367,7 +368,7 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Group *g = Group::GetIfValid(p1); - if (g == NULL || g->owner != _current_company) return CMD_ERROR; + if (g == nullptr || g->owner != _current_company) return CMD_ERROR; /* Remove all vehicles from the group */ DoCommand(0, p1, 0, flags, CMD_REMOVE_ALL_VEHICLES_GROUP); @@ -423,7 +424,7 @@ CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Group *g = Group::GetIfValid(GB(p1, 0, 16)); - if (g == NULL || g->owner != _current_company) return CMD_ERROR; + if (g == nullptr || g->owner != _current_company) return CMD_ERROR; if (!HasBit(p1, 16)) { /* Rename group */ @@ -437,23 +438,23 @@ CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Delete the old name */ free(g->name); /* Assign the new one */ - g->name = reset ? NULL : stredup(text); + g->name = reset ? nullptr : stredup(text); } } else { /* Set group parent */ const Group *pg = Group::GetIfValid(GB(p2, 0, 16)); - if (pg != NULL) { + if (pg != nullptr) { if (pg->owner != _current_company) return CMD_ERROR; if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR; /* Ensure request parent isn't child of group. * This is the only place that infinite loops are prevented. */ - if (GroupIsInGroup(pg->index, g->index)) return CMD_ERROR; + if (GroupIsInGroup(pg->index, g->index)) return_cmd_error(STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION); } if (flags & DC_EXEC) { - g->parent = (pg == NULL) ? INVALID_GROUP : pg->index; + g->parent = (pg == nullptr) ? INVALID_GROUP : pg->index; GroupStatistics::UpdateAutoreplace(g->owner); if (g->livery.in_use == 0) { @@ -497,7 +498,7 @@ static void AddVehicleToGroup(Vehicle *v, GroupID new_g) case VEH_AIRCRAFT: if (v->IsEngineCountable()) UpdateNumEngineGroup(v, v->group_id, new_g); v->group_id = new_g; - for (Vehicle *u = v; u != NULL; u = u->Next()) { + for (Vehicle *u = v; u != nullptr; u = u->Next()) { u->colourmap = PAL_NONE; u->InvalidateNewGRFCache(); u->UpdateViewport(true); @@ -525,7 +526,7 @@ CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, u Vehicle *v = Vehicle::GetIfValid(GB(p2, 0, 20)); GroupID new_g = p1; - if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP)) return CMD_ERROR; + if (v == nullptr || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP)) return CMD_ERROR; if (Group::IsValidID(new_g)) { Group *g = Group::Get(new_g); @@ -536,7 +537,7 @@ CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (new_g == NEW_GROUP) { /* Create new group. */ - CommandCost ret = CmdCreateGroup(0, flags, v->type, INVALID_GROUP, NULL); + CommandCost ret = CmdCreateGroup(0, flags, v->type, INVALID_GROUP, nullptr); if (ret.Failed()) return ret; new_g = _new_group_id; @@ -547,7 +548,7 @@ CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (HasBit(p2, 31)) { /* Add vehicles in the shared order list as well. */ - for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { + for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) { if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g); } } @@ -591,7 +592,7 @@ CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 if (v->group_id != id_g) continue; /* For each shared vehicles add it to the group */ - for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { + for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) { if (v2->group_id != id_g) DoCommand(tile, id_g, v2->index, flags, CMD_ADD_VEHICLE_GROUP, text); } } @@ -619,7 +620,7 @@ CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint3 GroupID old_g = p1; Group *g = Group::GetIfValid(old_g); - if (g == NULL || g->owner != _current_company) return CMD_ERROR; + if (g == nullptr || g->owner != _current_company) return CMD_ERROR; if (flags & DC_EXEC) { Vehicle *v; @@ -656,7 +657,7 @@ CommandCost CmdSetGroupLivery(TileIndex tile, DoCommandFlag flags, uint32 p1, ui bool primary = !HasBit(p2, 8); Colours colour = Extract(p2); - if (g == NULL || g->owner != _current_company) return CMD_ERROR; + if (g == nullptr || g->owner != _current_company) return CMD_ERROR; if (colour >= COLOUR_END && colour != INVALID_COLOUR) return CMD_ERROR; @@ -708,7 +709,7 @@ static void SetGroupReplaceProtection(Group *g, bool protect) CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Group *g = Group::GetIfValid(p1); - if (g == NULL || g->owner != _current_company) return CMD_ERROR; + if (g == nullptr || g->owner != _current_company) return CMD_ERROR; if (flags & DC_EXEC) { if (HasBit(p2, 1)) { @@ -749,7 +750,7 @@ void SetTrainGroupID(Train *v, GroupID new_g) assert(v->IsFrontEngine() || IsDefaultGroupID(new_g)); - for (Vehicle *u = v; u != NULL; u = u->Next()) { + for (Vehicle *u = v; u != nullptr; u = u->Next()) { if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g); u->group_id = new_g; @@ -776,7 +777,7 @@ void UpdateTrainGroupID(Train *v) assert(v->IsFrontEngine() || v->IsFreeWagon()); GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP; - for (Vehicle *u = v; u != NULL; u = u->Next()) { + for (Vehicle *u = v; u != nullptr; u = u->Next()) { if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g); u->group_id = new_g; @@ -808,6 +809,60 @@ uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e) return count + GroupStatistics::Get(company, id_g, e->type).num_engines[id_e]; } +/** + * Get the number of vehicles in the group with GroupID + * id_g and its sub-groups. + * @param company The company the group belongs to + * @param id_g The GroupID of the group used + * @param type The vehicle type of the group + * @return The number of vehicles in the group + */ +uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type) +{ + uint count = 0; + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->parent == id_g) count += GetGroupNumVehicle(company, g->index, type); + } + return count + GroupStatistics::Get(company, id_g, type).num_vehicle; +} + +/** + * Get the number of vehicles above profit minimum age in the group with GroupID + * id_g and its sub-groups. + * @param company The company the group belongs to + * @param id_g The GroupID of the group used + * @param type The vehicle type of the group + * @return The number of vehicles above profit minimum age in the group + */ +uint GetGroupNumProfitVehicle(CompanyID company, GroupID id_g, VehicleType type) +{ + uint count = 0; + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->parent == id_g) count += GetGroupNumProfitVehicle(company, g->index, type); + } + return count + GroupStatistics::Get(company, id_g, type).num_profit_vehicle; +} + +/** + * Get last year's profit for the group with GroupID + * id_g and its sub-groups. + * @param company The company the group belongs to + * @param id_g The GroupID of the group used + * @param type The vehicle type of the group + * @return Last year's profit for the group + */ +Money GetGroupProfitLastYear(CompanyID company, GroupID id_g, VehicleType type) +{ + Money sum = 0; + const Group *g; + FOR_ALL_GROUPS(g) { + if (g->parent == id_g) sum += GetGroupProfitLastYear(company, g->index, type); + } + return sum + GroupStatistics::Get(company, id_g, type).profit_last_year; +} + void RemoveAllGroupsForCompany(const CompanyID company) { Group *g; diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 1c90326257..828a061606 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -103,6 +103,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow { private: /* Columns in the group list */ enum ListColumns { + VGC_FOLD, ///< Fold / Unfold button. VGC_NAME, ///< Group name. VGC_PROTECT, ///< Autoreplace protect icon. VGC_AUTOREPLACE, ///< Autoreplace active icon. @@ -121,41 +122,48 @@ private: uint tiny_step_height; ///< Step height for the group list Scrollbar *group_sb; - SmallVector indents; ///< Indentation levels + std::vector indents; ///< Indentation levels Dimension column_size[VGC_END]; ///< Size of the columns in the group list. 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); + for (const Group *g : *source) { + if (g->parent != parent) continue; + this->groups.push_back(g); + this->indents.push_back(indent); + if (g->folded) { + /* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */ + auto child = std::find_if(source->begin(), source->end(), [g](const Group *child){ return child->parent == g->index; }); + bool has_children = child != source->end(); + Group::Get(g->index)->folded = has_children; + } else { + AddChildren(source, g->index, indent + 1); + } } } /** Sort the groups by their name */ - static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) + static bool GroupNameSorter(const Group * const &a, const Group * const &b) { - static const Group *last_group[2] = { NULL, NULL }; + static const Group *last_group[2] = { nullptr, nullptr }; static char last_name[2][64] = { "", "" }; - if (*a != last_group[0]) { - last_group[0] = *a; - SetDParam(0, (*a)->index); + 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); + 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; + if (r == 0) return a->index < b->index; + return r < 0; } /** @@ -167,15 +175,15 @@ private: { if (!this->groups.NeedRebuild()) return; - this->groups.Clear(); - this->indents.Clear(); + this->groups.clear(); + this->indents.clear(); GUIGroupList list; const Group *g; FOR_ALL_GROUPS(g) { if (g->owner == owner && g->vehicle_type == this->vli.vtype) { - *list.Append() = g; + list.push_back(g); } } @@ -184,7 +192,7 @@ private: AddChildren(&list, INVALID_GROUP, 0); - this->groups.Compact(); + this->groups.shrink_to_fit(); this->groups.RebuildDone(); } @@ -194,9 +202,12 @@ private: */ uint ComputeGroupInfoSize() { + this->column_size[VGC_FOLD] = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED)); + this->tiny_step_height = this->column_size[VGC_FOLD].height; + this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); this->column_size[VGC_NAME].width = max(170u, this->column_size[VGC_NAME].width); - this->tiny_step_height = this->column_size[VGC_NAME].height; + this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NAME].height); this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROTECT].height); @@ -213,13 +224,16 @@ private: } this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROFIT].height); - SetDParamMaxValue(0, GroupStatistics::Get(this->vli.company, ALL_GROUP, this->vli.vtype).num_vehicle, 3, FS_SMALL); - this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_TINY_COMMA); + int num_vehicle = GetGroupNumVehicle(this->vli.company, ALL_GROUP, this->vli.vtype); + SetDParamMaxValue(0, num_vehicle, 3, FS_SMALL); + SetDParamMaxValue(1, num_vehicle, 3, FS_SMALL); + this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_GROUP_COUNT_WITH_SUBGROUP); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); this->tiny_step_height += WD_MATRIX_TOP; return WD_FRAMERECT_LEFT + 8 + + this->column_size[VGC_FOLD].width + 2 + this->column_size[VGC_NAME].width + 8 + this->column_size[VGC_PROTECT].width + 2 + this->column_size[VGC_AUTOREPLACE].width + 2 + @@ -236,8 +250,9 @@ private: * @param g_id Group to list. * @param indent Indentation level. * @param protection Whether autoreplace protection is set. + * @param has_children Whether the group has children and should have a fold / unfold button. */ - void DrawGroupInfo(int y, int left, int right, GroupID g_id, int indent = 0, bool protection = false) const + void DrawGroupInfo(int y, int left, int right, GroupID g_id, int indent = 0, bool protection = false, bool has_children = false) const { /* Highlight the group if a vehicle is dragged over it */ if (g_id == this->group_over) { @@ -251,6 +266,12 @@ private: const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype); bool rtl = _current_text_dir == TD_RTL; + /* draw fold / unfold button */ + int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_FOLD].width + 1 : left + WD_FRAMERECT_LEFT + 8; + if (has_children) { + DrawSprite(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, rtl ? x - indent : x + indent, y + (this->tiny_step_height - this->column_size[VGC_FOLD].height) / 2); + } + /* draw group name */ StringID str; if (IsAllGroupID(g_id)) { @@ -261,7 +282,7 @@ private: SetDParam(0, g_id); str = STR_GROUP_NAME; } - int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width + 1 : left + WD_FRAMERECT_LEFT + 8; + x = rtl ? x - 2 - this->column_size[VGC_NAME].width : x + 2 + this->column_size[VGC_FOLD].width; DrawString(x + (rtl ? 0 : indent), x + this->column_size[VGC_NAME].width - 1 - (rtl ? indent : 0), y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); /* draw autoreplace protection */ @@ -275,11 +296,13 @@ private: /* draw the profit icon */ x = rtl ? x - 2 - this->column_size[VGC_PROFIT].width : x + 2 + this->column_size[VGC_AUTOREPLACE].width; SpriteID spr; - if (stats.num_profit_vehicle == 0) { + uint num_profit_vehicle = GetGroupNumProfitVehicle(this->vli.company, g_id, this->vli.vtype); + Money profit_last_year = GetGroupProfitLastYear(this->vli.company, g_id, this->vli.vtype); + if (num_profit_vehicle == 0) { spr = SPR_PROFIT_NA; - } else if (stats.profit_last_year < 0) { + } else if (profit_last_year < 0) { spr = SPR_PROFIT_NEGATIVE; - } else if (stats.profit_last_year < 10000 * stats.num_profit_vehicle) { // TODO magic number + } else if (profit_last_year < (Money)10000 * num_profit_vehicle) { // TODO magic number spr = SPR_PROFIT_SOME; } else { spr = SPR_PROFIT_LOT; @@ -288,8 +311,16 @@ private: /* draw the number of vehicles of the group */ x = rtl ? x - 2 - this->column_size[VGC_NUMBER].width : x + 2 + this->column_size[VGC_PROFIT].width; - SetDParam(0, stats.num_vehicle); - DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_TINY_COMMA, colour, SA_RIGHT | SA_FORCE); + int num_vehicle_with_subgroups = GetGroupNumVehicle(this->vli.company, g_id, this->vli.vtype); + int num_vehicle = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype).num_vehicle; + if (IsAllGroupID(g_id) || IsDefaultGroupID(g_id) || num_vehicle_with_subgroups == num_vehicle) { + SetDParam(0, num_vehicle); + DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_TINY_COMMA, colour, SA_RIGHT | SA_FORCE); + } else { + SetDParam(0, num_vehicle); + SetDParam(1, num_vehicle_with_subgroups - num_vehicle); + DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_GROUP_COUNT_WITH_SUBGROUP, colour, SA_RIGHT | SA_FORCE); + } } /** @@ -359,7 +390,7 @@ public: *this->sorting = this->vehicles.GetListing(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_GL_LIST_GROUP: { @@ -423,7 +454,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ @@ -447,7 +478,7 @@ public: this->SetDirty(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_GL_AVAILABLE_VEHICLES: @@ -460,21 +491,21 @@ public: if (IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index)) { SetDParam(0, STR_COMPANY_NAME); SetDParam(1, this->vli.company); - SetDParam(2, this->vehicles.Length()); - SetDParam(3, this->vehicles.Length()); + SetDParam(2, this->vehicles.size()); + SetDParam(3, this->vehicles.size()); } else { - const Group *g = Group::Get(this->vli.index); + uint num_vehicle = GetGroupNumVehicle(this->vli.company, this->vli.index, this->vli.vtype); SetDParam(0, STR_GROUP_NAME); - SetDParam(1, g->index); - SetDParam(2, g->statistics.num_vehicle); - SetDParam(3, g->statistics.num_vehicle); + SetDParam(1, this->vli.index); + SetDParam(2, num_vehicle); + SetDParam(3, num_vehicle); } break; } } - virtual void OnPaint() + void OnPaint() override { /* If we select the all vehicles, this->list will contain all vehicles of the owner * else this->list will contain all vehicles which belong to the selected group */ @@ -483,17 +514,17 @@ public: this->BuildGroupList(this->owner); - this->group_sb->SetCount(this->groups.Length()); - this->vscroll->SetCount(this->vehicles.Length()); + this->group_sb->SetCount((uint)this->groups.size()); + this->vscroll->SetCount((uint)this->vehicles.size()); /* The drop down menu is out, *but* it may not be used, retract it. */ - if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) { + if (this->vehicles.size() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) { this->RaiseWidget(WID_GL_MANAGE_VEHICLES_DROPDOWN); HideDropDownMenu(this); } /* Disable all lists management button when the list is empty */ - this->SetWidgetsDisabledState(this->vehicles.Length() == 0 || _local_company != this->vli.company, + this->SetWidgetsDisabledState(this->vehicles.size() == 0 || _local_company != this->vli.company, WID_GL_STOP_ALL, WID_GL_START_ALL, WID_GL_MANAGE_VEHICLES_DROPDOWN, @@ -529,7 +560,7 @@ public: this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_GL_ALL_VEHICLES: @@ -544,7 +575,7 @@ public: Money this_year = 0; Money last_year = 0; uint32 occupancy = 0; - uint32 vehicle_count = this->vehicles.Length(); + size_t vehicle_count = this->vehicles.size(); for (uint i = 0; i < vehicle_count; i++) { const Vehicle *v = this->vehicles[i]; @@ -580,17 +611,17 @@ public: case WID_GL_LIST_GROUP: { int y1 = r.top + WD_FRAMERECT_TOP; - int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.Length()); + int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), (uint)this->groups.size()); for (int i = this->group_sb->GetPosition(); i < max; ++i) { const Group *g = this->groups[i]; assert(g->owner == this->owner); - DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * LEVEL_WIDTH, g->replace_protection); + DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * LEVEL_WIDTH, g->replace_protection, g->folded || (i + 1 < (int)this->groups.size() && indents[i + 1] > this->indents[i])); y1 += this->tiny_step_height; } - if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.Length()) { + if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.size()) { DrawGroupInfo(y1, r.left, r.right, NEW_GROUP); } break; @@ -604,7 +635,7 @@ public: if (this->vli.index != ALL_GROUP) { /* Mark vehicles which are in sub-groups */ int y = r.top; - uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length()); + uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->vehicles.size()); for (uint i = this->vscroll->GetPosition(); i < max; ++i) { const Vehicle *v = this->vehicles[i]; if (v->group_id != this->vli.index) { @@ -628,7 +659,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending @@ -658,7 +689,34 @@ public: case WID_GL_LIST_GROUP: { // Matrix Group uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - if (id_g >= this->groups.Length()) return; + if (id_g >= this->groups.size()) return; + + if (groups[id_g]->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) { + /* The group has children, check if the user clicked the fold / unfold button. */ + NWidgetCore *group_display = this->GetWidget(widget); + int x = _current_text_dir == TD_RTL ? + group_display->pos_x + group_display->current_x - WD_FRAMERECT_RIGHT - 8 - this->indents[id_g] * LEVEL_WIDTH - this->column_size[VGC_FOLD].width : + group_display->pos_x + WD_FRAMERECT_LEFT + 8 + this->indents[id_g] * LEVEL_WIDTH; + if (click_count > 1 || (pt.x >= x && pt.x < (int)(x + this->column_size[VGC_FOLD].width))) { + + GroupID g = this->vli.index; + if (!IsAllGroupID(g) && !IsDefaultGroupID(g)) { + do { + g = Group::Get(g)->parent; + if (g == groups[id_g]->index) { + this->vli.index = g; + break; + } + } while (g != INVALID_GROUP); + } + + Group::Get(groups[id_g]->index)->folded = !groups[id_g]->folded; + this->groups.ForceRebuild(); + + this->SetDirty(); + break; + } + } this->group_sel = this->vli.index = this->groups[id_g]->index; @@ -671,7 +729,7 @@ public: case WID_GL_LIST_VEHICLE: { // Matrix Vehicle uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); - if (id_v >= this->vehicles.Length()) return; // click out of list bound + if (id_v >= this->vehicles.size()) return; // click out of list bound const Vehicle *v = this->vehicles[id_v]; if (VehicleClicked(v)) break; @@ -710,8 +768,7 @@ public: break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)); - ShowDropDownList(this, list, 0, WID_GL_MANAGE_VEHICLES_DROPDOWN); + ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)), 0, WID_GL_MANAGE_VEHICLES_DROPDOWN); break; } @@ -723,7 +780,7 @@ public: case WID_GL_REPLACE_PROTECTION: { const Group *g = Group::GetIfValid(this->vli.index); - if (g != NULL) { + if (g != nullptr) { DoCommandP(0, this->vli.index, (g->replace_protection ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_REPLACE_PROTECTION); } break; @@ -749,7 +806,7 @@ public: case WID_GL_LIST_GROUP: { // Matrix group uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - GroupID new_g = id_g >= this->groups.Length() ? INVALID_GROUP : this->groups[id_g]->index; + GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index; if (this->group_sel != new_g && g->parent != new_g) { DoCommandP(0, this->group_sel | (1 << 16), new_g, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_SET_PARENT)); @@ -782,9 +839,9 @@ public: this->SetDirty(); uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - GroupID new_g = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; + GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index; - DoCommandP(0, new_g, vindex | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : NULL); + DoCommandP(0, new_g, vindex | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr); break; } @@ -795,7 +852,7 @@ public: this->SetDirty(); uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); - if (id_v >= this->vehicles.Length()) return; // click out of list bound + if (id_v >= this->vehicles.size()) return; // click out of list bound const Vehicle *v = this->vehicles[id_v]; if (!VehicleClicked(v) && vindex == v->index) { @@ -806,7 +863,7 @@ public: } } - virtual void OnDragDrop(Point pt, int widget) + void OnDragDrop(Point pt, int widget) override { if (this->vehicle_sel != INVALID_VEHICLE) OnDragDrop_Vehicle(pt, widget); if (this->group_sel != INVALID_GROUP) OnDragDrop_Group(pt, widget); @@ -814,19 +871,19 @@ public: _cursor.vehchain = false; } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str); + if (str != nullptr) DoCommandP(0, this->group_rename, 0, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), nullptr, str); this->group_rename = INVALID_GROUP; } - virtual void OnResize() + void OnResize() override { this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP); this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_GL_SORT_BY_DROPDOWN: @@ -834,7 +891,7 @@ public: break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: - assert(this->vehicles.Length() != 0); + assert(this->vehicles.size() != 0); switch (index) { case ADI_REPLACE: // Replace window @@ -866,14 +923,14 @@ public: this->SetDirty(); } - virtual void OnGameTick() + void OnGameTick() override { if (this->groups.NeedResort() || this->vehicles.NeedResort()) { this->SetDirty(); } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { /* abort drag & drop */ this->vehicle_sel = INVALID_VEHICLE; @@ -882,7 +939,7 @@ public: this->SetWidgetDirty(WID_GL_LIST_VEHICLE); } - virtual void OnMouseDrag(Point pt, int widget) + void OnMouseDrag(Point pt, int widget) override { if (this->vehicle_sel == INVALID_VEHICLE && this->group_sel == INVALID_GROUP) return; @@ -895,7 +952,7 @@ public: case WID_GL_LIST_GROUP: { // ... the list of custom groups. uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); - new_group_over = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; + new_group_over = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index; break; } } @@ -976,7 +1033,7 @@ void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type) * Finds a group list window determined by vehicle type and owner * @param vt vehicle type * @param owner owner of groups - * @return pointer to VehicleGroupWindow, NULL if not found + * @return pointer to VehicleGroupWindow, nullptr if not found */ static inline VehicleGroupWindow *FindVehicleGroupWindow(VehicleType vt, Owner owner) { @@ -998,7 +1055,7 @@ void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 assert(p1 <= VEH_AIRCRAFT); VehicleGroupWindow *w = FindVehicleGroupWindow((VehicleType)p1, _current_company); - if (w != NULL) w->ShowRenameGroupWindow(_new_group_id, true); + if (w != nullptr) w->ShowRenameGroupWindow(_new_group_id, true); } /** @@ -1029,5 +1086,5 @@ void DeleteGroupHighlightOfVehicle(const Vehicle *v) if (_special_mouse_mode != WSM_DRAGDROP) return; VehicleGroupWindow *w = FindVehicleGroupWindow(v->type, v->owner); - if (w != NULL) w->UnselectVehicle(v->index); + if (w != nullptr) w->UnselectVehicle(v->index); } diff --git a/src/heightmap.cpp b/src/heightmap.cpp index 17bdbbf610..4609dceeb9 100644 --- a/src/heightmap.cpp +++ b/src/heightmap.cpp @@ -47,7 +47,7 @@ static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop { uint x, y; byte gray_palette[256]; - png_bytep *row_pointers = NULL; + png_bytep *row_pointers = nullptr; bool has_palette = png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE; uint channels = png_get_channels(png_ptr, info_ptr); @@ -99,33 +99,33 @@ static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop /** * Reads the heightmap and/or size of the heightmap from a PNG file. - * If map == NULL only the size of the PNG is read, otherwise a map + * If map == nullptr only the size of the PNG is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) { FILE *fp; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; + png_structp png_ptr = nullptr; + png_infop info_ptr = nullptr; fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); - if (fp == NULL) { + if (fp == nullptr) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (png_ptr == nullptr) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) { + if (info_ptr == nullptr || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } @@ -134,14 +134,14 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); - png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL); + png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, nullptr); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } @@ -152,11 +152,11 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) if ((uint64)width * height >= (size_t)-1) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(fp); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return false; } - if (map != NULL) { + if (map != nullptr) { *map = MallocT(width * height); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } @@ -165,7 +165,7 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, byte **map) *y = height; fclose(fp); - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); return true; } @@ -180,7 +180,7 @@ static void ReadHeightmapBMPImageData(byte *map, BmpInfo *info, BmpData *data) uint x, y; byte gray_palette[256]; - if (data->palette != NULL) { + if (data->palette != nullptr) { uint i; bool all_gray = true; @@ -229,7 +229,7 @@ static void ReadHeightmapBMPImageData(byte *map, BmpInfo *info, BmpData *data) /** * Reads the heightmap and/or size of the heightmap from a BMP file. - * If map == NULL only the size of the BMP is read, otherwise a map + * If map == nullptr only the size of the BMP is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, byte **map) @@ -243,7 +243,7 @@ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, byte **map) memset(&data, 0, sizeof(data)); f = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); - if (f == NULL) { + if (f == nullptr) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } @@ -265,7 +265,7 @@ static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, byte **map) return false; } - if (map != NULL) { + if (map != nullptr) { if (!BmpReadBitmap(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); @@ -449,7 +449,7 @@ void FixSlopes() * @param filename Name of the file to load. * @param[out] x Length of the image. * @param[out] y Height of the image. - * @param[in,out] map If not \c NULL, destination to store the loaded block of image data. + * @param[in,out] map If not \c nullptr, destination to store the loaded block of image data. * @return Whether loading was successful. */ static bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, uint *y, byte **map) @@ -478,7 +478,7 @@ static bool ReadHeightMap(DetailedFileType dft, const char *filename, uint *x, u */ bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, uint *y) { - return ReadHeightMap(dft, filename, x, y, NULL); + return ReadHeightMap(dft, filename, x, y, nullptr); } /** @@ -491,7 +491,7 @@ bool GetHeightmapDimensions(DetailedFileType dft, const char *filename, uint *x, void LoadHeightmap(DetailedFileType dft, const char *filename) { uint x, y; - byte *map = NULL; + byte *map = nullptr; if (!ReadHeightMap(dft, filename, &x, &y, &map)) { free(map); diff --git a/src/highscore.cpp b/src/highscore.cpp index 86e4f5ae88..687417229b 100644 --- a/src/highscore.cpp +++ b/src/highscore.cpp @@ -17,7 +17,6 @@ #include "string_func.h" #include "strings_func.h" #include "table/strings.h" -#include "core/sort_func.hpp" #include "debug.h" #include "safeguards.h" @@ -79,9 +78,9 @@ int8 SaveHighScoreValue(const Company *c) } /** Sort all companies given their performance */ -static int CDECL HighScoreSorter(const Company * const *a, const Company * const *b) +static bool HighScoreSorter(const Company * const &a, const Company * const &b) { - return (*b)->old_economy[0].performance_history - (*a)->old_economy[0].performance_history; + return b->old_economy[0].performance_history < a->old_economy[0].performance_history; } /** @@ -98,7 +97,7 @@ int8 SaveHighScoreValueNetwork() /* Sort all active companies with the highest score first */ FOR_ALL_COMPANIES(c) cl[count++] = c; - QSortT(cl, count, &HighScoreSorter); + std::sort(std::begin(cl), std::begin(cl) + count, HighScoreSorter); { uint i; @@ -129,7 +128,7 @@ void SaveToHighScore() { FILE *fp = fopen(_highscore_file, "wb"); - if (fp != NULL) { + if (fp != nullptr) { uint i; HighScore *hs; @@ -159,7 +158,7 @@ void LoadFromHighScore() memset(_highscore_table, 0, sizeof(_highscore_table)); - if (fp != NULL) { + if (fp != nullptr) { uint i; HighScore *hs; diff --git a/src/highscore_gui.cpp b/src/highscore_gui.cpp index 0e19519341..c353f6ebcc 100644 --- a/src/highscore_gui.cpp +++ b/src/highscore_gui.cpp @@ -64,12 +64,12 @@ struct EndGameHighScoreBaseWindow : Window { return pt; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { delete this; } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { /* All keys are 'handled' by this window but we want to make * sure that 'quit' still works correctly. Not handling the @@ -130,13 +130,13 @@ struct EndGameWindow : EndGameHighScoreBaseWindow { ShowHighscoreTable(this->window_number, this->rank); } - virtual void OnPaint() + void OnPaint() override { this->SetupHighScoreEndWindow(); Point pt = this->GetTopLeft(ScaleGUITrad(640), ScaleGUITrad(480)); const Company *c = Company::GetIfValid(_local_company); - if (c == NULL) return; + if (c == nullptr) return; /* We need to get performance from last year because the image is shown * at the start of the new year when these things have already been copied */ @@ -178,7 +178,7 @@ struct HighScoreWindow : EndGameHighScoreBaseWindow { if (!_networking && !this->game_paused_by_player) DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); // unpause } - virtual void OnPaint() + void OnPaint() override { const HighScore *hs = _highscore_table[this->window_number]; @@ -211,14 +211,14 @@ static const NWidgetPart _nested_highscore_widgets[] = { }; static WindowDesc _highscore_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_HIGHSCORE, WC_NONE, 0, _nested_highscore_widgets, lengthof(_nested_highscore_widgets) ); static WindowDesc _endgame_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_ENDSCREEN, WC_NONE, 0, _nested_highscore_widgets, lengthof(_nested_highscore_widgets) diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 36ee26293e..1b997524d2 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -24,7 +24,7 @@ char *_hotkeys_file; * List of all HotkeyLists. * This is a pointer to ensure initialisation order with the various static HotkeyList instances. */ -static SmallVector *_hotkey_lists = NULL; +static std::vector *_hotkey_lists = nullptr; /** String representation of a keycode */ struct KeycodeNames { @@ -219,7 +219,7 @@ const char *SaveKeycodes(const Hotkey *hotkey) { static char buf[128]; buf[0] = '\0'; - for (uint i = 0; i < hotkey->keycodes.Length(); i++) { + for (uint i = 0; i < hotkey->keycodes.size(); i++) { const char *str = KeycodeToString(hotkey->keycodes[i]); if (i > 0) strecat(buf, ",", lastof(buf)); strecat(buf, str, lastof(buf)); @@ -264,19 +264,19 @@ Hotkey::Hotkey(const uint16 *default_keycodes, const char *name, int num) : */ void Hotkey::AddKeycode(uint16 keycode) { - this->keycodes.Include(keycode); + include(this->keycodes, keycode); } HotkeyList::HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler) : global_hotkey_handler(global_hotkey_handler), ini_group(ini_group), items(items) { - if (_hotkey_lists == NULL) _hotkey_lists = new SmallVector(); - *_hotkey_lists->Append() = this; + if (_hotkey_lists == nullptr) _hotkey_lists = new std::vector(); + _hotkey_lists->push_back(this); } HotkeyList::~HotkeyList() { - _hotkey_lists->Erase(_hotkey_lists->Find(this)); + _hotkey_lists->erase(std::find(_hotkey_lists->begin(), _hotkey_lists->end(), this)); } /** @@ -286,11 +286,11 @@ HotkeyList::~HotkeyList() void HotkeyList::Load(IniFile *ini) { IniGroup *group = ini->GetGroup(this->ini_group); - for (Hotkey *hotkey = this->items; hotkey->name != NULL; ++hotkey) { + for (Hotkey *hotkey = this->items; hotkey->name != nullptr; ++hotkey) { IniItem *item = group->GetItem(hotkey->name, false); - if (item != NULL) { - hotkey->keycodes.Clear(); - if (item->value != NULL) ParseHotkeys(hotkey, item->value); + if (item != nullptr) { + hotkey->keycodes.clear(); + if (item->value != nullptr) ParseHotkeys(hotkey, item->value); } } } @@ -302,7 +302,7 @@ void HotkeyList::Load(IniFile *ini) void HotkeyList::Save(IniFile *ini) const { IniGroup *group = ini->GetGroup(this->ini_group); - for (const Hotkey *hotkey = this->items; hotkey->name != NULL; ++hotkey) { + for (const Hotkey *hotkey = this->items; hotkey->name != nullptr; ++hotkey) { IniItem *item = group->GetItem(hotkey->name, true); item->SetValue(SaveKeycodes(hotkey)); } @@ -316,8 +316,10 @@ void HotkeyList::Save(IniFile *ini) const */ int HotkeyList::CheckMatch(uint16 keycode, bool global_only) const { - for (const Hotkey *list = this->items; list->name != NULL; ++list) { - if (list->keycodes.Contains(keycode | WKC_GLOBAL_HOTKEY) || (!global_only && list->keycodes.Contains(keycode))) { + for (const Hotkey *list = this->items; list->name != nullptr; ++list) { + auto begin = list->keycodes.begin(); + auto end = list->keycodes.end(); + if (std::find(begin, end, keycode | WKC_GLOBAL_HOTKEY) != end || (!global_only && std::find(begin, end, keycode) != end)) { return list->num; } } @@ -330,11 +332,11 @@ static void SaveLoadHotkeys(bool save) IniFile *ini = new IniFile(); ini->LoadFromDisk(_hotkeys_file, NO_DIRECTORY); - for (HotkeyList **list = _hotkey_lists->Begin(); list != _hotkey_lists->End(); ++list) { + for (HotkeyList *list : *_hotkey_lists) { if (save) { - (*list)->Save(ini); + list->Save(ini); } else { - (*list)->Load(ini); + list->Load(ini); } } @@ -357,11 +359,11 @@ void SaveHotkeysToConfig() void HandleGlobalHotkeys(WChar key, uint16 keycode) { - for (HotkeyList **list = _hotkey_lists->Begin(); list != _hotkey_lists->End(); ++list) { - if ((*list)->global_hotkey_handler == NULL) continue; + for (HotkeyList *list : *_hotkey_lists) { + if (list->global_hotkey_handler == nullptr) continue; - int hotkey = (*list)->CheckMatch(keycode, true); - if (hotkey >= 0 && ((*list)->global_hotkey_handler(hotkey) == ES_HANDLED)) return; + int hotkey = list->CheckMatch(keycode, true); + if (hotkey >= 0 && (list->global_hotkey_handler(hotkey) == ES_HANDLED)) return; } } diff --git a/src/hotkeys.h b/src/hotkeys.h index 25a489b3f3..00e8c0c3fd 100644 --- a/src/hotkeys.h +++ b/src/hotkeys.h @@ -29,10 +29,10 @@ struct Hotkey { const char *name; int num; - SmallVector keycodes; + std::vector keycodes; }; -#define HOTKEY_LIST_END Hotkey((uint16)0, NULL, -1) +#define HOTKEY_LIST_END Hotkey((uint16)0, nullptr, -1) struct IniFile; @@ -42,7 +42,7 @@ struct IniFile; struct HotkeyList { typedef EventState (*GlobalHotkeyHandlerFunc)(int hotkey); - HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler = NULL); + HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler = nullptr); ~HotkeyList(); void Load(IniFile *ini); diff --git a/src/industry.h b/src/industry.h index af0208b3cc..b03b696549 100644 --- a/src/industry.h +++ b/src/industry.h @@ -18,6 +18,7 @@ #include "industry_map.h" #include "industrytype.h" #include "tilearea_type.h" +#include "station_base.h" typedef Pool IndustryPool; @@ -41,6 +42,7 @@ enum ProductionLevels { struct Industry : IndustryPool::PoolItem<&_industry_pool> { TileArea location; ///< Location of the industry Town *town; ///< Nearest town + Station *neutral_station; ///< Associated neutral station CargoID produced_cargo[INDUSTRY_NUM_OUTPUTS]; ///< 16 production cargo slots uint16 produced_cargo_waiting[INDUSTRY_NUM_OUTPUTS]; ///< amount of cargo produced per cargo uint16 incoming_cargo_waiting[INDUSTRY_NUM_INPUTS]; ///< incoming cargo waiting to be processed @@ -54,23 +56,24 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> { uint16 last_month_transported[INDUSTRY_NUM_OUTPUTS]; ///< total units transported per cargo in the last full month uint16 counter; ///< used for animation and/or production (if available cargo) - IndustryType type; ///< type of industry. - OwnerByte owner; ///< owner of the industry. Which SHOULD always be (imho) OWNER_NONE - byte random_colour; ///< randomized colour of the industry, for display purpose - Year last_prod_year; ///< last year of production - byte was_cargo_delivered; ///< flag that indicate this has been the closest industry chosen for cargo delivery by a station. see DeliverGoodsToIndustry + IndustryType type; ///< type of industry. + Owner owner; ///< owner of the industry. Which SHOULD always be (imho) OWNER_NONE + byte random_colour; ///< randomized colour of the industry, for display purpose + Year last_prod_year; ///< last year of production + byte was_cargo_delivered; ///< flag that indicate this has been the closest industry chosen for cargo delivery by a station. see DeliverGoodsToIndustry - PartOfSubsidyByte part_of_subsidy; ///< NOSAVE: is this industry a source/destination of a subsidy? + PartOfSubsidy part_of_subsidy; ///< NOSAVE: is this industry a source/destination of a subsidy? + StationList stations_near; ///< NOSAVE: List of nearby stations. - OwnerByte founder; ///< Founder of the industry - Date construction_date; ///< Date of the construction of the industry - uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType) + Owner founder; ///< Founder of the industry + Date construction_date; ///< Date of the construction of the industry + uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType) Date last_cargo_accepted_at[INDUSTRY_NUM_INPUTS]; ///< Last day each cargo type was accepted by this industry - byte selected_layout; ///< Which tile layout was used when creating the industry + byte selected_layout; ///< Which tile layout was used when creating the industry - uint16 random; ///< Random value used for randomisation of all kinds of things + uint16 random; ///< Random value used for randomisation of all kinds of things - PersistentStorage *psa; ///< Persistent storage for NewGRF industries. + PersistentStorage *psa; ///< Persistent storage for NewGRF industries. Industry(TileIndex tile = INVALID_TILE) : location(tile, 0, 0) {} ~Industry(); diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index dd40708e63..f8dc0cf7df 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -71,11 +71,15 @@ IndustryBuildData _industry_builder; ///< In-game manager of industries. */ void ResetIndustries() { - memset(&_industry_specs, 0, sizeof(_industry_specs)); - memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs)); - - /* once performed, enable only the current climate industries */ for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) { + /* Reset the spec to default */ + if (i < lengthof(_origin_industry_specs)) { + _industry_specs[i] = _origin_industry_specs[i]; + } else { + _industry_specs[i] = IndustrySpec{}; + } + + /* Enable only the current climate industries */ _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET && HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape); } @@ -101,7 +105,7 @@ IndustryType GetIndustryType(TileIndex tile) assert(IsTileType(tile, MP_INDUSTRY)); const Industry *ind = Industry::GetByTile(tile); - assert(ind != NULL); + assert(ind != nullptr); return ind->type; } @@ -155,9 +159,15 @@ Industry::~Industry() } } + if (this->neutral_station != nullptr) { + /* Remove possible docking tiles */ + TILE_AREA_LOOP(tile_cur, this->location) { + ClearDockingTilesCheckingNeighbours(tile_cur); + } + } + if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) { - TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42); - ta.ClampToMap(); + TileArea ta = TileArea(this->location.tile, 0, 0).Expand(21); /* Remove the farmland and convert it to regular tiles over time. */ TILE_AREA_LOOP(tile_cur, ta) { @@ -182,6 +192,10 @@ Industry::~Industry() DeleteSubsidyWith(ST_INDUSTRY, this->index); CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index); + + for (Station *st : this->stations_near) { + st->industries_near.erase(this); + } } /** @@ -191,17 +205,16 @@ Industry::~Industry() void Industry::PostDestructor(size_t index) { InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0); - Station::RecomputeIndustriesNearForAll(); } /** * Return a random valid industry. - * @return random industry, NULL if there are no industries + * @return random industry, nullptr if there are no industries */ /* static */ Industry *Industry::GetRandom() { - if (Industry::GetNumItems() == 0) return NULL; + if (Industry::GetNumItems() == 0) return nullptr; int num = RandomRange((uint16)Industry::GetNumItems()); size_t index = MAX_UVALUE(size_t); @@ -313,7 +326,7 @@ static void DrawTile_Industry(TileInfo *ti) * DrawNewIndustry will return false if ever the resolver could not * find any sprite to display. So in this case, we will jump on the * substitute gfx instead. */ - if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) { + if (indts->grf_prop.spritegroup[0] != nullptr && DrawNewIndustryTile(ti, ind, gfx, indts)) { return; } else { /* No sprite group (or no valid one) found, meaning no graphics associated. @@ -382,7 +395,7 @@ static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh) */ if (gfx >= NEW_INDUSTRYTILEOFFSET) { const IndustryTileSpec *indts = GetIndustryTileSpec(gfx); - if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) { + if (indts->grf_prop.spritegroup[0] != nullptr && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) { uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE; } @@ -472,7 +485,7 @@ static void GetTileDesc_Industry(TileIndex tile, TileDesc *td) td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION; } - if (is->grf_prop.grffile != NULL) { + if (is->grf_prop.grffile != nullptr) { td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName(); } } @@ -516,8 +529,6 @@ static bool TransportIndustryGoods(TileIndex tile) const IndustrySpec *indspec = GetIndustrySpec(i->type); bool moved_cargo = false; - StationFinder stations(i->location); - for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) { uint cw = min(i->produced_cargo_waiting[j], 255); if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) { @@ -528,7 +539,7 @@ static bool TransportIndustryGoods(TileIndex tile) i->this_month_production[j] += cw; - uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations()); + uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, &i->stations_near); i->this_month_transported[j] += am; moved_cargo |= (am != 0); @@ -798,7 +809,7 @@ static void TileLoopIndustry_BubbleGenerator(TileIndex tile) EV_BUBBLE ); - if (v != NULL) v->animation_substate = dir; + if (v != nullptr) v->animation_substate = dir; } static void TileLoop_Industry(TileIndex tile) @@ -1077,7 +1088,7 @@ static bool SearchLumberMillTrees(TileIndex tile, void *user_data) if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees /* found a tree */ - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); _industry_sound_ctr = 1; _industry_sound_tile = tile; @@ -1105,7 +1116,7 @@ static void ChopLumberMillTrees(Industry *i) } TileIndex tile = i->location.tile; - if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search. + if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search. i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo. } } @@ -1117,11 +1128,16 @@ static void ProduceIndustryGoods(Industry *i) /* play a sound? */ if ((i->counter & 0x3F) == 0) { uint32 r; - uint num; - if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) { - SndPlayTileFx( - (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]), - i->location.tile); + if (Chance16R(1, 14, r) && indsp->number_of_sounds != 0 && _settings_client.sound.ambient) { + for (size_t j = 0; j < lengthof(i->last_month_production); j++) { + if (i->last_month_production[j] > 0) { + /* Play sound since last month had production */ + SndPlayTileFx( + (SoundFx)(indsp->random_sounds[((r >> 16) * indsp->number_of_sounds) >> 16]), + i->location.tile); + break; + } + } } } @@ -1218,6 +1234,29 @@ static CommandCost CheckNewIndustry_Forest(TileIndex tile) return CommandCost(); } +/** + * Check if a tile is within a distance from map edges, scaled by map dimensions independently. + * Each dimension is checked independently, and dimensions smaller than 256 are not scaled. + * @param tile Which tile to check distance of. + * @param maxdist Normal distance on a 256x256 map. + * @return True if the tile is near the map edge. + */ +static bool CheckScaledDistanceFromEdge(TileIndex tile, uint maxdist) +{ + uint maxdist_x = maxdist; + uint maxdist_y = maxdist; + + if (MapSizeX() > 256) maxdist_x *= MapSizeX() / 256; + if (MapSizeY() > 256) maxdist_y *= MapSizeY() / 256; + + if (DistanceFromEdgeDir(tile, DIAGDIR_NE) < maxdist_x) return true; + if (DistanceFromEdgeDir(tile, DIAGDIR_NW) < maxdist_y) return true; + if (DistanceFromEdgeDir(tile, DIAGDIR_SW) < maxdist_x) return true; + if (DistanceFromEdgeDir(tile, DIAGDIR_SE) < maxdist_y) return true; + + return false; +} + /** * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map). * @param tile %Tile to perform the checking. @@ -1226,7 +1265,8 @@ static CommandCost CheckNewIndustry_Forest(TileIndex tile) static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile) { if (_game_mode == GM_EDITOR) return CommandCost(); - if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost(); + + if (CheckScaledDistanceFromEdge(TILE_ADDXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost(); return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED); } @@ -1241,8 +1281,9 @@ extern bool _ignore_restrictions; static CommandCost CheckNewIndustry_OilRig(TileIndex tile) { if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost(); + if (TileHeight(tile) == 0 && - DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost(); + CheckScaledDistanceFromEdge(TILE_ADDXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost(); return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED); } @@ -1338,11 +1379,11 @@ static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = { * Find a town for the industry, while checking for multiple industries in the same town. * @param tile Position of the industry to build. * @param type Industry type. - * @param[out] t Pointer to return town for the new industry, \c NULL is written if no good town can be found. + * @param[out] t Pointer to return town for the new industry, \c nullptr is written if no good town can be found. * @return Succeeded or failed command. * - * @pre \c *t != NULL - * @post \c *t points to a town on success, and \c NULL on failure. + * @pre \c *t != nullptr + * @post \c *t points to a town on success, and \c nullptr on failure. */ static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t) { @@ -1353,7 +1394,7 @@ static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t) const Industry *i; FOR_ALL_INDUSTRIES(i) { if (i->type == (byte)type && i->town == *t) { - *t = NULL; + *t = nullptr; return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN); } } @@ -1381,8 +1422,8 @@ bool IsSlopeRefused(Slope current, Slope refused) /** * Are the tiles of the industry free? * @param tile Position to check. - * @param it Industry tiles table. - * @param itspec_index The index of the itsepc to build/fund + * @param layout Industry tiles table. + * @param layout_index The index of the layout to build/fund * @param type Type of the industry. * @param initial_random_bits The random bits the industry is going to have after construction. * @param founder Industry founder @@ -1390,14 +1431,14 @@ bool IsSlopeRefused(Slope current, Slope refused) * @param[out] custom_shape_check Perform custom check for the site. * @return Failed or succeeded command. */ -static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = NULL) +static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileLayout &layout, size_t layout_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = nullptr) { bool refused_slope = false; bool custom_shape = false; - do { - IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx); - TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y); + for (const IndustryTileLayoutTile &it : layout) { + IndustryGfx gfx = GetTranslatedIndustryTileID(it.gfx); + TileIndex cur_tile = TileAddWrap(tile, it.ti.x, it.ti.y); if (!IsValidTile(cur_tile)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); @@ -1422,7 +1463,7 @@ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTil if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) { custom_shape = true; - CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type); + CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, layout_index, initial_random_bits, founder, creation_type); if (ret.Failed()) return ret; } else { Slope tileh = GetTileSlope(cur_tile); @@ -1436,7 +1477,7 @@ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTil } /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */ - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); @@ -1448,9 +1489,9 @@ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTil if (ret.Failed()) return ret; } } - } while ((++it)->ti.x != -0x80); + } - if (custom_shape_check != NULL) *custom_shape_check = custom_shape; + if (custom_shape_check != nullptr) *custom_shape_check = custom_shape; /* It is almost impossible to have a fully flat land in TG, so what we * do is that we check if we can make the land flat later on. See @@ -1512,18 +1553,17 @@ static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int i * This function tries to flatten out the land below an industry, without * damaging the surroundings too much. */ -static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type) +static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileLayout &layout, int type) { - const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h) int max_x = 0; int max_y = 0; /* Finds dimensions of largest variant of this industry */ - do { - if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it - if (it->ti.x > max_x) max_x = it->ti.x; - if (it->ti.y > max_y) max_y = it->ti.y; - } while ((++it)->ti.x != MKEND); + for (const IndustryTileLayoutTile &it : layout) { + if (it.gfx == GFX_WATERTILE_SPECIALCHECK) continue; // watercheck tiles don't count for footprint size + if (it.ti.x > max_x) max_x = it.ti.x; + if (it.ti.y > max_y) max_y = it.ti.y; + } /* Remember level height */ uint h = TileHeight(tile); @@ -1532,6 +1572,8 @@ static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, /* Check that all tiles in area and surrounding are clear * this determines that there are no obstructing items */ + /* TileArea::Expand is not used here as we need to abort + * instead of clamping if the bounds cannot expanded. */ TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform), max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform); @@ -1539,7 +1581,7 @@ static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry. * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */ - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); TILE_AREA_LOOP(tile_walk, ta) { uint curh = TileHeight(tile_walk); @@ -1587,14 +1629,12 @@ static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type) { const IndustrySpec *indspec = GetIndustrySpec(type); - const Industry *i = NULL; + const Industry *i = nullptr; /* On a large map with many industries, it may be faster to check an area. */ static const int dmax = 14; if (Industry::GetNumItems() > (size_t) (dmax * dmax * 2)) { - const int tx = TileX(tile); - const int ty = TileY(tile); - TileArea tile_area = TileArea(TileXY(max(0, tx - dmax), max(0, ty - dmax)), TileXY(min(MapMaxX(), tx + dmax), min(MapMaxY(), ty + dmax))); + TileArea tile_area = TileArea(tile, 1, 1).Expand(dmax); TILE_AREA_LOOP(atile, tile_area) { if (GetTileType(atile) == MP_INDUSTRY) { const Industry *i2 = Industry::GetByTile(atile); @@ -1644,18 +1684,49 @@ static void AdvertiseIndustryOpening(const Industry *ind) Game::NewEvent(new ScriptEventIndustryOpen(ind->index)); } +/** + * Populate an industry's list of nearby stations, and if it accepts any cargo, also + * add the industry to each station's nearby industry list. + * @param ind Industry + */ +static void PopulateStationsNearby(Industry *ind) +{ + if (ind->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) { + /* Industry has a neutral station. Use it and ignore any other nearby stations. */ + ind->stations_near.insert(ind->neutral_station); + ind->neutral_station->industries_near.clear(); + ind->neutral_station->industries_near.insert(ind); + return; + } + + /* Get our list of nearby stations. */ + FindStationsAroundTiles(ind->location, &ind->stations_near, false); + + /* Test if industry can accept cargo */ + uint cargo_index; + for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { + if (ind->accepts_cargo[cargo_index] != CT_INVALID) break; + } + if (cargo_index >= lengthof(ind->accepts_cargo)) return; + + /* Cargo is accepted, add industry to nearby stations nearby industry list. */ + for (Station *st : ind->stations_near) { + st->industries_near.insert(ind); + } +} + /** * Put an industry on the map. - * @param i Just allocated poolitem, mostly empty. - * @param tile North tile of the industry. - * @param type Type of the industry. - * @param it Industrylayout to build. - * @param layout Number of the layout. - * @param t Nearest town. - * @param founder Founder of the industry; OWNER_NONE in case of random construction. + * @param i Just allocated poolitem, mostly empty. + * @param tile North tile of the industry. + * @param type Type of the industry. + * @param layout Industrylayout to build. + * @param layout_index Number of the industry layout. + * @param t Nearest town. + * @param founder Founder of the industry; OWNER_NONE in case of random construction. * @param initial_random_bits Random bits for the industry. */ -static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits) +static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileLayout &layout, size_t layout_index, Town *t, Owner founder, uint16 initial_random_bits) { const IndustrySpec *indspec = GetIndustrySpec(type); @@ -1700,7 +1771,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries * 0 = created prior of newindustries * else, chosen layout + 1 */ - i->selected_layout = layout + 1; + i->selected_layout = (byte)(layout_index + 1); i->prod_level = PRODLEVEL_DEFAULT; @@ -1796,17 +1867,17 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, /* Plant the tiles */ - do { - TileIndex cur_tile = tile + ToTileIndexDiff(it->ti); + for (const IndustryTileLayoutTile &it : layout) { + TileIndex cur_tile = tile + ToTileIndexDiff(it.ti); - if (it->gfx != GFX_WATERTILE_SPECIALCHECK) { + if (it.gfx != GFX_WATERTILE_SPECIALCHECK) { i->location.Add(cur_tile); WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID); DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR); - MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc); + MakeIndustry(cur_tile, i->index, it.gfx, Random(), wc); if (_generating_world) { SetIndustryConstructionCounter(cur_tile, 3); @@ -1814,18 +1885,18 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, } /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */ - IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx); + IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx); const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx); if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile); } - } while ((++it)->ti.x != -0x80); + } if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { for (uint j = 0; j != 50; j++) PlantRandomFarmField(i); } InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0); - Station::RecomputeIndustriesNearForAll(); + if (!_generating_world) PopulateStationsNearby(i); } /** @@ -1834,7 +1905,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, * @param type of industry to build * @param flags of operations to conduct * @param indspec pointer to industry specifications - * @param itspec_index the index of the itsepc to build/fund + * @param layout_index the index of the itsepc to build/fund * @param random_var8f random seed (possibly) used by industries * @param random_initial_bits The random bits the industry is going to have after construction. * @param founder Founder of the industry @@ -1842,40 +1913,40 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, * @param[out] ip Pointer to store newly created industry. * @return Succeeded or failed command. * - * @post \c *ip contains the newly created industry if all checks are successful and the \a flags request actual creation, else it contains \c NULL afterwards. + * @post \c *ip contains the newly created industry if all checks are successful and the \a flags request actual creation, else it contains \c nullptr afterwards. */ -static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, uint itspec_index, uint32 random_var8f, uint16 random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip) +static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, size_t layout_index, uint32 random_var8f, uint16 random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip) { - assert(itspec_index < indspec->num_table); - const IndustryTileTable *it = indspec->table[itspec_index]; + assert(layout_index < indspec->layouts.size()); + const IndustryTileLayout &layout = indspec->layouts[layout_index]; bool custom_shape_check = false; - *ip = NULL; + *ip = nullptr; - SmallVector object_areas(_cleared_object_areas); - CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check); + std::vector object_areas(_cleared_object_areas); + CommandCost ret = CheckIfIndustryTilesAreFree(tile, layout, layout_index, type, random_initial_bits, founder, creation_type, &custom_shape_check); _cleared_object_areas = object_areas; if (ret.Failed()) return ret; if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) { - ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type); + ret = CheckIfCallBackAllowsCreation(tile, type, layout_index, random_var8f, random_initial_bits, founder, creation_type); } else { ret = _check_new_industry_procs[indspec->check_proc](tile); } if (ret.Failed()) return ret; if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && - !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) { + !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, layout, type)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } ret = CheckIfFarEnoughFromConflictingIndustry(tile, type); if (ret.Failed()) return ret; - Town *t = NULL; + Town *t = nullptr; ret = FindTownForIndustry(tile, type, &t); if (ret.Failed()) return ret; - assert(t != NULL); + assert(t != nullptr); ret = CheckIfIndustryIsAllowed(tile, type, t); if (ret.Failed()) return ret; @@ -1884,8 +1955,8 @@ static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, Do if (flags & DC_EXEC) { *ip = new Industry(tile); - if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type); - DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits); + if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, layout, type); + DoCreateNewIndustry(*ip, tile, type, layout, layout_index, t, founder, random_initial_bits); } return CommandCost(); @@ -1945,7 +2016,7 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin const IndustrySpec *indspec = GetIndustrySpec(it); /* Check if the to-be built/founded industry is available for this climate. */ - if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR; + if (!indspec->enabled || indspec->layouts.empty()) return CMD_ERROR; /* If the setting for raw-material industries is not on, you cannot build raw-material industries. * Raw material industries are industries that do not accept cargo (at least for now) */ @@ -1961,15 +2032,15 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin randomizer.SetSeed(p2); uint16 random_initial_bits = GB(p2, 0, 16); uint32 random_var8f = randomizer.Next(); - int num_layouts = indspec->num_table; + size_t num_layouts = indspec->layouts.size(); CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE); const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16); - Industry *ind = NULL; + Industry *ind = nullptr; if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) { if (flags & DC_EXEC) { /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */ - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); /* Prospecting has a chance to fail, however we cannot guarantee that something can * be built on the map, so the chance gets lower when the map is fuller, but there * is nothing we can really do about that. */ @@ -1980,9 +2051,9 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin */ tile = RandomTile(); /* Start with a random layout */ - int layout = RandomRange(num_layouts); + size_t layout = RandomRange((uint32)num_layouts); /* Check now each layout, starting with the random one */ - for (int j = 0; j < num_layouts; j++) { + for (size_t j = 0; j < num_layouts; j++) { layout = (layout + 1) % num_layouts; ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind); if (ret.Succeeded()) break; @@ -1993,11 +2064,11 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin cur_company.Restore(); } } else { - int layout = GB(p1, 8, 8); + size_t layout = GB(p1, 8, 8); if (layout >= num_layouts) return CMD_ERROR; /* Check subsequently each layout, starting with the given layout in p1 */ - for (int i = 0; i < num_layouts; i++) { + for (size_t i = 0; i < num_layouts; i++) { layout = (layout + 1) % num_layouts; ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind); if (ret.Succeeded()) break; @@ -2007,7 +2078,7 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (ret.Failed()) return ret; } - if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) { + if ((flags & DC_EXEC) && ind != nullptr && _game_mode != GM_EDITOR) { AdvertiseIndustryOpening(ind); } @@ -2020,7 +2091,7 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin * @param tile The location to build the industry. * @param type The industry type to build. * @param creation_type The circumstances the industry is created under. - * @return the created industry or NULL if it failed. + * @return the created industry or nullptr if it failed. */ static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type) { @@ -2028,9 +2099,10 @@ static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAv uint32 seed = Random(); uint32 seed2 = Random(); - Industry *i = NULL; - CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i); - assert(i != NULL || ret.Failed()); + Industry *i = nullptr; + size_t layout_index = RandomRange((uint32)indspec->layouts.size()); + CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, layout_index, seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i); + assert(i != nullptr || ret.Failed()); return i; } @@ -2044,7 +2116,7 @@ static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *forc { const IndustrySpec *ind_spc = GetIndustrySpec(it); uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision - if (!ind_spc->enabled || ind_spc->num_table == 0 || + if (!ind_spc->enabled || ind_spc->layouts.empty() || (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) || (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) { *force_at_least_one = false; @@ -2074,7 +2146,7 @@ static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number) const IndustrySpec *ind_spc = GetIndustrySpec(it); byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape]; - if (!ind_spc->enabled || ind_spc->num_table == 0 || + if (!ind_spc->enabled || ind_spc->layouts.empty() || ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) || ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) || (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) { @@ -2112,16 +2184,16 @@ static uint GetNumberOfIndustries() * than to try a few times before concluding it does not work. * @param type Industry type of the desired industry. * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.) - * @return Pointer to created industry, or \c NULL if creation failed. + * @return Pointer to created industry, or \c nullptr if creation failed. */ static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard) { uint tries = try_hard ? 10000u : 2000u; for (; tries > 0; tries--) { Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type); - if (ind != NULL) return ind; + if (ind != nullptr) return ind; } - return NULL; + return nullptr; } /** @@ -2131,7 +2203,7 @@ static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType c */ static void PlaceInitialIndustry(IndustryType type, bool try_hard) { - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); IncreaseGeneratingWorldProgress(GWP_INDUSTRY); PlaceIndustry(type, IACT_MAPGENERATION, try_hard); @@ -2387,7 +2459,7 @@ void IndustryBuildData::TryBuildNewIndustry() /* Try to create the industry. */ const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false); - if (ind == NULL) { + if (ind == nullptr) { this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below. this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2); } else { @@ -2464,11 +2536,7 @@ static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accept */ static int WhoCanServiceIndustry(Industry *ind) { - /* Find all stations within reach of the industry */ - StationList stations; - FindStationsAroundTiles(ind->location, &stations); - - if (stations.Length() == 0) return 0; // No stations found at all => nobody services + if (ind->stations_near.size() == 0) return 0; // No stations found at all => nobody services const Vehicle *v; int result = 0; @@ -2480,7 +2548,7 @@ static int WhoCanServiceIndustry(Industry *ind) bool c_accepts = false; bool c_produces = false; if (v->type == VEH_TRAIN && v->IsFrontEngine()) { - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces); } } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) { @@ -2499,12 +2567,12 @@ static int WhoCanServiceIndustry(Industry *ind) if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) { /* Vehicle visits a station to load or unload */ Station *st = Station::Get(o->GetDestination()); - assert(st != NULL); + assert(st != nullptr); /* Same cargo produced by industry is dropped here => not serviced by vehicle v */ if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break; - if (stations.Contains(st)) { + if (ind->stations_near.find(st) != ind->stations_near.end()) { if (v->owner == _local_company) return 2; // Company services industry result = 1; // Competitor services industry } @@ -2767,7 +2835,7 @@ void IndustryDailyLoop() return; // Nothing to do? get out } - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); /* perform the required industry changes for the day */ @@ -2780,7 +2848,7 @@ void IndustryDailyLoop() _industry_builder.TryBuildNewIndustry(); } else { Industry *i = Industry::GetRandom(); - if (i != NULL) { + if (i != nullptr) { ChangeIndustryProduction(i, false); SetWindowDirty(WC_INDUSTRY_VIEW, i->index); } @@ -2795,7 +2863,7 @@ void IndustryDailyLoop() void IndustryMonthlyLoop() { - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); _industry_builder.MonthlyLoop(); @@ -2898,6 +2966,13 @@ bool IndustrySpec::UsesSmoothEconomy() const !(HasBit(this->callback_mask, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CHANGE) || HasBit(this->callback_mask, CBM_IND_PROD_CHANGE_BUILD)); // production change callbacks } +IndustrySpec::~IndustrySpec() +{ + if (HasBit(this->cleanup_flag, CLEAN_RANDOMSOUNDS)) { + free(this->random_sounds); + } +} + static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { if (AutoslopeEnabled()) { @@ -2938,8 +3013,13 @@ extern const TileTypeProcs _tile_type_industry_procs = { AnimateTile_Industry, // animate_tile_proc TileLoop_Industry, // tile_loop_proc ChangeTileOwner_Industry, // change_tile_owner_proc - NULL, // add_produced_cargo_proc - NULL, // vehicle_enter_tile_proc + nullptr, // add_produced_cargo_proc + nullptr, // vehicle_enter_tile_proc GetFoundation_Industry, // get_foundation_proc TerraformTile_Industry, // terraform_tile_proc }; + +bool IndustryCompare::operator() (const Industry *lhs, const Industry *rhs) const +{ + return lhs->index < rhs->index; +} diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index c900b8ad17..5c01a466d7 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -78,7 +78,7 @@ static void ShowIndustryCargoesWindow(IndustryType id); * Gets the string to display after the cargo name (using callback 37) * @param cargo the cargo for which the suffix is requested, meaning depends on presence of flag 18 in prop 1A * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType - * @param ind the industry (NULL if in fund window) + * @param ind the industry (nullptr if in fund window) * @param ind_type the industry type * @param indspec the industry spec * @param suffix is filled with the string to display @@ -140,7 +140,7 @@ enum CargoSuffixInOut { * Gets all strings to display after the cargoes of industries (using callback 37) * @param use_input get suffixes for output cargoes or input cargoes? * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType - * @param ind the industry (NULL if in fund window) + * @param ind the industry (nullptr if in fund window) * @param ind_type the industry type * @param indspec the industry spec * @param cargoes array with cargotypes. for CT_INVALID no suffix will be determined @@ -185,23 +185,23 @@ static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixTy } } -IndustryType _sorted_industry_types[NUM_INDUSTRYTYPES]; ///< Industry types sorted by name. +std::array _sorted_industry_types; ///< Industry types sorted by name. /** Sort industry types by their name. */ -static int CDECL IndustryTypeNameSorter(const IndustryType *a, const IndustryType *b) +static bool IndustryTypeNameSorter(const IndustryType &a, const IndustryType &b) { static char industry_name[2][64]; - const IndustrySpec *indsp1 = GetIndustrySpec(*a); + const IndustrySpec *indsp1 = GetIndustrySpec(a); GetString(industry_name[0], indsp1->name, lastof(industry_name[0])); - const IndustrySpec *indsp2 = GetIndustrySpec(*b); + const IndustrySpec *indsp2 = GetIndustrySpec(b); GetString(industry_name[1], indsp2->name, lastof(industry_name[1])); int r = strnatcmp(industry_name[0], industry_name[1]); // Sort by name (natural sorting). /* If the names are equal, sort by industry type. */ - return (r != 0) ? r : (*a - *b); + return (r != 0) ? r < 0 : (a < b); } /** @@ -215,7 +215,7 @@ void SortIndustryTypes() } /* Sort industry types by name. */ - QSortT(_sorted_industry_types, NUM_INDUSTRYTYPES, &IndustryTypeNameSorter); + std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), IndustryTypeNameSorter); } /** @@ -313,8 +313,7 @@ class BuildIndustryWindow : public Window { * The tests performed after the enabled allow to load the industries * In the same way they are inserted by grf (if any) */ - for (uint i = 0; i < NUM_INDUSTRYTYPES; i++) { - IndustryType ind = _sorted_industry_types[i]; + for (IndustryType ind : _sorted_industry_types) { const IndustrySpec *indsp = GetIndustrySpec(ind); if (indsp->enabled) { /* Rule is that editor mode loads all industries. @@ -424,12 +423,12 @@ public: SetIndustryForbiddenTilesHighlight(INVALID_INDUSTRYTYPE); } - virtual void OnInit() + void OnInit() override { this->SetupArrays(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_DPI_MATRIX_WIDGET: { @@ -459,7 +458,7 @@ public: CargoSuffix cargo_suffix[lengthof(indsp->accepts_cargo)]; /* Measure the accepted cargoes, if any. */ - GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, NULL, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix); + GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, nullptr, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix); std::string cargostring = this->MakeCargoListString(indsp->accepts_cargo, cargo_suffix, lengthof(indsp->accepts_cargo), STR_INDUSTRY_VIEW_REQUIRES_N_CARGO); Dimension strdim = GetStringBoundingBox(cargostring.c_str()); if (strdim.width > max_minwidth) { @@ -469,7 +468,7 @@ public: d = maxdim(d, strdim); /* Measure the produced cargoes, if any. */ - GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, NULL, this->index[i], indsp, indsp->produced_cargo, cargo_suffix); + GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, nullptr, this->index[i], indsp, indsp->produced_cargo, cargo_suffix); cargostring = this->MakeCargoListString(indsp->produced_cargo, cargo_suffix, lengthof(indsp->produced_cargo), STR_INDUSTRY_VIEW_PRODUCES_N_CARGO); strdim = GetStringBoundingBox(cargostring.c_str()); if (strdim.width > max_minwidth) { @@ -498,7 +497,7 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_DPI_FUND_WIDGET: @@ -515,7 +514,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_DPI_MATRIX_WIDGET: { @@ -572,18 +571,18 @@ public: CargoSuffix cargo_suffix[lengthof(indsp->accepts_cargo)]; /* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */ - GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, NULL, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix); + GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, nullptr, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix); std::string cargostring = this->MakeCargoListString(indsp->accepts_cargo, cargo_suffix, lengthof(indsp->accepts_cargo), STR_INDUSTRY_VIEW_REQUIRES_N_CARGO); y = DrawStringMultiLine(left, right, y, bottom, cargostring.c_str()); /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ - GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, NULL, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix); + GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, nullptr, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix); cargostring = this->MakeCargoListString(indsp->produced_cargo, cargo_suffix, lengthof(indsp->produced_cargo), STR_INDUSTRY_VIEW_PRODUCES_N_CARGO); y = DrawStringMultiLine(left, right, y, bottom, cargostring.c_str()); /* Get the additional purchase info text, if it has not already been queried. */ if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) { - uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); + uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, nullptr, this->selected_type, INVALID_TILE); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { if (callback_res > 0x400) { ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_FUND_MORE_TEXT, callback_res); @@ -602,7 +601,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_DPI_MATRIX_WIDGET: { @@ -611,12 +610,12 @@ public: this->selected_index = y; this->selected_type = this->index[y]; SetIndustryForbiddenTilesHighlight(this->selected_type); - const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); + const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? nullptr : GetIndustrySpec(this->selected_type); this->SetDirty(); if (_thd.GetCallbackWnd() == this && - ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || + ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != nullptr && indsp->IsRawIndustry()) || this->selected_type == INVALID_INDUSTRYTYPE || !this->enabled[this->selected_index])) { /* Reset the button state if going to prospecting or "build many industries" */ @@ -667,18 +666,19 @@ public: } } - virtual void OnResize() + void OnResize() override { /* Adjust the number of items in the matrix depending of the resize */ this->vscroll->SetCapacityFromWidget(this, WID_DPI_MATRIX_WIDGET); } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { bool success = true; /* We do not need to protect ourselves against "Random Many Industries" in this mode */ const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); uint32 seed = InteractiveRandom(); + uint32 layout_index = InteractiveRandomRange((uint32)indsp->layouts.size()); if (_game_mode == GM_EDITOR) { /* Show error if no town exists at all */ @@ -688,25 +688,25 @@ public: return; } - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); _generating_world = true; _ignore_restrictions = true; - DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, + DoCommandP(tile, (layout_index << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY), &CcBuildIndustry); cur_company.Restore(); _ignore_restrictions = false; _generating_world = false; } else { - success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); + success = DoCommandP(tile, (layout_index << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); } /* If an industry has been built, just reset the cursor and the system */ if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } - virtual void OnGameTick() + void OnGameTick() override { if (!this->timer_enabled) return; if (--this->callback_timer == 0) { @@ -729,12 +729,12 @@ public: } } - virtual void OnTimeout() + void OnTimeout() override { this->RaiseWidget(WID_DPI_FUND_WIDGET); } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->RaiseWidget(WID_DPI_FUND_WIDGET); } @@ -744,13 +744,13 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->SetupArrays(); - const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); - if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; + const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? nullptr : GetIndustrySpec(this->selected_type); + if (indsp == nullptr) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; this->SetButtons(); } @@ -843,7 +843,7 @@ public: this->InvalidateData(); } - virtual void OnPaint() + void OnPaint() override { this->DrawWidgets(); @@ -980,17 +980,17 @@ public: return y + WD_FRAMERECT_BOTTOM; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_IV_CAPTION) SetDParam(0, this->window_number); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_IV_INFO) size->height = this->info_height; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_IV_INFO: { @@ -1095,16 +1095,16 @@ public: } } - virtual void OnTimeout() + void OnTimeout() override { this->clicked_line = IL_NONE; this->clicked_button = 0; this->SetDirty(); } - virtual void OnResize() + void OnResize() override { - if (this->viewport != NULL) { + if (this->viewport != nullptr) { NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); nvp->UpdateViewportCoordinates(this); @@ -1112,7 +1112,7 @@ public: } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (StrEmpty(str)) return; @@ -1138,7 +1138,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; const Industry *i = Industry::Get(this->window_number); @@ -1150,12 +1150,12 @@ public: } } - virtual bool IsNewGRFInspectable() const + bool IsNewGRFInspectable() const override { return ::IsNewGRFInspectable(GSF_INDUSTRIES, this->window_number); } - virtual void ShowNewGRFInspectWindow() const + void ShowNewGRFInspectWindow() const override { ::ShowNewGRFInspectWindow(GSF_INDUSTRIES, this->window_number); } @@ -1263,22 +1263,22 @@ protected: void BuildSortIndustriesList() { if (this->industries.NeedRebuild()) { - this->industries.Clear(); + this->industries.clear(); const Industry *i; FOR_ALL_INDUSTRIES(i) { if (this->type_filter[i->type]){ - *this->industries.Append() = i; + this->industries.push_back(i); } } - this->industries.Compact(); + this->industries.shrink_to_fit(); this->industries.RebuildDone(); - this->vscroll->SetCount(this->industries.Length()); // Update scrollbar as well. + this->vscroll->SetCount((uint)this->industries.size()); // Update scrollbar as well. } if (!this->industries.Sort()) return; - IndustryDirectoryWindow::last_industry = NULL; // Reset name sorter sort cache + IndustryDirectoryWindow::last_industry = nullptr; // Reset name sorter sort cache this->SetWidgetDirty(WID_ID_INDUSTRY_LIST); // Set the modified widget dirty } @@ -1315,52 +1315,52 @@ protected: } /** Sort industries by name */ - static int CDECL IndustryNameSorter(const Industry * const *a, const Industry * const *b) + static bool IndustryNameSorter(const Industry * const &a, const Industry * const &b) { static char buf_cache[96]; static char buf[96]; - SetDParam(0, (*a)->index); + SetDParam(0, a->index); GetString(buf, STR_INDUSTRY_NAME, lastof(buf)); - if (*b != last_industry) { - last_industry = *b; - SetDParam(0, (*b)->index); + if (b != last_industry) { + last_industry = b; + SetDParam(0, b->index); GetString(buf_cache, STR_INDUSTRY_NAME, lastof(buf_cache)); } - return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). + return strnatcmp(buf, buf_cache) < 0; // Sort by name (natural sorting). } /** Sort industries by type and name */ - static int CDECL IndustryTypeSorter(const Industry * const *a, const Industry * const *b) + static bool IndustryTypeSorter(const Industry * const &a, const Industry * const &b) { int it_a = 0; - while (it_a != NUM_INDUSTRYTYPES && (*a)->type != _sorted_industry_types[it_a]) it_a++; + while (it_a != NUM_INDUSTRYTYPES && a->type != _sorted_industry_types[it_a]) it_a++; int it_b = 0; - while (it_b != NUM_INDUSTRYTYPES && (*b)->type != _sorted_industry_types[it_b]) it_b++; + while (it_b != NUM_INDUSTRYTYPES && b->type != _sorted_industry_types[it_b]) it_b++; int r = it_a - it_b; - return (r == 0) ? IndustryNameSorter(a, b) : r; + return (r == 0) ? IndustryNameSorter(a, b) : r < 0; } /** Sort industries by production and name */ - static int CDECL IndustryProductionSorter(const Industry * const *a, const Industry * const *b) + static bool IndustryProductionSorter(const Industry * const &a, const Industry * const &b) { uint prod_a = 0, prod_b = 0; - for (uint i = 0; i < lengthof((*a)->produced_cargo); i++) { - if ((*a)->produced_cargo[i] != CT_INVALID) prod_a += (*a)->last_month_production[i]; - if ((*b)->produced_cargo[i] != CT_INVALID) prod_b += (*b)->last_month_production[i]; + for (uint i = 0; i < lengthof(a->produced_cargo); i++) { + if (a->produced_cargo[i] != CT_INVALID) prod_a += a->last_month_production[i]; + if (b->produced_cargo[i] != CT_INVALID) prod_b += b->last_month_production[i]; } int r = prod_a - prod_b; - return (r == 0) ? IndustryTypeSorter(a, b) : r; + return (r == 0) ? IndustryTypeSorter(a, b) : r < 0; } /** Sort industries by transported cargo and name */ - static int CDECL IndustryTransportedCargoSorter(const Industry * const *a, const Industry * const *b) + static bool IndustryTransportedCargoSorter(const Industry * const &a, const Industry * const &b) { - int r = GetCargoTransportedSortValue(*a) - GetCargoTransportedSortValue(*b); - return (r == 0) ? IndustryNameSorter(a, b) : r; + int r = GetCargoTransportedSortValue(a) - GetCargoTransportedSortValue(b); + return (r == 0) ? IndustryNameSorter(a, b) : r < 0; } /** @@ -1428,12 +1428,12 @@ public: this->last_sorting = this->industries.GetListing(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_ID_DROPDOWN_CRITERIA) SetDParam(0, IndustryDirectoryWindow::sorter_names[this->industries.SortType()]); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_ID_DROPDOWN_ORDER: @@ -1443,11 +1443,11 @@ public: case WID_ID_INDUSTRY_LIST: { int n = 0; int y = r.top + WD_FRAMERECT_TOP; - if (this->industries.Length() == 0) { + if (this->industries.size() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); break; } - for (uint i = this->vscroll->GetPosition(); i < this->industries.Length(); i++) { + for (uint i = this->vscroll->GetPosition(); i < this->industries.size(); i++) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, this->GetIndustryString(this->industries[i])); y += this->resize.step_height; @@ -1458,7 +1458,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_ID_DROPDOWN_ORDER: { @@ -1487,7 +1487,7 @@ public: case WID_ID_INDUSTRY_LIST: { Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE); - for (uint i = 0; i < this->industries.Length(); i++) { + for (uint i = 0; i < this->industries.size(); i++) { d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); } resize->height = d.height; @@ -1501,7 +1501,7 @@ public: } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_ID_DROPDOWN_ORDER: @@ -1514,24 +1514,25 @@ public: break; case WID_ID_DROPDOWN_FILTER: { - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_ALL, -2, false); - *list->Append() = new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_NONE, -1, false); - *list->Append() = new DropDownListItem(-3, false); + DropDownList lst; + + lst.emplace_back(new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_ALL, -2, false)); + lst.emplace_back(new DropDownListStringItem(STR_BUTTON_FILTER_SELECT_NONE, -1, false)); + lst.emplace_back(new DropDownListItem(-3, false)); for (IndustryType indt = 0; indt < NUM_INDUSTRYTYPES; ++indt) { const IndustrySpec *inds = GetIndustrySpec(indt); if (inds->enabled) - *list->Append() = new DropDownListCheckedItem(inds->name, indt, false, IndustryDirectoryWindow::type_filter[indt]); + lst.emplace_back(new DropDownListCheckedItem(inds->name, indt, false, IndustryDirectoryWindow::type_filter[indt])); } - ShowDropDownList(this, list, -2, WID_ID_DROPDOWN_FILTER, 0, true, false); + ShowDropDownList(this, std::move(lst), -2, WID_ID_DROPDOWN_FILTER, 0, true, false); break; } case WID_ID_INDUSTRY_LIST: { uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP); - if (p < this->industries.Length()) { + if (p < this->industries.size()) { if (_ctrl_pressed) { ShowExtraViewPortWindow(this->industries[p]->location.tile); } else { @@ -1543,7 +1544,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (widget == WID_ID_DROPDOWN_CRITERIA) { if (this->industries.SortType() != index) { @@ -1568,18 +1569,18 @@ public: this->BuildSortIndustriesList(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); } - virtual void OnPaint() + void OnPaint() override { if (this->industries.NeedRebuild()) this->BuildSortIndustriesList(); this->DrawWidgets(); } - virtual void OnHundredthTick() + void OnHundredthTick() override { this->industries.ForceResort(); this->BuildSortIndustriesList(); @@ -1590,7 +1591,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ @@ -1602,7 +1603,7 @@ public: }; Listing IndustryDirectoryWindow::last_sorting = {false, 0}; -const Industry *IndustryDirectoryWindow::last_industry = NULL; +const Industry *IndustryDirectoryWindow::last_industry = nullptr; bool IndustryDirectoryWindow::initialized = false; bool IndustryDirectoryWindow::type_filter[NUM_INDUSTRYTYPES]; @@ -2009,8 +2010,8 @@ struct CargoesField { /** * Decide which cargo was clicked at in a #CFT_CARGO field. - * @param left Left industry neighbour if available (else \c NULL should be supplied). - * @param right Right industry neighbour if available (else \c NULL should be supplied). + * @param left Left industry neighbour if available (else \c nullptr should be supplied). + * @param right Right industry neighbour if available (else \c nullptr should be supplied). * @param pt Click position in the cargo field. * @return Cargo clicked at, or #INVALID_CARGO if none. */ @@ -2040,7 +2041,7 @@ struct CargoesField { /* row = 0 -> at first horizontal row, row = 1 -> second horizontal row, 2 = 3rd horizontal row. */ if (col == 0) { if (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]]; - if (left != NULL) { + if (left != nullptr) { if (left->type == CFT_INDUSTRY) return left->u.industry.other_produced[row]; if (left->type == CFT_CARGO_LABEL && !left->u.cargo_label.left_align) return left->u.cargo_label.cargoes[row]; } @@ -2048,7 +2049,7 @@ struct CargoesField { } if (col == this->u.cargo.num_cargoes) { if (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]]; - if (right != NULL) { + if (right != nullptr) { if (right->type == CFT_INDUSTRY) return right->u.industry.other_accepted[row]; if (right->type == CFT_CARGO_LABEL && right->u.cargo_label.left_align) return right->u.cargo_label.cargoes[row]; } @@ -2266,7 +2267,7 @@ next_cargo: ; struct IndustryCargoesWindow : public Window { static const int HOR_TEXT_PADDING, VERT_TEXT_PADDING; - typedef SmallVector Fields; + typedef std::vector Fields; Fields fields; ///< Fields to display in the #WID_IC_PANEL. uint ind_cargo; ///< If less than #NUM_INDUSTRYTYPES, an industry type, else a cargo id + NUM_INDUSTRYTYPES. @@ -2283,7 +2284,7 @@ struct IndustryCargoesWindow : public Window { this->OnInvalidateData(id); } - virtual void OnInit() + void OnInit() override { /* Initialize static CargoesField size variables. */ Dimension d = GetStringBoundingBox(STR_INDUSTRY_CARGOES_PRODUCERS); @@ -2330,7 +2331,7 @@ struct IndustryCargoesWindow : public Window { CargoesField::cargo_field_width = CargoesField::HOR_CARGO_BORDER_SPACE * 2 + CargoesField::HOR_CARGO_WIDTH * CargoesField::max_cargoes + CargoesField::HOR_CARGO_SPACE * (CargoesField::max_cargoes - 1); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_IC_PANEL: @@ -2349,7 +2350,7 @@ struct IndustryCargoesWindow : public Window { CargoesFieldType type; ///< Type of field. - virtual void SetStringParameters (int widget) const + void SetStringParameters (int widget) const override { if (widget != WID_IC_CAPTION) return; @@ -2525,13 +2526,14 @@ struct IndustryCargoesWindow : public Window { _displayed_industries.reset(); _displayed_industries.set(it); - this->fields.Clear(); - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); - row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[2].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[4].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); + this->fields.clear(); + /*C++17: CargoesRow &row = */ this->fields.emplace_back(); + CargoesRow &row = this->fields.back(); + row.columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); + row.columns[1].MakeEmpty(CFT_SMALL_EMPTY); + row.columns[2].MakeEmpty(CFT_SMALL_EMPTY); + row.columns[3].MakeEmpty(CFT_SMALL_EMPTY); + row.columns[4].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); const IndustrySpec *central_sp = GetIndustrySpec(it); bool houses_supply = HousesCanSupply(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); @@ -2541,12 +2543,13 @@ struct IndustryCargoesWindow : public Window { int num_cust = CountMatchingAcceptingIndustries(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)) + houses_accept; int num_indrows = max(3, max(num_supp, num_cust)); // One is needed for the 'it' industry, and 2 for the cargo labels. for (int i = 0; i < num_indrows; i++) { - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeEmpty(CFT_EMPTY); - row->columns[1].MakeCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); - row->columns[2].MakeEmpty(CFT_EMPTY); - row->columns[3].MakeCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); - row->columns[4].MakeEmpty(CFT_EMPTY); + /*C++17: CargoesRow &row = */ this->fields.emplace_back(); + CargoesRow &row = this->fields.back(); + row.columns[0].MakeEmpty(CFT_EMPTY); + row.columns[1].MakeCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); + row.columns[2].MakeEmpty(CFT_EMPTY); + row.columns[3].MakeCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); + row.columns[4].MakeEmpty(CFT_EMPTY); } /* Add central industry. */ int central_row = 1 + num_indrows / 2; @@ -2603,13 +2606,14 @@ struct IndustryCargoesWindow : public Window { this->ind_cargo = cid + NUM_INDUSTRYTYPES; _displayed_industries.reset(); - this->fields.Clear(); - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); - row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[2].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); - row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); - row->columns[4].MakeEmpty(CFT_SMALL_EMPTY); + this->fields.clear(); + /*C++17: CargoesRow &row = */ this->fields.emplace_back(); + CargoesRow &row = this->fields.back(); + row.columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); + row.columns[1].MakeEmpty(CFT_SMALL_EMPTY); + row.columns[2].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); + row.columns[3].MakeEmpty(CFT_SMALL_EMPTY); + row.columns[4].MakeEmpty(CFT_SMALL_EMPTY); bool houses_supply = HousesCanSupply(&cid, 1); bool houses_accept = HousesCanAccept(&cid, 1); @@ -2617,12 +2621,13 @@ struct IndustryCargoesWindow : public Window { int num_cust = CountMatchingAcceptingIndustries(&cid, 1) + houses_accept; int num_indrows = max(num_supp, num_cust); for (int i = 0; i < num_indrows; i++) { - CargoesRow *row = this->fields.Append(); - row->columns[0].MakeEmpty(CFT_EMPTY); - row->columns[1].MakeCargo(&cid, 1); - row->columns[2].MakeEmpty(CFT_EMPTY); - row->columns[3].MakeEmpty(CFT_EMPTY); - row->columns[4].MakeEmpty(CFT_EMPTY); + /*C++17: CargoesRow &row = */ this->fields.emplace_back(); + CargoesRow &row = this->fields.back(); + row.columns[0].MakeEmpty(CFT_EMPTY); + row.columns[1].MakeCargo(&cid, 1); + row.columns[2].MakeEmpty(CFT_EMPTY); + row.columns[3].MakeEmpty(CFT_EMPTY); + row.columns[4].MakeEmpty(CFT_EMPTY); } this->fields[num_indrows].MakeCargoLabel(0, false); // Add cargo labels at the left bottom. @@ -2668,7 +2673,7 @@ struct IndustryCargoesWindow : public Window { * - data = NUM_INDUSTRYTYPES: Stop sending updates to the smallmap window. * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (data == NUM_INDUSTRYTYPES) { @@ -2683,7 +2688,7 @@ struct IndustryCargoesWindow : public Window { this->ComputeIndustryDisplay(data); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_IC_PANEL) return; @@ -2700,7 +2705,7 @@ struct IndustryCargoesWindow : public Window { const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); int vpos = -this->vscroll->GetPosition() * nwp->resize_y; - for (uint i = 0; i < this->fields.Length(); i++) { + for (uint i = 0; i < this->fields.size(); i++) { int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height; if (vpos + row_height >= 0) { int xpos = left_pos; @@ -2742,7 +2747,7 @@ struct IndustryCargoesWindow : public Window { if (pt.y < vpos) return false; int row = (pt.y - vpos) / CargoesField::normal_height; // row is relative to row 1. - if (row + 1 >= (int)this->fields.Length()) return false; + if (row + 1 >= (int)this->fields.size()) return false; vpos = pt.y - vpos - row * CargoesField::normal_height; // Position in the row + 1 field row++; // rebase row to match index of this->fields. @@ -2771,7 +2776,7 @@ struct IndustryCargoesWindow : public Window { return true; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_IC_PANEL: { @@ -2785,8 +2790,8 @@ struct IndustryCargoesWindow : public Window { break; case CFT_CARGO: { - CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; - CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; + CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : nullptr; + CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : nullptr; CargoID cid = fld->CargoClickedAt(lft, rgt, xy); if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); break; @@ -2810,46 +2815,41 @@ struct IndustryCargoesWindow : public Window { if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); if (this->IsWidgetLowered(WID_IC_NOTIFY)) { - if (FindWindowByClass(WC_SMALLMAP) == NULL) ShowSmallMap(); + if (FindWindowByClass(WC_SMALLMAP) == nullptr) ShowSmallMap(); this->NotifySmallmap(); } break; case WID_IC_CARGO_DROPDOWN: { - DropDownList *lst = new DropDownList; + DropDownList lst; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { - *lst->Append() = new DropDownListStringItem(cs->name, cs->Index(), false); + lst.emplace_back(new DropDownListStringItem(cs->name, cs->Index(), false)); } - if (lst->Length() == 0) { - delete lst; - break; + if (!lst.empty()) { + int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; + ShowDropDownList(this, std::move(lst), selected, WID_IC_CARGO_DROPDOWN, 0, true); } - int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; - ShowDropDownList(this, lst, selected, WID_IC_CARGO_DROPDOWN, 0, true); break; } case WID_IC_IND_DROPDOWN: { - DropDownList *lst = new DropDownList; - for (uint i = 0; i < NUM_INDUSTRYTYPES; i++) { - IndustryType ind = _sorted_industry_types[i]; + DropDownList lst; + for (IndustryType ind : _sorted_industry_types) { const IndustrySpec *indsp = GetIndustrySpec(ind); if (!indsp->enabled) continue; - *lst->Append() = new DropDownListStringItem(indsp->name, ind, false); + lst.emplace_back(new DropDownListStringItem(indsp->name, ind, false)); } - if (lst->Length() == 0) { - delete lst; - break; + if (!lst.empty()) { + int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? (int)this->ind_cargo : -1; + ShowDropDownList(this, std::move(lst), selected, WID_IC_IND_DROPDOWN, 0, true); } - int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? (int)this->ind_cargo : -1; - ShowDropDownList(this, lst, selected, WID_IC_IND_DROPDOWN, 0, true); break; } } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (index < 0) return; @@ -2864,7 +2864,7 @@ struct IndustryCargoesWindow : public Window { } } - bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) + bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override { if (widget != WID_IC_PANEL) return false; @@ -2875,8 +2875,8 @@ struct IndustryCargoesWindow : public Window { CargoID cid = INVALID_CARGO; switch (fld->type) { case CFT_CARGO: { - CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; - CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; + CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : nullptr; + CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : nullptr; cid = fld->CargoClickedAt(lft, rgt, xy); break; } @@ -2888,7 +2888,7 @@ struct IndustryCargoesWindow : public Window { case CFT_INDUSTRY: if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES && (this->ind_cargo >= NUM_INDUSTRYTYPES || fieldxy.x != 2)) { - GuiShowTooltips(this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, close_cond); + GuiShowTooltips(this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, nullptr, close_cond); } return true; @@ -2906,7 +2906,7 @@ struct IndustryCargoesWindow : public Window { return false; } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_IC_PANEL); } @@ -2922,10 +2922,10 @@ const int IndustryCargoesWindow::VERT_TEXT_PADDING = 5; ///< Vertical padding ar static void ShowIndustryCargoesWindow(IndustryType id) { if (id >= NUM_INDUSTRYTYPES) { - for (uint i = 0; i < NUM_INDUSTRYTYPES; i++) { - const IndustrySpec *indsp = GetIndustrySpec(_sorted_industry_types[i]); + for (IndustryType ind : _sorted_industry_types) { + const IndustrySpec *indsp = GetIndustrySpec(ind); if (indsp->enabled) { - id = _sorted_industry_types[i]; + id = ind; break; } } @@ -2933,7 +2933,7 @@ static void ShowIndustryCargoesWindow(IndustryType id) } Window *w = BringWindowToFrontById(WC_INDUSTRY_CARGOES, 0); - if (w != NULL) { + if (w != nullptr) { w->InvalidateData(id); return; } diff --git a/src/industrytype.h b/src/industrytype.h index cd451fa777..c17bf795e2 100644 --- a/src/industrytype.h +++ b/src/industrytype.h @@ -12,6 +12,8 @@ #ifndef INDUSTRYTYPE_H #define INDUSTRYTYPE_H +#include +#include #include "map_type.h" #include "slope_type.h" #include "industry_type.h" @@ -22,7 +24,6 @@ enum IndustryCleanupType { CLEAN_RANDOMSOUNDS, ///< Free the dynamically allocated sounds table - CLEAN_TILELAYOUT, ///< Free the dynamically allocated tile layout structure }; /** Available types of industry lifetimes. */ @@ -92,17 +93,20 @@ enum IndustryTileSpecialFlags { }; DECLARE_ENUM_AS_BIT_SET(IndustryTileSpecialFlags) -struct IndustryTileTable { +/** Definition of one tile in an industry tile layout */ +struct IndustryTileLayoutTile { TileIndexDiffC ti; IndustryGfx gfx; }; +/** A complete tile layout for an industry is a list of tiles */ +using IndustryTileLayout = std::vector; + /** * Defines the data structure for constructing industry. */ struct IndustrySpec { - const IndustryTileTable * const *table; ///< List of the tiles composing the industry - byte num_table; ///< Number of elements in the table + std::vector layouts; ///< List of possible tile layouts for the industry uint8 cost_multiplier; ///< Base construction cost multiplier. uint32 removal_cost_multiplier; ///< Base removal cost multiplier. uint32 prospecting_chance; ///< Chance prospecting succeeds @@ -142,6 +146,8 @@ struct IndustrySpec { Money GetConstructionCost() const; Money GetRemovalCost() const; bool UsesSmoothEconomy() const; + + ~IndustrySpec(); }; /** @@ -179,7 +185,7 @@ extern IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES]; /* industry_gui.cpp */ void SortIndustryTypes(); /* Industry types sorted alphabetically by name. */ -extern IndustryType _sorted_industry_types[NUM_INDUSTRYTYPES]; +extern std::array _sorted_industry_types; /** * Do industry gfx ID translation for NewGRFs. diff --git a/src/ini.cpp b/src/ini.cpp index 6767d8525d..05ddc0386e 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -29,7 +29,7 @@ /** * Create a new ini file with given group names. - * @param list_group_names A \c NULL terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST + * @param list_group_names A \c nullptr terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST */ IniFile::IniFile(const char * const *list_group_names) : IniLoadFile(list_group_names) { @@ -52,23 +52,23 @@ bool IniFile::SaveToDisk(const char *filename) strecpy(file_new, filename, lastof(file_new)); strecat(file_new, ".new", lastof(file_new)); FILE *f = fopen(file_new, "w"); - if (f == NULL) return false; + if (f == nullptr) return false; - for (const IniGroup *group = this->group; group != NULL; group = group->next) { + for (const IniGroup *group = this->group; group != nullptr; group = group->next) { if (group->comment) fputs(group->comment, f); fprintf(f, "[%s]\n", group->name); - for (const IniItem *item = group->item; item != NULL; item = item->next) { - if (item->comment != NULL) fputs(item->comment, f); + for (const IniItem *item = group->item; item != nullptr; item = item->next) { + if (item->comment != nullptr) fputs(item->comment, f); /* protect item->name with quotes if needed */ - if (strchr(item->name, ' ') != NULL || + if (strchr(item->name, ' ') != nullptr || item->name[0] == '[') { fprintf(f, "\"%s\"", item->name); } else { fprintf(f, "%s", item->name); } - fprintf(f, " = %s\n", item->value == NULL ? "" : item->value); + fprintf(f, " = %s\n", item->value == nullptr ? "" : item->value); } } if (this->comment) fputs(this->comment, f); diff --git a/src/ini_load.cpp b/src/ini_load.cpp index 389dcab031..5980b459d3 100644 --- a/src/ini_load.cpp +++ b/src/ini_load.cpp @@ -23,7 +23,7 @@ * @param name the name of the item * @param last the last element of the name of the item */ -IniItem::IniItem(IniGroup *parent, const char *name, const char *last) : next(NULL), value(NULL), comment(NULL) +IniItem::IniItem(IniGroup *parent, const char *name, const char *last) : next(nullptr), value(nullptr), comment(nullptr) { this->name = stredup(name, last); str_validate(this->name, this->name + strlen(this->name)); @@ -58,7 +58,7 @@ void IniItem::SetValue(const char *value) * @param name the name of the group * @param last the last element of the name of the group */ -IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : next(NULL), type(IGT_VARIABLES), item(NULL), comment(NULL) +IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : next(nullptr), type(IGT_VARIABLES), item(nullptr), comment(nullptr) { this->name = stredup(name, last); str_validate(this->name, this->name + strlen(this->name)); @@ -67,16 +67,16 @@ IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : ne *parent->last_group = this; parent->last_group = &this->next; - if (parent->list_group_names != NULL) { - for (uint i = 0; parent->list_group_names[i] != NULL; i++) { + if (parent->list_group_names != nullptr) { + for (uint i = 0; parent->list_group_names[i] != nullptr; i++) { if (strcmp(this->name, parent->list_group_names[i]) == 0) { this->type = IGT_LIST; return; } } } - if (parent->seq_group_names != NULL) { - for (uint i = 0; parent->seq_group_names[i] != NULL; i++) { + if (parent->seq_group_names != nullptr) { + for (uint i = 0; parent->seq_group_names[i] != nullptr; i++) { if (strcmp(this->name, parent->seq_group_names[i]) == 0) { this->type = IGT_SEQUENCE; return; @@ -100,18 +100,18 @@ IniGroup::~IniGroup() * and create is true it creates a new item. * @param name name of the item to find. * @param create whether to create an item when not found or not. - * @return the requested item or NULL if not found. + * @return the requested item or nullptr if not found. */ IniItem *IniGroup::GetItem(const char *name, bool create) { - for (IniItem *item = this->item; item != NULL; item = item->next) { + for (IniItem *item = this->item; item != nullptr; item = item->next) { if (strcmp(item->name, name) == 0) return item; } - if (!create) return NULL; + if (!create) return nullptr; /* otherwise make a new one */ - return new IniItem(this, name, NULL); + return new IniItem(this, name, nullptr); } /** @@ -120,18 +120,18 @@ IniItem *IniGroup::GetItem(const char *name, bool create) void IniGroup::Clear() { delete this->item; - this->item = NULL; + this->item = nullptr; this->last_item = &this->item; } /** * Construct a new in-memory Ini file representation. - * @param list_group_names A \c NULL terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST - * @param seq_group_names A \c NULL terminated list with group names that should be loaded as lists of names. @see IGT_SEQUENCE + * @param list_group_names A \c nullptr terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST + * @param seq_group_names A \c nullptr terminated list with group names that should be loaded as lists of names. @see IGT_SEQUENCE */ IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * const *seq_group_names) : - group(NULL), - comment(NULL), + group(nullptr), + comment(nullptr), list_group_names(list_group_names), seq_group_names(seq_group_names) { @@ -151,20 +151,20 @@ IniLoadFile::~IniLoadFile() * @param name name of the group to find. * @param len the maximum length of said name (\c 0 means length of the string). * @param create_new Allow creation of group if it does not exist. - * @return The requested group if it exists or was created, else \c NULL. + * @return The requested group if it exists or was created, else \c nullptr. */ IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new) { if (len == 0) len = strlen(name); /* does it exist already? */ - for (IniGroup *group = this->group; group != NULL; group = group->next) { + for (IniGroup *group = this->group; group != nullptr; group = group->next) { if (!strncmp(group->name, name, len) && group->name[len] == 0) { return group; } } - if (!create_new) return NULL; + if (!create_new) return nullptr; /* otherwise make a new one */ IniGroup *group = new IniGroup(this, name, name + len - 1); @@ -179,19 +179,19 @@ IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new) void IniLoadFile::RemoveGroup(const char *name) { size_t len = strlen(name); - IniGroup *prev = NULL; + IniGroup *prev = nullptr; IniGroup *group; /* does it exist already? */ - for (group = this->group; group != NULL; prev = group, group = group->next) { + for (group = this->group; group != nullptr; prev = group, group = group->next) { if (strncmp(group->name, name, len) == 0) { break; } } - if (group == NULL) return; + if (group == nullptr) return; - if (prev != NULL) { + if (prev != nullptr) { prev->next = prev->next->next; if (this->last_group == &group->next) this->last_group = &prev->next; } else { @@ -199,7 +199,7 @@ void IniLoadFile::RemoveGroup(const char *name) if (this->last_group == &group->next) this->last_group = &this->group; } - group->next = NULL; + group->next = nullptr; delete group; } @@ -214,15 +214,15 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) assert(this->last_group == &this->group); char buffer[1024]; - IniGroup *group = NULL; + IniGroup *group = nullptr; - char *comment = NULL; + char *comment = nullptr; uint comment_size = 0; uint comment_alloc = 0; size_t end; FILE *in = this->OpenFile(filename, subdir, &end); - if (in == NULL) return; + if (in == nullptr) return; end += ftell(in); @@ -238,7 +238,7 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) *e = '\0'; /* Skip comments and empty lines outside IGT_SEQUENCE groups. */ - if ((group == NULL || group->type != IGT_SEQUENCE) && (*s == '#' || *s == ';' || *s == '\0')) { + if ((group == nullptr || group->type != IGT_SEQUENCE) && (*s == '#' || *s == ';' || *s == '\0')) { uint ns = comment_size + (e - s + 1); uint a = comment_alloc; /* add to comment */ @@ -267,7 +267,7 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) group->comment = stredup(comment, comment + comment_size - 1); comment_size = 0; } - } else if (group != NULL) { + } else if (group != nullptr) { if (group->type == IGT_SEQUENCE) { /* A sequence group, use the line as item name without further interpretation. */ IniItem *item = new IniItem(group, buffer, e - 1); @@ -305,9 +305,9 @@ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) if (e > t && e[-1] == '\"') e--; *e = '\0'; - /* If the value was not quoted and empty, it must be NULL */ - item->value = (!quoted && e == t) ? NULL : stredup(t); - if (item->value != NULL) str_validate(item->value, item->value + strlen(item->value)); + /* If the value was not quoted and empty, it must be nullptr */ + item->value = (!quoted && e == t) ? nullptr : stredup(t); + if (item->value != nullptr) str_validate(item->value, item->value + strlen(item->value)); } else { /* it's an orphan item */ this->ReportFileError("ini: '", buffer, "' outside of group"); diff --git a/src/ini_type.h b/src/ini_type.h index 9bd47fd4e5..a2ff765020 100644 --- a/src/ini_type.h +++ b/src/ini_type.h @@ -28,7 +28,7 @@ struct IniItem { char *value; ///< The value of this item char *comment; ///< The comment associated with this item - IniItem(struct IniGroup *parent, const char *name, const char *last = NULL); + IniItem(struct IniGroup *parent, const char *name, const char *last = nullptr); ~IniItem(); void SetValue(const char *value); @@ -43,7 +43,7 @@ struct IniGroup { char *name; ///< name of group char *comment; ///< comment for group - IniGroup(struct IniLoadFile *parent, const char *name, const char *last = NULL); + IniGroup(struct IniLoadFile *parent, const char *name, const char *last = nullptr); ~IniGroup(); IniItem *GetItem(const char *name, bool create); @@ -55,10 +55,10 @@ struct IniLoadFile { IniGroup *group; ///< the first group in the ini IniGroup **last_group; ///< the last group in the ini char *comment; ///< last comment in file - const char * const *list_group_names; ///< NULL terminated list with group names that are lists - const char * const *seq_group_names; ///< NULL terminated list with group names that are sequences. + const char * const *list_group_names; ///< nullptr terminated list with group names that are lists + const char * const *seq_group_names; ///< nullptr terminated list with group names that are sequences. - IniLoadFile(const char * const *list_group_names = NULL, const char * const *seq_group_names = NULL); + IniLoadFile(const char * const *list_group_names = nullptr, const char * const *seq_group_names = nullptr); virtual ~IniLoadFile(); IniGroup *GetGroup(const char *name, size_t len = 0, bool create_new = true); @@ -71,7 +71,7 @@ struct IniLoadFile { * @param filename Name of the INI file. * @param subdir The subdir to load the file from. * @param[out] size Size of the opened file. - * @return File handle of the opened file, or \c NULL. + * @return File handle of the opened file, or \c nullptr. */ virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size) = 0; @@ -86,7 +86,7 @@ struct IniLoadFile { /** Ini file that supports both loading and saving. */ struct IniFile : IniLoadFile { - IniFile(const char * const *list_group_names = NULL); + IniFile(const char * const *list_group_names = nullptr); bool SaveToDisk(const char *filename); diff --git a/src/intro_gui.cpp b/src/intro_gui.cpp index 3659b033cf..804ada8d75 100644 --- a/src/intro_gui.cpp +++ b/src/intro_gui.cpp @@ -49,7 +49,7 @@ struct SelectGameWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->SetWidgetLoweredState(WID_SGI_TEMPERATE_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); @@ -58,7 +58,7 @@ struct SelectGameWindow : public Window { this->SetWidgetLoweredState(WID_SGI_TOYLAND_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TOYLAND); } - virtual void OnInit() + void OnInit() override { bool missing_sprites = _missing_extra_graphics > 0 && !IsReleasedVersion(); this->GetWidget(WID_SGI_BASESET_SELECTION)->SetDisplayedPlane(missing_sprites ? 0 : SZSP_NONE); @@ -67,7 +67,7 @@ struct SelectGameWindow : public Window { this->GetWidget(WID_SGI_TRANSLATION_SELECTION)->SetDisplayedPlane(missing_lang ? 0 : SZSP_NONE); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SGI_BASESET: @@ -82,7 +82,7 @@ struct SelectGameWindow : public Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { StringID str = 0; switch (widget) { @@ -111,13 +111,11 @@ struct SelectGameWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { -#ifdef ENABLE_NETWORK /* Do not create a network server when you (just) have closed one of the game * creation/load windows for the network server. */ if (IsInsideMM(widget, WID_SGI_GENERATE_GAME, WID_SGI_EDIT_SCENARIO + 1)) _is_network_server = false; -#endif /* ENABLE_NETWORK */ switch (widget) { case WID_SGI_GENERATE_GAME: @@ -271,7 +269,7 @@ static const NWidgetPart _nested_select_game_widgets[] = { }; static WindowDesc _select_game_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_SELECT_GAME, WC_NONE, 0, _nested_select_game_widgets, lengthof(_nested_select_game_widgets) @@ -293,27 +291,19 @@ void AskExitGame() SetDParam(0, STR_OSNAME_WINDOWS); #elif defined(__APPLE__) SetDParam(0, STR_OSNAME_OSX); -#elif defined(__BEOS__) - SetDParam(0, STR_OSNAME_BEOS); #elif defined(__HAIKU__) SetDParam(0, STR_OSNAME_HAIKU); -#elif defined(__MORPHOS__) - SetDParam(0, STR_OSNAME_MORPHOS); -#elif defined(__AMIGA__) - SetDParam(0, STR_OSNAME_AMIGAOS); #elif defined(__OS2__) SetDParam(0, STR_OSNAME_OS2); #elif defined(SUNOS) SetDParam(0, STR_OSNAME_SUNOS); -#elif defined(DOS) - SetDParam(0, STR_OSNAME_DOS); #else SetDParam(0, STR_OSNAME_UNIX); #endif ShowQuery( STR_QUIT_CAPTION, STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD, - NULL, + nullptr, AskExitGameCallback ); } @@ -332,7 +322,7 @@ void AskExitToGameMenu() ShowQuery( STR_ABANDON_GAME_CAPTION, (_game_mode != GM_EDITOR) ? STR_ABANDON_GAME_QUERY : STR_ABANDON_SCENARIO_QUERY, - NULL, + nullptr, AskExitToGameMenuCallback ); } diff --git a/src/landscape.cpp b/src/landscape.cpp index b36f5c8842..0d5df5f874 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -82,12 +82,12 @@ extern const byte _slope_to_sprite_offset[32] = { /** * Description of the snow line throughout the year. * - * If it is \c NULL, a static snowline height is used, as set by \c _settings_game.game_creation.snow_line_height. + * If it is \c nullptr, a static snowline height is used, as set by \c _settings_game.game_creation.snow_line_height. * Otherwise it points to a table loaded from a newGRF file that describes the variable snowline. * @ingroup SnowLineGroup * @see GetSnowLine() GameCreationSettings */ -static SnowLine *_snow_line = NULL; +static SnowLine *_snow_line = nullptr; /** * Map 2D viewport or smallmap coordinate to 3D world or tile coordinate. @@ -104,7 +104,7 @@ static SnowLine *_snow_line = NULL; */ Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped) { - if (clamped != NULL) *clamped = false; // Not clamping yet. + if (clamped != nullptr) *clamped = false; // Not clamping yet. /* Initial x/y world coordinate is like if the landscape * was completely flat on height 0. */ @@ -122,7 +122,7 @@ Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped) Point old_pt = pt; pt.x = Clamp(pt.x, -extra_tiles * TILE_SIZE, max_x); pt.y = Clamp(pt.y, -extra_tiles * TILE_SIZE, max_y); - if (clamped != NULL) *clamped = (pt.x != old_pt.x) || (pt.y != old_pt.y); + if (clamped != nullptr) *clamped = (pt.x != old_pt.x) || (pt.y != old_pt.y); } /* Now find the Z-world coordinate by fix point iteration. @@ -147,7 +147,7 @@ Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped) Point old_pt = pt; pt.x = Clamp(pt.x, min_coord, max_x); pt.y = Clamp(pt.y, min_coord, max_y); - if (clamped != NULL) *clamped = *clamped || (pt.x != old_pt.x) || (pt.y != old_pt.y); + if (clamped != nullptr) *clamped = *clamped || (pt.x != old_pt.x) || (pt.y != old_pt.y); } return pt; @@ -352,8 +352,8 @@ int GetSlopePixelZ(int x, int y) * Return world \c z coordinate of a given point of a tile, * also for tiles outside the map (virtual "black" tiles). * - * @param x World X coordinate in tile "units", may be ouside the map. - * @param y World Y coordinate in tile "units", may be ouside the map. + * @param x World X coordinate in tile "units", may be outside the map. + * @param y World Y coordinate in tile "units", may be outside the map. * @return World Z coordinate at tile ground level, including slopes and foundations. */ int GetSlopePixelZOutsideMap(int x, int y) @@ -418,7 +418,7 @@ void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2) * If a tile does not have a foundation, the function returns the same as GetTileSlope. * * @param tile The tile of interest. - * @param z returns the z of the foundation slope. (Can be NULL, if not needed) + * @param z returns the z of the foundation slope. (Can be nullptr, if not needed) * @return The slope on top of the foundation. */ Slope GetFoundationSlope(TileIndex tile, int *z) @@ -426,7 +426,7 @@ Slope GetFoundationSlope(TileIndex tile, int *z) Slope tileh = GetTileSlope(tile, z); Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh); uint z_inc = ApplyFoundationToSlope(f, &tileh); - if (z != NULL) *z += z_inc; + if (z != nullptr) *z += z_inc; return tileh; } @@ -572,7 +572,7 @@ void DrawFoundation(TileInfo *ti, Foundation f) void DoClearSquare(TileIndex tile) { /* If the tile can have animation and we clear it, delete it from the animated tile list. */ - if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile); + if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != nullptr) DeleteAnimatedTile(tile); MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0); MarkTileDirtyByTile(tile); @@ -616,7 +616,7 @@ void GetTileDesc(TileIndex tile, TileDesc *td) */ bool IsSnowLineSet() { - return _snow_line != NULL; + return _snow_line != nullptr; } /** @@ -645,7 +645,7 @@ void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]) */ byte GetSnowLine() { - if (_snow_line == NULL) return _settings_game.game_creation.snow_line_height; + if (_snow_line == nullptr) return _settings_game.game_creation.snow_line_height; YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); @@ -659,7 +659,7 @@ byte GetSnowLine() */ byte HighestSnowLine() { - return _snow_line == NULL ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value; + return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value; } /** @@ -669,7 +669,7 @@ byte HighestSnowLine() */ byte LowestSnowLine() { - return _snow_line == NULL ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value; + return _snow_line == nullptr ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value; } /** @@ -679,7 +679,7 @@ byte LowestSnowLine() void ClearSnowLine() { free(_snow_line); - _snow_line = NULL; + _snow_line = nullptr; } /** @@ -702,8 +702,8 @@ CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, ui cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]); } - Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company); - if (c != NULL && (int)GB(c->clear_limit, 16, 16) < 1) { + Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? nullptr : Company::GetIfValid(_current_company); + if (c != nullptr && (int)GB(c->clear_limit, 16, 16) < 1) { return_cmd_error(STR_ERROR_CLEARING_LIMIT_REACHED); } @@ -711,7 +711,7 @@ CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, ui /* If this tile was the first tile which caused object destruction, always * pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */ - if (coa != NULL && coa->first_tile != tile) { + if (coa != nullptr && coa->first_tile != tile) { /* If this tile belongs to an object which was already cleared via another tile, pretend it has been * already removed. * However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */ @@ -725,7 +725,7 @@ CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, ui } if (flags & DC_EXEC) { - if (c != NULL) c->clear_limit -= 1 << 16; + if (c != nullptr) c->clear_limit -= 1 << 16; if (do_clear) DoClearSquare(tile); } return cost; @@ -750,8 +750,8 @@ CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 CommandCost last_error = CMD_ERROR; bool had_success = false; - const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company); - int limit = (c == NULL ? INT32_MAX : GB(c->clear_limit, 16, 16)); + const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? nullptr : Company::GetIfValid(_current_company); + int limit = (c == nullptr ? INT32_MAX : GB(c->clear_limit, 16, 16)); TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1); for (; *iter != INVALID_TILE; ++(*iter)) { @@ -761,7 +761,7 @@ CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 last_error = ret; /* We may not clear more tiles. */ - if (c != NULL && GB(c->clear_limit, 16, 16) < 1) break; + if (c != nullptr && GB(c->clear_limit, 16, 16) < 1) break; continue; } @@ -862,7 +862,7 @@ static void GenerateTerrain(int type, uint flag) uint32 r = Random(); const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN); - if (templ == NULL) usererror("Map generator sprites could not be loaded"); + if (templ == nullptr) usererror("Map generator sprites could not be loaded"); uint x = r & MapMaxX(); uint y = (r >> MapLogX()) & MapMaxY(); @@ -1065,7 +1065,7 @@ static bool MakeLake(TileIndex tile, void *user_data) MakeRiver(tile, Random()); /* Remove desert directly around the river tile. */ TileIndex t = tile; - CircularTileSearch(&t, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, NULL); + CircularTileSearch(&t, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr); return false; } } @@ -1132,12 +1132,12 @@ static void River_GetNeighbours(AyStar *aystar, OpenListNode *current) /* AyStar callback when an route has been found. */ static void River_FoundEndNode(AyStar *aystar, OpenListNode *current) { - for (PathNode *path = ¤t->path; path != NULL; path = path->parent) { + for (PathNode *path = ¤t->path; path != nullptr; path = path->parent) { TileIndex tile = path->node.tile; if (!IsWaterTile(tile)) { MakeRiver(tile, Random()); /* Remove desert directly around the river tile. */ - CircularTileSearch(&tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, NULL); + CircularTileSearch(&tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr); } } } @@ -1249,7 +1249,7 @@ static bool FlowRiver(TileIndex spring, TileIndex begin) end = lakeCenter; MakeRiver(lakeCenter, Random()); /* Remove desert directly around the river tile. */ - CircularTileSearch(&lakeCenter, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, NULL); + CircularTileSearch(&lakeCenter, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr); lakeCenter = end; uint range = RandomRange(8) + 3; CircularTileSearch(&lakeCenter, range, MakeLake, &height); @@ -1280,7 +1280,7 @@ static void CreateRivers() IncreaseGeneratingWorldProgress(GWP_RIVER); for (int tries = 0; tries < 128; tries++) { TileIndex t = RandomTile(); - if (!CircularTileSearch(&t, 8, FindSpring, NULL)) continue; + if (!CircularTileSearch(&t, 8, FindSpring, nullptr)) continue; if (FlowRiver(t, t)) break; } } diff --git a/src/landscape.h b/src/landscape.h index 43d9e5f2e6..1209c5c1a9 100644 --- a/src/landscape.h +++ b/src/landscape.h @@ -36,7 +36,7 @@ byte LowestSnowLine(); void ClearSnowLine(); int GetSlopeZInCorner(Slope tileh, Corner corner); -Slope GetFoundationSlope(TileIndex tile, int *z = NULL); +Slope GetFoundationSlope(TileIndex tile, int *z = nullptr); uint GetPartialPixelZ(int x, int y, Slope corners); int GetSlopePixelZ(int x, int y); @@ -62,12 +62,12 @@ static inline int GetSlopePixelZInCorner(Slope tileh, Corner corner) * If a tile does not have a foundation, the function returns the same as GetTilePixelSlope. * * @param tile The tile of interest. - * @param z returns the z of the foundation slope. (Can be NULL, if not needed) + * @param z returns the z of the foundation slope. (Can be nullptr, if not needed) * @return The slope on top of the foundation. */ static inline Slope GetFoundationPixelSlope(TileIndex tile, int *z) { - assert(z != NULL); + assert(z != nullptr); Slope s = GetFoundationSlope(tile, z); *z *= TILE_HEIGHT; return s; @@ -117,7 +117,7 @@ static inline Point InverseRemapCoords(int x, int y) return pt; } -Point InverseRemapCoords2(int x, int y, bool clamp_to_map = false, bool *clamped = NULL); +Point InverseRemapCoords2(int x, int y, bool clamp_to_map = false, bool *clamped = nullptr); uint ApplyFoundationToSlope(Foundation f, Slope *s); /** diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index 3fd6ff7dae..8340207dc3 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -1685,7 +1685,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Vragver STR_CONFIG_SETTING_AI :{ORANGE}Mededingers STR_CONFIG_SETTING_AI_NPC :{ORANGE}Rekenaar spelers -STR_CONFIG_SETTING_PATHFINDER_OPF :Oorspronklik STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Aanbevole) @@ -1768,13 +1767,9 @@ STR_QUIT_NO :{BLACK}Nee # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2402,6 +2397,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Bou tonn STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Skakel bou/verwydering van pad konstruksie STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Skakel bou/verwyder vir tremweg konstruksie + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Pad Depot Oriëntering STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Kies pad voertuig depot orientasie @@ -3261,8 +3257,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spoorstukke: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seine STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Padstukke: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Pad -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tremweg STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Waterteëls: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanale STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasies: @@ -3336,6 +3330,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Ongegroepeerde STR_GROUP_DEFAULT_SHIPS :Ongegroepeerde skepe STR_GROUP_DEFAULT_AIRCRAFTS :Ongegroepeerde vliegtuig + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groepe - klik op 'n groep om alle voertuie in hierdie groep te lys. Sleep en los om te rangskik volgens hiërargie. STR_GROUP_CREATE_TOOLTIP :{BLACK}Klik om groep te skep STR_GROUP_DELETE_TOOLTIP :{BLACK}Vee uit die gekose groep @@ -3357,10 +3352,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nuwe Elektries STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nuwe monospoor voertuie STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nuwe Maglev Voertuie -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Spoorweg Voertuie STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nuwe Pad Voertuie + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Spoorweg Voertuie STR_BUY_VEHICLE_SHIP_CAPTION :Nuwe Skepe STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nuwe Vliegtuig +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Koste: {GOLD}{CURRENCY_LONG}{BLACK} Gewig: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Spoed: {GOLD}{VELOCITY}{BLACK} Krag: {GOLD}{POWER} @@ -3393,11 +3391,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Koop Voe STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Bou skip STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Koop vliegtuig + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose lokomotief/wa. Shift+klik vir kwotasie STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose voertuig. Shift+klik vir kwotasie STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose skip. Shift+klik vir kwotasie STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose vliegtuig. Shift+klik vir kwotasie + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Hernoem STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Hernoem STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Hernoem @@ -3506,13 +3506,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}U staan # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Boodskap van voertuig fabrikant STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Ons het sopas 'n nuwe {STRING} ontwerp, sal jy belangstel om hierdie voertuig eksklusief vir 'n jaar te gebruik. Hierdie word gedoen om te kyk hoe die voertuig doen voordat hy wereld wyd in produksie gesit word? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :spoorweg lokomotief -STR_ENGINE_PREVIEW_ROAD_VEHICLE :padvoertuig -STR_ENGINE_PREVIEW_AIRCRAFT :vliegtuig -STR_ENGINE_PREVIEW_SHIP :skip STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monospoor lokomotief STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev lokomotief +STR_ENGINE_PREVIEW_ROAD_VEHICLE :padvoertuig + +STR_ENGINE_PREVIEW_AIRCRAFT :vliegtuig +STR_ENGINE_PREVIEW_SHIP :skip + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Koste: {CURRENCY_LONG} Massa: {WEIGHT_SHORT}{}Spoed: {VELOCITY} Krag: {POWER}{}Loopkoste: {CURRENCY_LONG}/jr{}Kapasitiet: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Koste: {CURRENCY_LONG} Gewig: {WEIGHT_SHORT}{}Spoed: {VELOCITY} Krag: {POWER} Maks. Treg Krag: {6:FORCE}{}Lopende Koste: {4:CURRENCY_LONG}/jaar{}Kapasitiet: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Koste: {CURRENCY_LONG} Maks. Spoed: {VELOCITY}{}Kapasiteit: {CARGO_LONG}{}Lopende Koste: {CURRENCY_LONG}/jaar @@ -3553,6 +3556,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Elektriese trei STR_REPLACE_MONORAIL_VEHICLES :Monospoor voertuie STR_REPLACE_MAGLEV_VEHICLES :Maglev Voertuie + STR_REPLACE_REMOVE_WAGON :{BLACK}Wa verwydering: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Maak autovervanging die lengte van 'n trein dieselfde hou deur verwydering waens (deur voor te begin), indien die enjin vervanging die trein langer sal maak @@ -4271,7 +4275,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Moet eer STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Geen geskikte treinspoor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Moet eers spoor verwyder STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Pad is een rigting of geblok -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Vlak kruisings word nie toegelaat vir die spoor tipe nie +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Vlak kruisings word nie toegelaat vir die spoor tipe nie STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan nie seinligte hier bou nie... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan nie spore hier bou nie... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan nie spore hier verwyder nie... diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index bedfd34f9d..cb558aa3a4 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -1369,7 +1369,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :توزيع ال STR_CONFIG_SETTING_AI :{ORANGE}المتنافسين STR_CONFIG_SETTING_AI_NPC :{ORANGE} لاعبين الحاسوب -STR_CONFIG_SETTING_PATHFINDER_OPF :اصلي STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(مفضل) @@ -1440,13 +1439,9 @@ STR_QUIT_NO :{BLACK}لا # Supported OSes STR_OSNAME_WINDOWS :ويندوز -STR_OSNAME_DOS :دوس STR_OSNAME_UNIX :يونكس STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :بي او اس STR_OSNAME_HAIKU :هايكو -STR_OSNAME_MORPHOS :مورف او اس -STR_OSNAME_AMIGAOS :اميقا STR_OSNAME_OS2 :او اس/2 STR_OSNAME_SUNOS :صن @@ -2041,6 +2036,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}بناء STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}بدل بناء/إزالة الطرق STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}بدل بناء / ازالة طرق الترام + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}اتجاه ورشة الصيانة STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}اختر اتجاة ورشة صيانة العربات @@ -2865,6 +2861,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :لاتنتمي STR_GROUP_DEFAULT_SHIPS :مركبة لاتنتمي لأي مجموعة STR_GROUP_DEFAULT_AIRCRAFTS :طائرة لاتنتمي لأي مجموعة + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}المجموعات: اضغط على اي مجموعة لعرض مركباتها . اسحب للترتيب . STR_GROUP_CREATE_TOOLTIP :{BLACK}أضغط لإنشاء مجموعة STR_GROUP_DELETE_TOOLTIP :{BLACK}أحذف المجموعة المختارة @@ -2886,10 +2883,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :عربات قط STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :عربات قطار احادي جديدة STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :عربات قطار ممغنط جديدة -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :عربات قطار STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :عربات جديدة + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :عربات قطار STR_BUY_VEHICLE_SHIP_CAPTION :سفن جديدة STR_BUY_VEHICLE_AIRCRAFT_CAPTION :طائرة جديدة +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK} التكلفة: {GOLD}{CURRENCY_LONG}{BLACK} الوزن: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}السرعة: {GOLD}{VELOCITY}{BLACK} الطاقة: {GOLD}{POWER} @@ -2921,11 +2921,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}شراء STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}شراء سفينة STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}شراء طائرة + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}شراء العربة الموضحة STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}شراء العربة STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}شراء السفينة المختارة STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}اشتر الطائرة المختارة + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}اعادة تسمية STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}أعد التسمية STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}تسمية @@ -3022,13 +3024,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}أنت # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}رسالة من المصنعين STR_ENGINE_PREVIEW_MESSAGE :{GOLD}قد صممنا موديل جديد من {STRING} - هل ترغب في استخدام سنة حصري لهذه المركبة, لنستطيع تقييمها للأستخدام العام + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :قاطرة سكة حديد -STR_ENGINE_PREVIEW_ROAD_VEHICLE :مركبة -STR_ENGINE_PREVIEW_AIRCRAFT :طائرة -STR_ENGINE_PREVIEW_SHIP :سفينة STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :قاطرة سكة قطار احادية STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :قاطرة سكة قطار ممغنطة +STR_ENGINE_PREVIEW_ROAD_VEHICLE :مركبة + +STR_ENGINE_PREVIEW_AIRCRAFT :طائرة +STR_ENGINE_PREVIEW_SHIP :سفينة + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK} التكلفة: {CURRENCY_LONG} الوزن: {WEIGHT_SHORT}{} السرعة: {VELOCITY} الطاقة: {POWER}{} كلفة التشغيل: {CURRENCY_LONG} / سنة{} السعة: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}التكلفة {CURRENCY_LONG} الوزن {WEIGHT_SHORT}{}السرعة {VELOCITY} Power: {POWER}قوة السحب {6:FORCE}{}التكلفة التشغيلية {4:CURRENCY_LONG}/سنة{}السعة: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK} التكلفة {CURRENCY_LONG} السرعة القصوى {VELOCITY}{} السعة {CARGO_LONG}{} كلفة التشغيل {CURRENCY_LONG} / سنة @@ -3062,6 +3067,7 @@ STR_REPLACE_ELRAIL_VEHICLES :سكة حديد STR_REPLACE_MONORAIL_VEHICLES :عربات احادية السكة STR_REPLACE_MAGLEV_VEHICLES :مركبات ممغنطة + STR_REPLACE_REMOVE_WAGON :{BLACK} إزالة العربات: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK} المحافظة على طول القطار بازالة عربات ابتداء من المقدمة عند التبديل - عندما يكون التبدل ينتج قطارا اطول. @@ -3736,7 +3742,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}يجب STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}... مسار السكة الحديدية غير مناسب STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}يجب إزاله السكه الحديديه اولاً STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}الطريق باتجاه واحد او ربما يكون مسدوداً -STR_ERROR_CROSSING_DISALLOWED :{WHITE}التقاطع المتعدد غير متاح لهذا النوع من السكك +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}التقاطع المتعدد غير متاح لهذا النوع من السكك STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}تعذر بناء اﻹشارات هنا... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}تعذر بناء السكه الحديديه هنا... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}تعذر إزاله السكه الحديديه من هنا... diff --git a/src/lang/basque.txt b/src/lang/basque.txt index e5ea6a873b..f6d5cbeb48 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -1598,7 +1598,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Zama ba STR_CONFIG_SETTING_AI :{ORANGE}Lehiakideak STR_CONFIG_SETTING_AI_NPC :{ORANGE}Ordenagailu jokalariak -STR_CONFIG_SETTING_PATHFINDER_OPF :Jatorrizkoa STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Gomendatua) @@ -1680,13 +1679,9 @@ STR_QUIT_NO :{BLACK}Ez # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2305,6 +2300,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Tranbia STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Errepidea ezabatu STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Tranbia ezabatu + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Errepide gordailuen norabidea STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Aukeratu errepide biltokien norabidea @@ -3149,8 +3145,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Trenbide sailak: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seinaleak STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Errepide sailak: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Errepidea -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tranbia sailak STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Urbide sailak: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalak STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Geltokiak: @@ -3224,6 +3218,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Taldeetan ez da STR_GROUP_DEFAULT_SHIPS :Taldeetan ez dauden itsasontziak STR_GROUP_DEFAULT_AIRCRAFTS :Taldeetan ez dauden hegazkinak + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Taldeak - Taldean klikatu taldearen ibilgailuak zerrendatzeko STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikatu taldea sortzeko STR_GROUP_DELETE_TOOLTIP :{BLACK}Aukeratutako taldea ezabatu @@ -3244,10 +3239,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Tren elektriko STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Monorail tren berriak STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Tren magnetiko berriak -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Tren berriak STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Errepide ibilgailu berriak + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Tren berriak STR_BUY_VEHICLE_SHIP_CAPTION :Itsasontzi berriak STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Hegazkin berriak +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Kosteak: {GOLD}{CURRENCY_LONG}{BLACK} Pisua: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Abiadura: {GOLD}{VELOCITY}{BLACK} Potentzia: {GOLD}{POWER} @@ -3280,11 +3278,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Ibilgail STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Itsasontia erosi STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Hegazkina erosi + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Aukeratuta dagoen ibilgailua erosi. Shift+Klik gutxi gora beherako kostea erakutsi STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Aukeratuta dagoen ibilgailua erosi. Shift+Klik gutxi gora beherako kostea erakutsi STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Aukeratuta dagoen itsasontzia erosi. Shift+Klik gutxi gora beherako kostea erakutsi STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Aukeratuta dagoen hegazkina erosi. Shift+Klik gutxi gora beherako kostea erakutsi + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Berrizendatu STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Berrizendatu STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Berrizendatu @@ -3389,13 +3389,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Gordail # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Ibilgailu frabrikaren mezua STR_ENGINE_PREVIEW_MESSAGE :{GOLD}{STRING} berria diesinatu dugu - Nahiko zenuke ibilgailu honen urte baterako erabilera esklusiboa izatea? Bere funtzionamendua ikusi ahalko genuke publiko egin aurretik. + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :Lokomotora -STR_ENGINE_PREVIEW_ROAD_VEHICLE :Errepide ibilgailua -STR_ENGINE_PREVIEW_AIRCRAFT :Hegazkina -STR_ENGINE_PREVIEW_SHIP :Itsasontzia STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :Monorail lokomotora STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :Lokomotora magnetikoa +STR_ENGINE_PREVIEW_ROAD_VEHICLE :Errepide ibilgailua + +STR_ENGINE_PREVIEW_AIRCRAFT :Hegazkina +STR_ENGINE_PREVIEW_SHIP :Itsasontzia + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Kostea: {CURRENCY_LONG} Pisua: {WEIGHT_SHORT}{}Pisua: {VELOCITY} Potentzia: {POWER}{}Mantenimendua: {CURRENCY_LONG}/urtero{}Edukiera: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Kostua: {CURRENCY_LONG} Pisua: {WEIGHT_SHORT}{}Abiadura: {VELOCITY} Potentzia: {POWER} Gehienezko trakzioa: {6:FORCE}{}Mantinemendua: {4:CURRENCY_LONG}/urtero{}Edukiera: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Kostea: {CURRENCY_LONG} Gehienezko abiadura: {VELOCITY}{}Edukiera: {CARGO_LONG}{}Mantenimendua: {CURRENCY_LONG}/urtero @@ -3434,6 +3437,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Tren ibilgailu STR_REPLACE_MONORAIL_VEHICLES :Monorail trenak STR_REPLACE_MAGLEV_VEHICLES :Tren magnetikoak + STR_REPLACE_REMOVE_WAGON :{BLACK}Bagoiak ezabatu: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Ordezkatze automatikoari agindu trenaren luzera errespetatzea, bagoiak ezabatuz luzera handitzen badute (trenaren hasierako bagoietik hasita) @@ -4143,7 +4147,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Lehendab STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ez dago trenbide egokirik STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Lehendabizi trenbidea ezabatu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Errepidea norabide bakarrekoa da edo blokeatua dago -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ezin dira maila bereko pasaguneak egin trenbide mota honetan +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ezin dira maila bereko pasaguneak egin trenbide mota honetan STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ezin da seinalerik hemen eraiki... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ezin da trenbiderik hemen eraiki... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Ezin da hemengo trenbidea ezabatu... diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index 52215d57e7..5a7011e3b2 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -2009,7 +2009,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Раз STR_CONFIG_SETTING_AI :{ORANGE}Канкурэнты STR_CONFIG_SETTING_AI_NPC :{ORANGE}Кампутарныя гульцы -STR_CONFIG_SETTING_PATHFINDER_OPF :арыґінальны STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(рэкамэндуецца) @@ -2093,13 +2092,9 @@ STR_QUIT_NO :{BLACK}Не # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2744,6 +2739,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Буда STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Будаўніцтва/выдаленьне аўтамабільных дарогаў STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Будаўніцтва/выдаленьне трамвайных каляінаў + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Кірунак гаража STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Выберыце кірунак гаража @@ -3610,8 +3606,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Iнфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Чыгуначныя элемэнты: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Сыґналы STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Дарожныя элемэнты: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Дарогi -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Трамваi STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Водныя клеткi: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Каналы STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Станцыi: @@ -3688,6 +3682,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Бяз груп STR_GROUP_DEFAULT_SHIPS :Бяз групы STR_GROUP_DEFAULT_AIRCRAFTS :Бяз групы + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Ґрупы — клікніце па назьве ґрупы, каб убачыць сьпіс транспарту ў гэтай ґрупе. Націсьніце ды перацягвайце ґрупы, каб упарадкаваць гіерархію. STR_GROUP_CREATE_TOOLTIP :{BLACK}Стварыць групу STR_GROUP_DELETE_TOOLTIP :{BLACK}Выдаліць выбраную групу @@ -3713,10 +3708,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Новы эле STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Новы монарэйкавы цягнік STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Новы маґнітарэйкавы цягнік -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Новы цягнiк STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Новы аўтамабiль + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Новы цягнiк STR_BUY_VEHICLE_SHIP_CAPTION :Новы карабель STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Новы авiятранспарт +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Кошт: {GOLD}{CURRENCY_LONG}{BLACK} Вага: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Хуткасьць: {GOLD}{VELOCITY}{BLACK} Магутнасьць: {GOLD}{POWER} @@ -3750,11 +3748,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Купі STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Купіць STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Купіць + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Набыць абраны лякаматыў/ваґон. Shift+пстрычка — ацэнка кошту набыцьця. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Набыць абраны аўтамабіль. Shift+пстрычка — ацэнка кошту набыцьця. STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Набыць абраны карабель. Shift+пстрычка — ацэнка кошту набыцьця. STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Набыць абраны авіятранспарт. Shift+пстрычка — ацэнка кошту набыцьця. + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Перайменаваць STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Перайменаваць STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Перайменаваць @@ -3863,18 +3863,10 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Уве # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Паведамленьне ад вытворцы транспарту STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Мы стварылі новую мадэль {STRING.gen}. Цi зацікаўлены Вы ў яе гадавым эксклюзіўным выкарыстаньні для праверкі перад запускам у масавую вытворчасьць? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :{G=m}чыгуначны лякаматыў STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE.gen :чыгуначнага лакаматыва STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE.acc :чыгуначны лякаматыў -STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=m}аўтамабiль -STR_ENGINE_PREVIEW_ROAD_VEHICLE.gen :аўтамабiля -STR_ENGINE_PREVIEW_ROAD_VEHICLE.acc :аўтамабіль -STR_ENGINE_PREVIEW_AIRCRAFT :{G=m}авiятранспарт -STR_ENGINE_PREVIEW_AIRCRAFT.gen :авiятранспарту -STR_ENGINE_PREVIEW_AIRCRAFT.acc :авіятранспарт -STR_ENGINE_PREVIEW_SHIP :{G=m}карабель -STR_ENGINE_PREVIEW_SHIP.gen :карабля -STR_ENGINE_PREVIEW_SHIP.acc :карабель STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :{G=m}монарэйкавы лякаматыў STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE.gen :монарэйкавага лякаматыва STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE.acc :монарэйкавы лякаматыў @@ -3882,6 +3874,17 @@ STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :{G=m}маґні STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE.gen :магнiтарэйкавага лякаматыва STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE.acc :магнітарэйкавы лякаматыў +STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=m}аўтамабiль +STR_ENGINE_PREVIEW_ROAD_VEHICLE.gen :аўтамабiля +STR_ENGINE_PREVIEW_ROAD_VEHICLE.acc :аўтамабіль + +STR_ENGINE_PREVIEW_AIRCRAFT :{G=m}авiятранспарт +STR_ENGINE_PREVIEW_AIRCRAFT.gen :авiятранспарту +STR_ENGINE_PREVIEW_AIRCRAFT.acc :авіятранспарт +STR_ENGINE_PREVIEW_SHIP :{G=m}карабель +STR_ENGINE_PREVIEW_SHIP.gen :карабля +STR_ENGINE_PREVIEW_SHIP.acc :карабель + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Кошт: {CURRENCY_LONG} Вага: {WEIGHT_SHORT}{}Хуткасьць: {VELOCITY} Магутнасьць: {POWER}{}Кошт абслуг.: {CURRENCY_LONG}/год{}Ёмістасьць: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Кошт: {CURRENCY_LONG} Вага: {WEIGHT_SHORT}{}Хуткасьць: {VELOCITY} Магутнасьць: {POWER} Макс. ЦН: {6:FORCE}{}Кошт абслуг.: {4:CURRENCY_LONG}/год{}Ёмістасьць: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Кошт: {CURRENCY_LONG} Макс. хуткасьць: {VELOCITY}{}Ёмістасьць: {CARGO_LONG}{}Кошт абслуг.: {CURRENCY_LONG}/год @@ -3935,6 +3938,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Чыгунач STR_REPLACE_MONORAIL_VEHICLES :Монарэйкавыя ТС STR_REPLACE_MAGLEV_VEHICLES :Маґнітныя ТС + STR_REPLACE_REMOVE_WAGON :{BLACK}Выдаленьне ваґонаў: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Дазволіць пры аўтазамене захоўваць даўжыню цягнікоў шляхам выдаленьня ваґонаў (пачынаючы з галавы цягніка), калі пры аўтазамене лякаматыва павялічыцца даўжыня цягніка. @@ -4655,7 +4659,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Спач STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Няма прыдатных рэйкаў STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Спачатку выдаліце чыгунку STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Дарога аднабаковая або блякаваная -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Праз гэты від рэйкаў забаронена будаваць пераезды +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Праз гэты від рэйкаў забаронена будаваць пераезды STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Тут немагчыма паставіць сьветлафор... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Тут немагчыма пракласьцi рэйкі... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Не атрымалася выдаліць чыгунку... diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index e6ac23a72a..5e688f006b 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -1700,7 +1700,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distrib STR_CONFIG_SETTING_AI :{ORANGE}Oponentes STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computadores -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recomendado) @@ -1784,13 +1783,9 @@ STR_QUIT_NO :{BLACK}Não # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2419,6 +2414,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Construi STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Alternar construir/remover para contrução rodoviária STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Alternar construir/remover linhas de bonde e sinais + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Orientação da Garagem STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Selecionar a orientação da garagem @@ -3320,8 +3316,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Partes de ferrovias: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Sinais STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Partes de rodovias: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Rodovia -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Linha de bonde STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Partes d'água: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canais STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estações: @@ -3398,6 +3392,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Automóveis sem STR_GROUP_DEFAULT_SHIPS :Embarcações sem grupo STR_GROUP_DEFAULT_AIRCRAFTS :Aeronaves sem grupo + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupos - Clique em um grupo para listar seus veículos. Clique e arraste para organizar a hierarquia. STR_GROUP_CREATE_TOOLTIP :{BLACK}Clique para criar um grupo STR_GROUP_DELETE_TOOLTIP :{BLACK}Remove o grupo selecionado @@ -3423,10 +3418,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nova Locomotiva STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nova Locomotiva Monotrilho STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nova Locomotiva Maglev -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Trens STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Novos Automóveis + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Trens STR_BUY_VEHICLE_SHIP_CAPTION :Novas Embarcações STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nova Aeronave +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Preço: {GOLD}{CURRENCY_LONG}{BLACK} Peso: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Velocidade: {GOLD}{VELOCITY}{BLACK} Potência: {GOLD}{POWER} @@ -3460,11 +3458,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Comprar STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Comprar Embarcação STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Comprar Aeronave + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Compra o veículo ferroviário selecionado. Shift+Clique mostra preço estimado sem a compra STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Compra o veículo selecionado. Shift+Clique mostra preço estimado sem a compra STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Compra a embarcação selecionada. Shift+Clique mostra preço estimado sem a compra STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Compra a aeronave selecionada. Shift+Clique mostra o preço estimado sem a compra + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Renomear STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Renomear STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Renomear @@ -3573,13 +3573,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Você e # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Mensagem de um fabricante de veículos STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Projetamos um novo {STRING} - estaria interessado em um ano de exclusividade do uso deste veículo, de modo a que possamos avaliar a sua performance antes de o disponibilizar para todos ? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :locomotiva ferroviária -STR_ENGINE_PREVIEW_ROAD_VEHICLE :automóvel -STR_ENGINE_PREVIEW_AIRCRAFT :aeronave -STR_ENGINE_PREVIEW_SHIP :embarcação STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :locomotiva monotrilho STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :locomotiva maglev +STR_ENGINE_PREVIEW_ROAD_VEHICLE :automóvel + +STR_ENGINE_PREVIEW_AIRCRAFT :aeronave +STR_ENGINE_PREVIEW_SHIP :embarcação + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Preço: {CURRENCY_LONG} Peso: {WEIGHT_SHORT}{}Velocidade: {VELOCITY} Potência: {POWER}{}Custo de manutenção: {CURRENCY_LONG}/ano{}Capacidade: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Preço: {CURRENCY_LONG} Peso: {WEIGHT_SHORT}{}Vel.: {VELOCITY} Potência: {POWER} Tração Máx: {6:FORCE}{}Custo de manutenção: {4:CURRENCY_LONG}/yr{}Capacidade: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Preço: {CURRENCY_LONG} Vel. Max.: {VELOCITY}{}Capacidade: {CARGO_LONG}{}Custo de manuteção: {CURRENCY_LONG}/ano @@ -3625,6 +3628,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Locomotivas El STR_REPLACE_MONORAIL_VEHICLES :Monotrilho STR_REPLACE_MAGLEV_VEHICLES :Maglevs + STR_REPLACE_REMOVE_WAGON :{BLACK}Remoção de vagões: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Faz autosubstituição manter o tamanho do trem removendo vagões (começando pela frente), se ao substituir a locomotiva o trem ficar maior @@ -4345,7 +4349,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Remova o STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Tipo de linha não apropriado STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Remova a ferrovia antes STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Rua é mão única ou está bloqueada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Cruzamentos de nível não são permitidos para esse tipo de trilho +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Cruzamentos de nível não são permitidos para esse tipo de trilho STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Impossível construir sinais aqui... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Impossível construir ferrovia aqui... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Impossível remover a ferrovia daqui... diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index 68d44b7f03..974557ff9c 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -237,6 +237,7 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Избе STR_BUTTON_SORT_BY :{BLACK}Сортирай по STR_BUTTON_LOCATION :{BLACK}Позиция STR_BUTTON_RENAME :{BLACK}Преименувай +STR_BUTTON_CATCHMENT :{BLACK}Покритие STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Затвори прозореца STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Заглавие на прозорец - преместване на прозореца с мишката @@ -919,6 +920,8 @@ STR_GAME_OPTIONS_CURRENCY_ZAR :Южноафр STR_GAME_OPTIONS_CURRENCY_CUSTOM :друга... STR_GAME_OPTIONS_CURRENCY_GEL :Грузинско лари (ГЕЛ) STR_GAME_OPTIONS_CURRENCY_IRR :Ирански Риал (ИРР) +STR_GAME_OPTIONS_CURRENCY_NTD :Нов тайвански долар +STR_GAME_OPTIONS_CURRENCY_HKD :Хонгконгски долар (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Движение по пътищата @@ -1649,7 +1652,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Инд STR_CONFIG_SETTING_AI :{ORANGE}Съперници STR_CONFIG_SETTING_AI_NPC :{ORANGE}Компютърни играчи -STR_CONFIG_SETTING_PATHFINDER_OPF :Оригинален STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(препоръчва се) @@ -1731,13 +1733,9 @@ STR_QUIT_NO :{BLACK}Не # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :ДОС STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2363,6 +2361,8 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Пост STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Премахване на асфалтов път STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Превключване строене/разрушаване на трамвайни консктрукции +STR_ROAD_NAME_ROAD :Път + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Ориентация на гараж STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Ориентация на гараж @@ -3221,8 +3221,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Инфр STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Релсови части: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Сигнали STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Пътни части: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Път -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Трамвай +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Трамвайни вагони: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Водни части: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Канали STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Станции: @@ -3297,6 +3296,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Безгруп STR_GROUP_DEFAULT_SHIPS :Безгрупни кораби STR_GROUP_DEFAULT_AIRCRAFTS :Безгрупни самолети + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Групи - Щракни на група за да видиш списък на всички превозни средства от тази група STR_GROUP_CREATE_TOOLTIP :{BLACK}Щракни да създадеш група STR_GROUP_DELETE_TOOLTIP :{BLACK}Изтрий избраната група @@ -3320,10 +3320,14 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Нови еле STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Нови Машини за Монорелсов път STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Нови Машини за Магниторелсов път -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Нови ЖП превозни средства STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Нова кола + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Нови ЖП превозни средства +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :Ново пътно превозно средство STR_BUY_VEHICLE_SHIP_CAPTION :Нови Кораби STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Нова летателна машина +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Цена: {GOLD}{CURRENCY_LONG}{BLACK} Тегло: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Скорост: {GOLD}{VELOCITY}{BLACK} Мощност: {GOLD}{POWER} @@ -3336,8 +3340,10 @@ STR_PURCHASE_INFO_REFITTABLE :(преустр STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Модел: {GOLD}{NUM}{BLACK} Живот: {GOLD}{COMMA} години STR_PURCHASE_INFO_RELIABILITY :{BLACK}Макс. надеждност: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Цена: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Цена: {GOLD}{CURRENCY_LONG}{BLACK} (Цена за преустройване: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Тегло: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Цема {GOLD}{CURRENCY_LONG}{BLACK} Скорост: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Цена: {GOLD}{CURRENCY_LONG}{BLACK} (Цена за преустройване: {GOLD}{CURRENCY_LONG}{BLACK}) Скорост: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Капацитет: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Вагони с мощност: {GOLD}+{POWER}{BLACK} Тегло: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Преобразуваем на: {GOLD}{STRING} @@ -3357,11 +3363,15 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Купи STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Купи Кораб STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Купи самолет +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Купуване и преустройване на кораб +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Купуване и преустройване на самолет + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Купи маркираният влак. Shift строеж/цена за построяване STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Купи посоченото МПС. Shift строеж/цена за построяване STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Купи посоченият кораб. Shift строеж/цена за построяване STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Купи посоченият самолет. Shift строеж/цена за построяване + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Преименувай STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Преименувай STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Промяна на име @@ -3470,13 +3480,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Иск # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Съобщение от производител STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Създадохме нов {STRING}.{}Интересувате ли се от изключителното право да използвате това ПС за една година, за да видим как то работи преди да го пуснем на пазара за масова употреба? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :локомотив за двурелсов път -STR_ENGINE_PREVIEW_ROAD_VEHICLE :автомобил -STR_ENGINE_PREVIEW_AIRCRAFT :самолет -STR_ENGINE_PREVIEW_SHIP :кораб STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :локомотив за еднорелсов път STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :локомотив за магниторелсов път +STR_ENGINE_PREVIEW_ROAD_VEHICLE :автомобил + +STR_ENGINE_PREVIEW_AIRCRAFT :самолет +STR_ENGINE_PREVIEW_SHIP :кораб + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Цена: {CURRENCY_LONG} Тегло: {WEIGHT_SHORT}{}Скорост: {VELOCITY} Мощност: {POWER}{}Разход: {CURRENCY_LONG}/г.{}Капацитет: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Цена: {CURRENCY_LONG} Тегло: {WEIGHT_SHORT}{}Скорост: {VELOCITY} Мощност: {POWER} Макс. Т.С.: {6:FORCE}{}Експлоатационни разходи: {4:CURRENCY_LONG}/год.{}Вместимост: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Цена: {CURRENCY_LONG} Макс. Скорост: {VELOCITY}{}Вместимост: {CARGO_LONG}{}Експлоатационни разходи: {CURRENCY_LONG}/год. @@ -3511,14 +3524,17 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Прев STR_REPLACE_ENGINES :Двигатели STR_REPLACE_WAGONS :Вагони STR_REPLACE_ALL_RAILTYPE :Всички ЖП композиции +STR_REPLACE_ALL_ROADTYPE :Всички пътни превозни средства STR_REPLACE_HELP_RAILTYPE :{BLACK}Избор на ЖП линия с която да се заменят локомотивите +STR_REPLACE_HELP_ROADTYPE :Изберете типа път, за който искате да подмените двигателите. STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Показване с кой двигател се заменя ляво избрания, ако има STR_REPLACE_RAIL_VEHICLES :ЖП влакове STR_REPLACE_ELRAIL_VEHICLES :Електрически локомотиви STR_REPLACE_MONORAIL_VEHICLES :Монорелсови локомотиви STR_REPLACE_MAGLEV_VEHICLES :Маглев влакове + STR_REPLACE_REMOVE_WAGON :{BLACK}Премахване на вагон: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Автоматичната замяна ще запази дължината на влака като премахне вагони (започвайки от предните), ако замяната довежда до по-дълъг влак. @@ -4236,7 +4252,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Първ STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Неподходящ за употреба релсов път STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Първо трябва да бъде премахнат релсовия път STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Пътят е еднопосочен или блокиран -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Пресичането на различни видове ЖП линии не е позволено. +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Пресичането на различни видове ЖП линии не е позволено. STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Тук не може да бъдат поставени сигнали... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Тук не могат да бъдат построени ЖП релси... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Не може да премахнеш тези ЖП релси... @@ -4256,6 +4272,8 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Пътя STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Не може да се разруши трамвайната линия... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... тук няма път STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... няма трамвайни линии +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Няма подходящ път +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... несъвместима трамвайна линия # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Тук не е възможно да се прокопае канал... diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index d262e1029f..52fed2d757 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -1201,8 +1201,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :El pendent de l STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Pendent de les costes per als vehicles de carretera: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :El pendent de les caselles amb costes per a vehicles de carretera. Els valors alts fan que sigui més difícil pujar els turons. -STR_CONFIG_SETTING_FORBID_90_DEG :Prohibeix fer girs de 90 graus als trens i vaixells: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Els girs de 90 graus succeeixen quan hi ha una via horitzontal seguida d'una de vertical a la cel·la annexa, provocant que el tren giri 90 graus quan travessi la vora de la cel·la en lloc dels 45 graus usuals en les altres combinacions. Això també s'aplica al gir dels vaixells. +STR_CONFIG_SETTING_FORBID_90_DEG :Prohibeix fer girs de 90 graus als trens: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Els girs de 90 graus succeeixen quan hi ha una via horitzontal seguida d'una de vertical a la cel·la annexa, provocant que el tren giri 90 graus quan travessi la vora de la cel·la en lloc dels 45 graus usuals en les altres combinacions. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Permet ajuntar estacions no annexes: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Aquesta opció permet afegir parts noves a una estació existent sense estar les parts noves en contacte directe amb les existents. Cal clicar Ctrl+Clic mentre es col·loquen les parts noves. STR_CONFIG_SETTING_INFLATION :Inflació: {STRING} @@ -1258,8 +1258,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Factor de veloc STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Estableix la velocitat relativa dels avions en comparació amb els altres tipus de vehicles, per reduir la quantitat de guanys de transport dels avions STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Nombre d'accidents d'avió: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Estableix la probabilitat amb què succeeixen els accidents d'avió -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Cap +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Estableix la probabilitat amb què succeeixen els accidents d'avió.{}* Els avions grans sempre tenen un risc d'estavellar-se quan aterren en aeroports petits. +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Cap* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduït STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Permet situar parades en carreteres que són propietat de la població: {STRING} @@ -1584,6 +1584,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Activant aquest STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Prohibit STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Permès STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Permès, disposició dels carrers personalitzada +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Generació de càrrega a les poblacions: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Estableix quanta càrrega es produirà a les cases en funció dels habitants de la població.{}Creixement quadràtic: una població el doble de gran generarà el quàdruple de passatgers.{}Creixement lineal: una població el doble de gran generarà el doble de passatgers. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Quadràtica (original) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineal STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Disposició de nous arbres durant la partida: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Controla l'aparició aleatòria dels arbres durant una partida. Això podria afectar a les indústries que es basen en el creixement dels arbres, per exemple les serradores @@ -1711,7 +1715,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distrib STR_CONFIG_SETTING_AI :{ORANGE}Competidors STR_CONFIG_SETTING_AI_NPC :{ORANGE}Jugadors IA -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recomanat) @@ -1795,13 +1798,9 @@ STR_QUIT_NO :{BLACK}No # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2432,6 +2431,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Construe STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Intercanvia funció construeix/treu per la construcció de carreteres STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Canvia construeix/treu de la construcció de vies de tramvia + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Orientació de la cotxera STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Seleccioneu l'orientació desitjada de la cotxera per a vehicles de carretera. @@ -3355,8 +3355,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infraest STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Trossos de vies: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Senyals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Trossos de carretera: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Carretera -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvia STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Cel·les d'aigua: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Estacions: @@ -3436,6 +3434,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Vehicles desagr STR_GROUP_DEFAULT_SHIPS :Vaixells desagrupats STR_GROUP_DEFAULT_AIRCRAFTS :Avions desagrupats + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grups - Clica en un grup per llistar tots els vehicles d'aquest grup. Arrossega i solta per a canviar-ne la jerarquia. STR_GROUP_CREATE_TOOLTIP :{BLACK}Clica per crear un grup STR_GROUP_DELETE_TOOLTIP :{BLACK}Elimina el grup seleccionat @@ -3462,10 +3461,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Compra de nous STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Compra de nous vehicles monorail STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Compra de nous vehicles Maglev -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Compra de nous vehicles sobre vies STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Compra de nous vehicles de carretera + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Compra de nous vehicles sobre vies STR_BUY_VEHICLE_SHIP_CAPTION :Compra de nous vaixells STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Compra de noves aeronaus +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Pes: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Velocitat: {GOLD}{VELOCITY}{BLACK} Potència: {GOLD}{POWER} @@ -3500,11 +3502,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Compra e STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Compra el vaixell STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Compra l'aeronau + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Compra el tren/vagó seleccionat. Amb Maj+Clic, mostra el cost estimat sense comprar-lo. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Compra el vehicle marcat. Amb Maj+Clic, mostra el cost estimat sense comprar-lo. STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Compra el vaixell seleccionat. Amb Maj+Clic, mostra el cost estimat sense comprar-lo. STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Compra l'aeronau marcada. Amb Maj+Clic, mostra el cost estimat sense comprar-la. + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Canvia el nom STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Canvia el nom STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Canvia el nom @@ -3613,13 +3617,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Estàs # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Missatge del fabricant de vehicles STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Acabem de dissenyar {G un una} {G nou nova} {STRING}. Esteu interessats en fer ús exclusiu d'aquest vehicle durant un any, per veure com va, abans del seu llançament mundial? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :{G=Femenin}locomotora de tren -STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=Masculin}automòbil -STR_ENGINE_PREVIEW_AIRCRAFT :{G=Masculin}avió -STR_ENGINE_PREVIEW_SHIP :{G=Masculin}vaixell STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :{G=Femenin}locomotora de monorail STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :{G=Femenin}locomotora de maglev +STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=Masculin}automòbil + +STR_ENGINE_PREVIEW_AIRCRAFT :{G=Masculin}avió +STR_ENGINE_PREVIEW_SHIP :{G=Masculin}vaixell + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Pes: {WEIGHT_SHORT}{}Velocitat: {VELOCITY} Potència: {POWER}{}Cost de circulació: {CURRENCY_LONG}/any{}Capacitat: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Pes: {WEIGHT_SHORT}{}Velocitat: {VELOCITY} Potència: {POWER} Màx. E.T.: {6:FORCE}{}Cost d'utilització: {4:CURRENCY_LONG}/any{}Capacitat: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Vel. Màx: {VELOCITY}{}Capacitat: {CARGO_LONG}{}Cost d'utilització: {CURRENCY_LONG}/any @@ -3665,6 +3672,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Trens Elèctric STR_REPLACE_MONORAIL_VEHICLES :Trens monorail STR_REPLACE_MAGLEV_VEHICLES :Trens maglev + STR_REPLACE_REMOVE_WAGON :{BLACK}Treure vagons: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Fer que la substitució automàtica mantingui la llargada del tren eliminant vagons (començant pel front), si substituint la màquina el tren es fa més llarg @@ -4386,7 +4394,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}...abans STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Via de tren no apropiada STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}...abans s'ha de treure la via. STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}La carretera és un d'un sol sentit o està bloquejada -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Els passos a nivell no estan permesos en aquest tipus de via +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Els passos a nivell no estan permesos en aquest tipus de via STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Aquí no es poden construir senyals... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Aquí no es pot construir la via de tren... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Aquí no es pot treure la via de tren... diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index e890c2fa26..344702819c 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -333,6 +333,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Odaberi STR_BUTTON_SORT_BY :{BLACK}Sortiraj prema STR_BUTTON_LOCATION :{BLACK}Lokacija STR_BUTTON_RENAME :{BLACK}Preimenuj +STR_BUTTON_CATCHMENT :{BLACK}Područje pokrivanja +STR_TOOLTIP_CATCHMENT :{BLACK}Uključi prikaz područja pokrivanja STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Zatvori prozor STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Naslov prozora - povuci ovo za micanje prozora @@ -361,6 +363,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Uključi STR_BUTTON_DEFAULT :{BLACK}Zadano STR_BUTTON_CANCEL :{BLACK}Odustani STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Upozorenje: Administratori servera mogu pročitati bilo koji tekst upisan ovdje. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . @@ -434,6 +437,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Približ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Udalji pogled STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Izgradi željezničku prugu STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Izgradi ceste +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Izgradi tramvajsku prugu STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Izgradi pristaništa za brodove STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Izgradi zračne luke STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Otvori alatnu traku za krajolik kako bi spustio/izdignuo zemlju, posadio drveće, itd. @@ -454,6 +458,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Stvaranj STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Stvaranje gradova STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Stvaranje industrije STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Izgradnja ceste +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Izgradnja tramvajske pruge STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Posadi drveće. Shift mijenja prikaz građenje/procjena troškova. STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Postavi znak STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Postavi objekt. Shift mijenja prikaz građenje/procjena troškova. @@ -1029,6 +1034,9 @@ STR_GAME_OPTIONS_CURRENCY_GEL :Gruzijski Lari STR_GAME_OPTIONS_CURRENCY_IRR :Iranski Rial (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Nove ruske rublje (RUB) STR_GAME_OPTIONS_CURRENCY_MXN :Meksički Pesos (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :Novi Tajvanski Dolar (NTD) +STR_GAME_OPTIONS_CURRENCY_CNY :Kineski Renminbi (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Hongkonški Dolar (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Cestovna vozila @@ -1280,6 +1288,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Dopusti uređiv STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Dopusti uređivanje krajolika ispod građevina i pruga bez njihovog uklanjanja STR_CONFIG_SETTING_CATCHMENT :Dopusti realističnije veličine područja zahvaćanja: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Različiti dohvati za različite vrste stanica i zračnih luka +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Stanice kompanije mogu opsluživati industrije sa priključenim neutralnim stanicama: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Kada je uključeno, industrije sa priključenim stanicama (kao naftne platforme) mogu biti opsluživane od strane kompanija koje imaju stanice izgrađene u blizini. Kada je isključeno, ove industrije mogu biti opsluživane samo putem svojih priključenih stanica. Bilo koja stanica u blizini u vlasništvu neke kompanije neće moći opsluživati ove industrije niti će stanice priključene industriji moći opsluživati bilo što osim te industrije. STR_CONFIG_SETTING_EXTRADYNAMITE :Dopusti rušenje više cesta, mostova i tunela u vlasništvu grada: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Jednostavnije uklanjanje infrastrukture i građevina u vlasništvu grada STR_CONFIG_SETTING_TRAIN_LENGTH :Najveća dužina vlakova: {STRING} @@ -1296,8 +1306,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Kosina nagiba p STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Strmina nagiba za cestovna vozila: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Kosina nagiba polja za cestovna vozila. Veće vrijednosti čine nagib težim za penjanje -STR_CONFIG_SETTING_FORBID_90_DEG :Zabrani vlakovima i brodovima skretanja pod 90 stupnjeva: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Okreti za 90 stupnjeva se događaju kada vodoravni dio pruge odmah nastavlja okomiti dio pruge na sljedećem polju, dakle čineći zaokret vlaka od 90 stupnjeva prelaskom ruba polja umjesto uobičajenih 45 stupnjeva kod drugih kombinacija pruge. Ovo se primjenjuje i na radijus okretanja brodova +STR_CONFIG_SETTING_FORBID_90_DEG :Zabrani vlakovima skretanja pod 90 stupnjeva: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Okreti za 90 stupnjeva se događaju kada se na vodoravni dio pruge odmah nastavlja okomiti dio pruge na sljedećem polju, dakle čineći zaokret vlaka od 90 stupnjeva prelaskom ruba polja umjesto uobičajenih 45 stupnjeva kod drugih kombinacija pruge. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Dopusti spajanje postaja koje nisu izravno jedna do druge {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Dopusti dodavanje dijelova stanice bez izravnog dodira s postojećim dijelovima. Potrebno pritisnuti Ctrl+klik dok se dodaju novi dijelovi STR_CONFIG_SETTING_INFLATION :Inflacija: {STRING} @@ -1353,8 +1363,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Faktor brzine z STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Postavite relativnu brzinu zrakoplova u odnosu na ostale vrste vozila, kako bi se smanjio iznos prihoda od prijevoza zrakoplovom STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Broj padova zrakoplova: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Odredi šansu za događanje zrakoplovne nesreće -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ništa +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Odredi šansu za događanje avionske nesreće.{}* Veliki avioni uvijek riskiraju nesreću kad slijeću na male aerodrome +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ništa* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Smanjeno STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normalno STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Dopusti prolazne postaje na cestama u vlasništvu gradova: {STRING} @@ -1577,6 +1587,9 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Dopusti UI u mr STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Dopusti UI računalnim-igračima da sudjeluju u igrama za više igrača STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#op-kodova prije prekida skripte: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Najveći broj računalnih koraka koje skripta može poduzeti u jednom krugu +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Maksimalno korištenje memorije po skripti: {STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :Koliko memorija svaka pojedina skripta može iskoristiti prije nego bude prisilno zatvorena. Ova postavka treba biti povećana za velike mape. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Servisni su intervali u postotcima: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Odaberi hoće li servis vozila potaknuti količina vremana koja je prošla od zadnjeg servisa ili postotni pad u odnosu na najveću pouzdanost @@ -1679,6 +1692,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Uklučivanje ov STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Zabranjeno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Dopušteno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Dopušteno, proizvoljan raspored grada +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Proizvodnja tereta u gradu: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Koliko tereta proizvode kuće u gradu u odnosu na ukupno stanovništvo grada.{}Kvadratni rast: Grad dvostruke veličine proizvodi četverostruku količinu putnika.{}Linearni rast: Grad dvostruke veličine proizvodi dvostruku količinu putnika. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Kvadratno (originalno) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Linearno STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Smještaj drveća u igri: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Kontroliraj nasumično pojavljivanje stabala tijekom igre. Ovo može utjecati na industrije koje ovise o rastu stabala, npr. pilane @@ -1806,7 +1823,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distrib STR_CONFIG_SETTING_AI :{ORANGE}Suparnici STR_CONFIG_SETTING_AI_NPC :{ORANGE}Računalni igrači -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Preporučljivo) @@ -1890,13 +1906,9 @@ STR_QUIT_NO :{BLACK}Ne # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2234,7 +2246,7 @@ STR_NETWORK_CHAT_ALL :[Svima] {STRING STR_NETWORK_CHAT_OSKTITLE :{BLACK}Upišite tekst mrežnog razgovora # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Nisu pronađeni mrežni uređaji ili je kompajlirano bez opcije ENABLE_NETWORK +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Nisu pronađeni mrežni uređaji STR_NETWORK_ERROR_NOSERVER :{WHITE}Niti jedna mrežna igra nije pronađena STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Poslužitelj nije odgovorio na zahtjev STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Spajanje nije moguće zbog razlike u NewGRF datotekama @@ -2526,6 +2538,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Izgradi STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Izgradi tramvajski tunel. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Aktiviraj izgradnju/uklanjanje za izgradnju ceste STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Aktiviraj izgradnju/uklanjanje za izgradnju tramvaja +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Pretvori/nadogradi vrstu ceste. Shift mijenja prikaz građenje/procjena troškova. +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Pretvori/nadogradi vrstu tramvajske pruge. Shift mijenja prikaz građenje/procjena troškova. + +STR_ROAD_NAME_ROAD :Cesta +STR_ROAD_NAME_TRAM :Tramvajska pruga # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Smjer cestovnog spremišta @@ -2710,8 +2727,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Prihvaćeni teret: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Vrsta željeznice: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Vrsta ceste: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Vrsta tramvaja: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Najveća brzina željeznice: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Ograničenje brzine na cesti: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Limit brzine tramvaja: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Stijenje @@ -2821,6 +2841,7 @@ STR_FRAMERATE_SPEED_FACTOR :{BLACK}Trenutni STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}Koliko brzo se igra izvodi trenutno u usporedbi sa očekivanom brzinom u uobičajenoj simulaciji. STR_FRAMERATE_CURRENT :{WHITE}Trenutno STR_FRAMERATE_AVERAGE :{WHITE}Prosječno +STR_FRAMERATE_MEMORYUSE :{WHITE}Memorija STR_FRAMERATE_DATA_POINTS :{BLACK}Podaci bazirani na {COMMA} mjerama STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_WARN :{YELLOW}{DECIMAL} ms @@ -2828,6 +2849,9 @@ STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} sličica/s STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} sličica/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} sličica/s +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! @@ -3451,8 +3475,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Dijelovi pruge: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signali STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Dijelovi ceste: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajska pruga +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Dijelovi tramvaja: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Polje s vodom: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Postaje: @@ -3532,6 +3555,8 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Negrupirana ces STR_GROUP_DEFAULT_SHIPS :Negrupirani brodovi STR_GROUP_DEFAULT_AIRCRAFTS :Negrupirani zrakoplovi +STR_GROUP_COUNT_WITH_SUBGROUP :{TINY_FONT}{COMMA} (+{COMMA}) + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupe - kliknite na grupu kako bi izlistali sva vozila ove grupe. Povucite i prenesite grupe za postavljanje hijerarhije. STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikni za kreiranje grupe STR_GROUP_DELETE_TOOLTIP :{BLACK}Obriši odabranu grupu @@ -3558,12 +3583,18 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nova električn STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nova jednotračna željeznička vozila STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nova vozila Maglev -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nova pružna vozila STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nova cestovna vozila +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :Novi tramvaji + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nova pružna vozila +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :Nova cestovna vozila STR_BUY_VEHICLE_SHIP_CAPTION :Novi brodovi STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Novi zrakoplov +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cijena: {GOLD}{CURRENCY_LONG}{BLACK} Težina {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cijena : {GOLD}{CURRENCY_LONG}{BLACK} (Cijena prenamjene: {GOLD}{CURRENCY_LONG}{BLACK}) Težina: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Brzina: {GOLD}{VELOCITY}{BLACK} Snaga: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Brzina: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Brzina na oceanu: {GOLD}{VELOCITY} @@ -3574,8 +3605,10 @@ STR_PURCHASE_INFO_REFITTABLE :(prenamjenjiv) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Dizajnirano: {GOLD}{NUM}{BLACK} Životni vijek: {GOLD}{COMMA} godina STR_PURCHASE_INFO_RELIABILITY :{BLACK}Najveća pouzdanost: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cijena: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Cijena: {GOLD}{CURRENCY_LONG}{BLACK} (Cijena prenamjene: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Težina: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Trošak: {GOLD}{CURRENCY_LONG}{BLACK} Brzina: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Cijena: {GOLD}{CURRENCY_LONG}{BLACK} (Cijena prenamjene: {GOLD}{CURRENCY_LONG}{BLACK}) Brzina: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Nosivost: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK} Pokretni vagoni:.{GOLD}+{POWER}{BLACK} Težina: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Prenamjenjivo u: {GOLD}{STRING} @@ -3596,11 +3629,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Kupi voz STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Kupi brod STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Kupi zrakoplov +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Kupi i prenamijeni vozilo +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Kupi i prenamijeni vozilo +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Kupi i prenamijeni brod +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Kupi i prenamijeni zrakoplov + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeni vlak. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeno cestovno vozilo. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeni brod. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeni zrakoplov. Shift+Klik prikazuje trošak bez kupnje. +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Kupi i prenamijeni označeni vlak. Shift+Klik prikazuje trošak bez kupnje. +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Kupi i prenamijeni označeno cestovno vozilo. Shift+Klik prikazuje trošak bez kupnje. +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Kupi i prenamijeni označeni brod. Shift+Klik prikazuje trošak bez kupnje. +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Kupi i prenamijeni označeni zrakoplov. Shift+Klik prikazuje trošak bez kupnje. + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Preimenuj @@ -3709,13 +3752,18 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Upravo # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Poruka od proizvođača vozila STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Upravo smo dizajnirali novi {STRING} - jeste li zainteresirani za jednogodišnje ekskluzivno pravo uporabe ovog vozila, kako bi vidjeli kako se vozilo ponaša prije nego što postane univerzalno dostupno? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :željeznička lokomotiva -STR_ENGINE_PREVIEW_ROAD_VEHICLE :cestovno vozilo -STR_ENGINE_PREVIEW_AIRCRAFT :zrakoplov -STR_ENGINE_PREVIEW_SHIP :brod +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :lokomotiva za elektrificiranu željeznicu STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :jednotračna željeznička lokomotiva STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev lokomotiva +STR_ENGINE_PREVIEW_ROAD_VEHICLE :cestovno vozilo +STR_ENGINE_PREVIEW_TRAM_VEHICLE :tramvaj + +STR_ENGINE_PREVIEW_AIRCRAFT :zrakoplov +STR_ENGINE_PREVIEW_SHIP :brod + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cijena: {CURRENCY_LONG} Težina: {WEIGHT_SHORT}{}Brzina: {VELOCITY} Snaga: {POWER}{}Trošak uporabe: {CURRENCY_LONG}/god{}Kapacitet: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Trošak: {CURRENCY_LONG} Težina: {WEIGHT_SHORT}{}Brzina: {VELOCITY} Snaga: {POWER} Maks. T.E.: {6:FORCE}{}Trošak uporabe: {4:CURRENCY_LONG}/god{}Nosivost: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Trošak: {CURRENCY_LONG} Maks. brzina: {VELOCITY}{}Nosivost: {CARGO_LONG}{}Trošak uporabe: {CURRENCY_LONG}/god @@ -3753,14 +3801,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Prebaci STR_REPLACE_ENGINES :Lokomotive STR_REPLACE_WAGONS :Vagoni STR_REPLACE_ALL_RAILTYPE :Sva pružna vozila +STR_REPLACE_ALL_ROADTYPE :Sva cestovna vozila STR_REPLACE_HELP_RAILTYPE :{BLACK}Odaberite vrstu željeznice za koju želite zamijeniti lokomotive +STR_REPLACE_HELP_ROADTYPE :{BLACK}Odaberite vrstu ceste za koju želite zamijeniti vozila STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Prikazuje sa kojom se lokomotivom zamjenjuje lijevo odabrana lokomotiva, ako postoji koji STR_REPLACE_RAIL_VEHICLES :Pružna vozila STR_REPLACE_ELRAIL_VEHICLES :Električna pružna vozila STR_REPLACE_MONORAIL_VEHICLES :Jednotračna vozila STR_REPLACE_MAGLEV_VEHICLES :Željeznička vozila Maglev +STR_REPLACE_ROAD_VEHICLES :Cestovna vozila +STR_REPLACE_TRAM_VEHICLES :Tramvaji + STR_REPLACE_REMOVE_WAGON :{BLACK}Uklanjanje vagona: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Automatska zamjena zadržava istu dužinu vlaka tako da ukloni suvišne vagone (počevši od naprijed), ako bi zamjena lokomotive učinila vlak dužim @@ -4482,7 +4535,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprije STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nije prikladno za želježnicku prugu STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprije je potrebno ukloniti željezničku prugu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je jednosmjerna ili je blokirana -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Pružni prijelazi nisu dopušteni za ovu vrstu pruge +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Pružni prijelazi nisu dopušteni za ovu vrstu pruge +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Pružni prijelazi nisu dopušteni za ovu vrstu ceste STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ovdje nije moguće postaviti signale... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ovdje nije moguće izgraditi željezničke tračnice... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nije moguće ukloniti željezničku prugu odavde... @@ -4502,6 +4556,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Nije mog STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Nije moguće ukloniti tramvaj odavde... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... nema ceste STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... nema tramvajske pruge +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Ovdje nije moguće pretvoriti cestu... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Ovdje nije moguće pretvoriti tramvajsku prugu... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Nema prikladne ceste +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}Nema prikladne tramvajske pruge +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... nekompatibilna cesta +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... nekompatibilna tramvajska pruga # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Ovdje nije moguće izgraditi kanale... @@ -4554,6 +4614,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Nije mog STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Nije moguće obrisati ovu grupu... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Nije moguće preimenovati ovu grupu... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Ne može se postaviti matična grupa... +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... petlje u grupnoj hijerarhiji nisu dozvoljene STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Nije moguće ukloniti sva vozila iz ove grupe... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Nije moguće dodati vozila u ovu grupu STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Nije moguće dodati dijeljena vozila u grupu... diff --git a/src/lang/czech.txt b/src/lang/czech.txt index b0ef98a248..79973c8de2 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -265,6 +265,7 @@ STR_COLOUR_BROWN :Hnědá STR_COLOUR_GREY :Šedá STR_COLOUR_WHITE :Bílá STR_COLOUR_RANDOM :Náhodná +STR_COLOUR_DEFAULT :Výchozí # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}m{P íle íle il}/h @@ -311,6 +312,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Vyber t STR_BUTTON_SORT_BY :{BLACK}Řadit podle STR_BUTTON_LOCATION :{BLACK}Umístění STR_BUTTON_RENAME :{BLACK}Přejmenovat +STR_BUTTON_CATCHMENT :{BLACK}Pokrytí +STR_TOOLTIP_CATCHMENT :{BLACK}Zapnout/vypnout zvýrazňování oblasti pokrytí STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Zavřít okno STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Titulek okna - tahej pro posun okna @@ -339,6 +342,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Zapnutí STR_BUTTON_DEFAULT :{BLACK}Původní STR_BUTTON_CANCEL :{BLACK}Zrušit STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Upozornění: Administrátor serveru může zjistit a přečíst jakýkoliv text sem vložený. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :"+ěščřžýáíé=-\qwertyuiopú)asdfghjklů' zxcvbnm,./ . @@ -412,6 +416,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Přiblí STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Oddálit pohled STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Budovat železnici STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Budovat silniční síť +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Výstavba tramvajových tratí STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Budovat vodní cesty STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Stavět letiště STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Otevřít nástrojovou lištu na úpravu terénu, výsadbu stromů, atd. @@ -432,6 +437,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Generov STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Generování měst STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Generování průmyslu STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Výstavba silniční sítě +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Výstavba tramvajové tratě STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Vysadit stromy. Shift zobrazí odhad ceny STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Umístit popisek STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Umisťte objekt. Shift zobrazí odhad ceny @@ -761,10 +767,12 @@ STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Zapnout/ STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Ukaž skladbu ve výběrovém okně # Playlist window +STR_PLAYLIST_MUSIC_SELECTION_SETNAME :{WHITE}Hudební program - '{STRING}' STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Index skladeb STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Program - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Vymazat +STR_PLAYLIST_CHANGE_SET :{BLACK}Změnit program STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Vyprázdnit současný program (jen u Voleb 1 a 2) STR_PLAYLIST_TOOLTIP_CHANGE_SET :{BLACK}Změnit výběr hudby na jinou nainstalovanou sadu. STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Skladba se přidá do zvoleného programu (Volba 1 nebo 2) klepnutím na její název @@ -1016,6 +1024,10 @@ STR_GAME_OPTIONS_CURRENCY_CUSTOM :Vlastní... STR_GAME_OPTIONS_CURRENCY_GEL :Georgijské Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Íránský Riál (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Ruský rubl (RUB) +STR_GAME_OPTIONS_CURRENCY_MXN :Mexické peso (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :Nový taiwanský dolar (NTD) +STR_GAME_OPTIONS_CURRENCY_CNY :Čínský renminbi (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Hongkongský dolar (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Silniční vozidla jezdí @@ -1072,14 +1084,18 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Zvolit r STR_GAME_OPTIONS_RESOLUTION_OTHER :jiné STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Velikost rozhraní -STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Zvolil velikost prvků uživatelského rozhraní +STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Zvolit velikost prvků uživatelského rozhraní STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normální STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Dvojnásobná velikost STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Čtyřnásobná velikost +STR_GAME_OPTIONS_FONT_ZOOM :{BLACK}Velikost písma +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Zvolit velikost písma STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Běžné +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Dvojnásobná velikost +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :Čtyřnásobná velikost STR_GAME_OPTIONS_BASE_GRF :{BLACK}Základní sada grafiky STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Zvol základní sadu grafiky @@ -1263,6 +1279,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Povolit srovná STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Povoluje změnu terénu pod budovami a tratěmi bez jejich odstranění STR_CONFIG_SETTING_CATCHMENT :Povolit u oblasti pokrytí realističtější velikost: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Rozdílná velikost oblasti pokrytí u různých stanic a letišť +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Obsluhovat průmysl s vlastní stanicí i prostřednictvím jiných stanic: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Pokud je zapnuto, průmysl s vlastní stanicí (např. ropné plošiny) může být obsluhován i prostřednictvím společnostmi vlastněných stanic v okolí. Pokud je vypnuto, tento průmysl může být obsluhován pouze prostřednictvím vlastní stanice. Společnostmi vlastněné stanice v okolí nebudou moci tento průmysl obsluhovat a vlastní stanice tohoto průmyslu nebude moci obsluhovat žádný jiný průmysl ani domy v okolí. STR_CONFIG_SETTING_EXTRADYNAMITE :Povolit bourání více městských silnic, mostů a tunelů: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Usnadňuje odstranění městských staveb a silnic STR_CONFIG_SETTING_TRAIN_LENGTH :Maximální délka vlaků: {STRING} @@ -1279,8 +1297,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Strnost svahů STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Strmost svahu pro silniční vozidla: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Vyšší hodnoty ztěžují vozidlům výjezd do kopce -STR_CONFIG_SETTING_FORBID_90_DEG :Zakázat vlakům a lodím otáčení o 90 stupňů: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90° zatočení nastane ve chvíli, kdy vodorovná kolej přímo navazuje na svislou kolej na vedlejším políčku. Vlak tak zatáčí o 90° místo klasických 45° u jiných kombinací kolejí. Ovlivní i zatáčení lodí. +STR_CONFIG_SETTING_FORBID_90_DEG :Zakázat vlakům otáčení o 90 stupňů: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90° zatočení nastane ve chvíli, kdy vodorovná kolej přímo navazuje na svislou kolej na vedlejším políčku. Vlak tak zatáčí o 90° místo klasických 45° u jiných kombinací kolejí. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Umožnit spojení nesousedících stanic: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Povolit přidávání částí stanice, které se nedotýkají již existujících částí. Je potřeba stisknout Ctrl při přidávání nových částí. STR_CONFIG_SETTING_INFLATION :Inflace: {STRING} @@ -1336,8 +1354,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Poměr rychlost STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Nastavit poměr rychlostí letadel ku ostatním dopravním prostředům, pro snížení zisku z nákladu převáženého letadly. STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Počet leteckých havárií: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Určuje šanci na havárii letadel -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Žádný +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Určuje pravděpodobnost leteckých neštěstí.{}* Při přistávání velkých letadel na malých letištích hrozí zvýšené nebezpeší havárie vždy. +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Žádná* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Redukovaný STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Obvyklý STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Stavba průjezdných zastávek na obecních silnicích: {STRING} @@ -1348,6 +1366,8 @@ STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Toto nas STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Udržování infrastruktury: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Pokud je zapnuto, je třeba platit za údržbu infrastruktury. Náklady vzrůstají společně s velikostí dopravní sítě, takže velké společnosti platí více než malé. +STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR :Počáteční barva společnosti: {STRING} +STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_HELPTEXT :Vyberte počáteční barvu společnosti STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Žádný druh letiště nezastará: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Povolení této možnosti způsobí, že všechny druhy letišť zůstanou po uvedení dostupné napořád. (nezastarají). @@ -1393,8 +1413,8 @@ STR_CONFIG_SETTING_TERRAIN_TYPE :Druh terénu: { STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(pouze TerraGenesis) Hornatost terénu STR_CONFIG_SETTING_INDUSTRY_DENSITY :Množství průmyslu: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Nastavuje množství průmyslu, které bude nyní vytvořeno a udržováno v průběhu hry -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maximální vzdálenost rafinerie od okraje mapy: {STRING} -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Ropné rafinerie jsou stavěny pouze blízko okrajům mapy. Pokud je mapa ostrov, pak je to pobřeží. +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maximální vzdálenost ropného průmyslu od okraje mapy: {STRING} +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Omezení, jak daleko od okrajů mapy mohou být postaveny rafinerie a ropné vrty. Je-li při okraji mapy voda, toto omezení zajišťuje, že se rafinerie a ropné vrty vyskytují poblíž pobřeží. Na mapách větších než 256 polí je toto omezení úměrně přizpůsobeno. STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Výška sněhové čáry: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Určuje o jaké výšky se vyskytuje sníh u subarktického klimatu. Sníh rovněž ovlivňuje vytváření průmyslu a požadavky na růst měst STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Členitost krajiny: {STRING} @@ -1432,7 +1452,12 @@ STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Barva terénu n STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :zelená STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :tmavě zelená STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :fialová +STR_CONFIG_SETTING_SCROLLMODE :Reakce pohledů na scrollování: {STRING} +STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT :Reakce na scrollování v mapě +STR_CONFIG_SETTING_SCROLLMODE_DEFAULT :Pohyb v pohledu pomocí pravého tlačítka myši, poloha myši uzamčena STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Pohyb v mapě pomocí pravého tlačítka myši, poloha myši uzamčena +STR_CONFIG_SETTING_SCROLLMODE_RMB :Pohyb v mapě pomocí pravého tlačítka myši +STR_CONFIG_SETTING_SCROLLMODE_LMB :Pohyb v mapě pomocí levého tlačítka myši STR_CONFIG_SETTING_SMOOTH_SCROLLING :Plynulé posouvání po mapě: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Ovládá jak se hlavní pohled posouvá na specifické místo na mapě, kliknutím na minimapu nebo spuštěním příkazu na posun na specifický objekt na mapě. Pokud zapnuto, pohled se posouvá plynule, pokud vypnuto, skáče pohled přímo na cílové místo STR_CONFIG_SETTING_MEASURE_TOOLTIP :Ukázat rozměry při použití stavebních nástrojů: {STRING} @@ -1553,6 +1578,9 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Povolit AI v s STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Umožňuje AI počítačem řízeným hráčům připojit se do hry s více hráči STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes před skripty než budou pozastaveny: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximální počet výpočetních kroků, které může skript vykonat za jeden tah +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Max. využití paměti skriptem: {STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :Určuje, kolik paměti může každý skript využít. Při překročení bude okamžitě ukončen. Pro větší mapy bude možná třeba tuto hodnotu zvýšit. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Intervaly servisů v procentech: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Vyber, jestli potřebu návštěvy servisu určuje čas od poslední návštěvy nebo určitý pokles % spolehlivosti od jejího maxima. @@ -1655,6 +1683,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Povoluje hráč STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Zakázáno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Povoleno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Povoleno s výběrem rozložení a velikosti města +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Produkce nákladu městy: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Určuje, kolik nákladu je produkováno domy ve městě relativně k celkovému počtu obyvatel města.{}Kvadratická závislost: Dvakrát větší město produkuje čtyřikrát více cestujících.{}Lineární závislost: Dvakrát větší město produkuje dvakrát více cestujících. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Kvadratický (původní) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineární STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Umístění stromů ve hře: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Náhodné umisťování stromů během hry. Může ovlivnit průmysl závisející na růstu stromů, například pily. @@ -1782,7 +1814,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distrib STR_CONFIG_SETTING_AI :{ORANGE}Konkurenti STR_CONFIG_SETTING_AI_NPC :{ORANGE}Umělá inteligence -STR_CONFIG_SETTING_PATHFINDER_OPF :Původní STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(doporučený) @@ -1866,13 +1897,9 @@ STR_QUIT_NO :{BLACK}Ne # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unixu STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -1901,6 +1928,7 @@ STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Změnit STR_CHEAT_SETUP_PROD :{LTBLUE}Povolit změnu produkce průmyslu: {ORANGE}{STRING} # Livery window +STR_LIVERY_CAPTION :{WHITE}{COMPANY} - barevné schéma STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Zobrazit všeobecná barevná schémata STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Zobrazit barevná schémata pro vlaky @@ -2160,6 +2188,7 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Odpojit STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server je chráněný. Napiš heslo STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Společnost je chráněná. Napiš heslo +STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :Seznam klientů # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Seznam hráčů @@ -2208,7 +2237,7 @@ STR_NETWORK_CHAT_ALL :[Všichni] {STR STR_NETWORK_CHAT_OSKTITLE :{BLACK}Zadej zprávu # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Žádná síťová zařízení nebyla nalezena (nebo je hra zkompilována bez ENABLE_NETWORK) +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Žádná síťová zařízení nebyla nalezena STR_NETWORK_ERROR_NOSERVER :{WHITE}Nenalezena žádná síťová hra STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Server neodpověděl na požadavek STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Nelze se připojit kvůli rozdílným grafikám @@ -2500,6 +2529,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Postavit STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Postavit tramvajový tunel. Stisknutý Shift pro zobrazení odhadu ceny STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Stavět nebo bourat silnici nebo zastávku STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Přepínání mezi výstavbou a bouráním tramvajové tratě +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Změnit nebo vylepšit typ silnice (na tento). Stisknutý Shift pro zobrazení odhadu ceny +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Změnit nebo vylepšit druh tramvajové tratě (na tento). Stisknutý Shift pro zobrazení odhadu ceny + +STR_ROAD_NAME_ROAD :Silnice +STR_ROAD_NAME_TRAM :Tramvajová trať # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Orientace garáže @@ -2690,8 +2724,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Přijímané zboží: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Druh kolejí: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Typ silnice: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Typ tramvaje: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rychlostní omezení tratě: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Rychlostní omezení silnice: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Omezení rychlosti pro tramvaje: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Kamení @@ -2792,32 +2829,59 @@ STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD # Framerate display window STR_FRAMERATE_CAPTION :{WHITE}Počet snímků za sekundu +STR_FRAMERATE_CAPTION_SMALL :{STRING}{WHITE} ({DECIMAL}x) +STR_FRAMERATE_RATE_GAMELOOP :{BLACK}Rychlost simulace: {STRING} +STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP :{BLACK}Počet kroků hry simulovaných za 1 sekundu. +STR_FRAMERATE_RATE_BLITTER :{BLACK}Počet snímků za sekundu: {STRING} STR_FRAMERATE_RATE_BLITTER_TOOLTIP :{BLACK}Počet snímků videa vykreslovaných za sekundu. -STR_FRAMERATE_SPEED_FACTOR :{WHITE}Aktuální činitel rychlosti hry: {DECIMAL}x +STR_FRAMERATE_SPEED_FACTOR :{BLACK}Aktuální činitel rychlosti hry: {DECIMAL}x STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}Rychlost, kterou hra právě běží, v porovnání s očekávanou rychlostí při běžné rychlosti simulace. STR_FRAMERATE_CURRENT :{WHITE}Aktuální STR_FRAMERATE_AVERAGE :{WHITE}Průměr +STR_FRAMERATE_MEMORYUSE :{WHITE}Paměť STR_FRAMERATE_DATA_POINTS :{BLACK}Podle {COMMA} měření STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms -STR_FRAMERATE_MS_BAD :{RED}{DECIMAL}{WHITE} ms -STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL}{WHITE} sním{P "ek" "ky" "ků"}/s -STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL}{WHITE} sním{P "ek" "ky" "ků"}/s +STR_FRAMERATE_MS_WARN :{YELLOW}{DECIMAL} ms +STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} ms +STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} sním{P "ek" "ky" "ků"}/s +STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} sním{P "ek" "ky" "ků"}/s +STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} sním{P "ek" "ky" "ků"}/s +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! -STR_FRAMERATE_GL_ECONOMY :{WHITE} Manipulace s nákladem: +STR_FRAMERATE_GAMELOOP :{BLACK}Herní smyčka celkem: +STR_FRAMERATE_GL_ECONOMY :{BLACK} Manipulace s nákladem: +STR_FRAMERATE_GL_TRAINS :{BLACK} Kroky vlaků: +STR_FRAMERATE_GL_ROADVEHS :{BLACK} Kroky silničních vozidel: +STR_FRAMERATE_GL_SHIPS :{BLACK} Kroky lodí: +STR_FRAMERATE_GL_AIRCRAFT :{BLACK} Kroky letadel: +STR_FRAMERATE_GL_LANDSCAPE :{BLACK} Kroky terénu: STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Zpoždění grafu spojení: -STR_FRAMERATE_DRAWING :{WHITE}Vykreslování grafiky: +STR_FRAMERATE_DRAWING :{BLACK}Vykreslování grafiky: STR_FRAMERATE_DRAWING_VIEWPORTS :{BLACK} Pohledy: STR_FRAMERATE_VIDEO :{BLACK}Video: STR_FRAMERATE_SOUND :{BLACK}Míchání zvuků: +STR_FRAMERATE_ALLSCRIPTS :{BLACK} Skripty/AI celkem: STR_FRAMERATE_GAMESCRIPT :{BLACK} Herní skript: +STR_FRAMERATE_AI :{BLACK} AI {NUM} {STRING} ############ End of leave-in-this-order ############ Leave those lines in this order!! STR_FRAMETIME_CAPTION_GAMELOOP :Herní smyčka STR_FRAMETIME_CAPTION_GL_ECONOMY :Manipulace s nákladem +STR_FRAMETIME_CAPTION_GL_TRAINS :Kroky vlaků +STR_FRAMETIME_CAPTION_GL_ROADVEHS :Kroky silničních vozidel +STR_FRAMETIME_CAPTION_GL_SHIPS :Kroky lodí +STR_FRAMETIME_CAPTION_GL_AIRCRAFT :Kroky letadel +STR_FRAMETIME_CAPTION_GL_LANDSCAPE :Kroky terénu +STR_FRAMETIME_CAPTION_GL_LINKGRAPH :Zpoždění grafu spojení STR_FRAMETIME_CAPTION_DRAWING :Vykreslování grafiky +STR_FRAMETIME_CAPTION_DRAWING_VIEWPORTS :Vykreslování pohledů +STR_FRAMETIME_CAPTION_VIDEO :Video STR_FRAMETIME_CAPTION_SOUND :Míchání zvuků +STR_FRAMETIME_CAPTION_ALLSCRIPTS :Herní skripty/AI celkem STR_FRAMETIME_CAPTION_GAMESCRIPT :Herní skript STR_FRAMETIME_CAPTION_AI :AI {NUM} {STRING} ############ End of leave-in-this-order @@ -2847,6 +2911,7 @@ STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}Grafiky: {WHITE}{STRING} STR_SAVELOAD_FILTER_TITLE :{BLACK}Filtr: STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}Přepsat soubor +STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}Opravdu chcete přepsat existující soubor? STR_SAVELOAD_OSKTITLE :{BLACK}Zadej jméno pro uloženou hru @@ -2964,6 +3029,10 @@ STR_NEWGRF_SETTINGS_VERSION :{BLACK}Verze: { STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Minimální kompatibilní verze: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Paleta: {SILVER}{STRING} +STR_NEWGRF_SETTINGS_PALETTE_DEFAULT :Výchozí (D) +STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :32 bpp +STR_NEWGRF_SETTINGS_PALETTE_LEGACY :Originální (W) +STR_NEWGRF_SETTINGS_PALETTE_LEGACY_32BPP :Originální (W) / 32 bpp STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parametry: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER_NONE :Žádný @@ -3143,6 +3212,8 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Přejmenovat m # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}Místní správa města {TOWN} +STR_LOCAL_AUTHORITY_ZONE :{BLACK}Oblast +STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}Zobrazit oblast působnosti místní správy STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Hodnocení společností: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Možné činnosti: @@ -3171,6 +3242,7 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Podplat # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Cíle STR_GOALS_SPECTATOR_CAPTION :{WHITE}Globální cíle +STR_GOALS_SPECTATOR :Globální cíle STR_GOALS_GLOBAL_TITLE :{BLACK}Globální cíle: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Žádné - @@ -3399,8 +3471,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Železniční oblasti: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Semafory STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Silniční oblasti: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Silnice -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajové koleje STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vodní oblasti: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Průplavy STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stanice: @@ -3425,6 +3495,8 @@ STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Produkce STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Průmysl oznámila blížící se uzavření! STR_INDUSTRY_VIEW_REQUIRES_N_CARGO :{BLACK}Vyžaduje: {YELLOW}{STRING}{STRING} +STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Produkuje: {YELLOW}{STRING}{STRING} +STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Vyžaduje: STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{STRING}{BLACK}{3:STRING} @@ -3478,10 +3550,13 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Nezařazená si STR_GROUP_DEFAULT_SHIPS :Nezařazené lodě STR_GROUP_DEFAULT_AIRCRAFTS :Nezařazená letadla +STR_GROUP_COUNT_WITH_SUBGROUP :{TINY_FONT}{COMMA} (+{COMMA}) + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Skupiny - Kliknutím na skupinu se zobrazí seznam vozidel ve skupině. Přetáhnutím skupin je uspořádáš. STR_GROUP_CREATE_TOOLTIP :{BLACK}Kliknutím vytvoříš skupinu STR_GROUP_DELETE_TOOLTIP :{BLACK}Vymazat vybranou skupinu STR_GROUP_RENAME_TOOLTIP :{BLACK}Přejmenovat vybranou skupinu +STR_GROUP_LIVERY_TOOLTIP :{BLACK}Změnit nátěr vozidel vybrané skupiny STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Kliknutím nebude na tuto skupinu mít vliv automatická výměna vozidel STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Smazat Skupinu @@ -3503,12 +3578,18 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nové elektrick STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nové lokomotivy a vagony pro monorail STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nové lokomotivy a vagony Maglev -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nová železniční vozidla STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nová silniční vozidla +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :Nové tramvaje + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nová železniční vozidla +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :Nová silniční vozidla STR_BUY_VEHICLE_SHIP_CAPTION :Nové lodě STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nové letadlo +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Hmotnost: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} (Cena přestavby: {GOLD}{CURRENCY_LONG}{BLACK}) Hmotnost: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Rychlost: {GOLD}{VELOCITY}{BLACK} Výkon: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Rychlost: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Rychlost na moři: {GOLD}{VELOCITY} @@ -3519,12 +3600,15 @@ STR_PURCHASE_INFO_REFITTABLE :(lze přestavě STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Vyvinuto: {GOLD}{NUM}{BLACK} Životnost: {GOLD}{COMMA} {P rok roky let} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. spolehlivost: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cena: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Náklady: {GOLD}{CURRENCY_LONG}{BLACK} (Náklady na přestavbu: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Hmotnost: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Rychlost: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} (Cena přestavby: {GOLD}{CURRENCY_LONG}{BLACK}) Rychlost: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Kapacita: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Poháněné vagony: {GOLD}+{POWER}{BLACK} Hmotnost: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Refitovatelné na: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Všechny druhy nákladu +STR_PURCHASE_INFO_NONE :Žádné STR_PURCHASE_INFO_ALL_BUT :Všechny kromě {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. tažná síla: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Dosah: {GOLD}{COMMA} polí @@ -3540,11 +3624,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Koupit v STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Koupit loď STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Koupit letadlo +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Koupit a přestavět vozy +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Koupit a přestavět vozidlo +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Koupit a přestavět loď +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :Koupit a přestavět letadlo + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Kup označený vagon/lokomotivu. Stisknutý Shift pro zobrazení odhadu ceny STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Koupit označené vozidlo. Stisknutý Shift pro zobrazení odhadu ceny STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Koupit označenou loď. Stisknutý Shift pro zobrazení odhadu ceny STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Koupit označené letadlo. Stisknutý Shift pro zobrazení odhadu ceny +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :Koupit a přestavět označený vagon/lokomotivu. Stiskněte Shift pro zobrazení odhadu ceny. +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koupit a přestavět označené vozidlo. Stiskněte Shift pro zobrazení odhadu ceny. +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koupit a přestavět označenou loď. Stiskněte Shift pro zobrazení odhadu ceny. +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koupit a přestavět označené letadlo. Stiskněte Shift pro zobrazení odhadu ceny. + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Přejmenovat STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Přejmenovat STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Přejmenovat @@ -3653,16 +3747,21 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Chceš # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Zpráva od výrobce dopravních prostředků STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Právě jsme vyvinuli nov{G ý ou é é é é á} {STRING.acc}. Měl byste zájem o roční výhradní právo na používání tohoto prostředku, aby byl otestován před uvedením na trh? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :{G=f}lokomotiva STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE.acc :lokomotivu -STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=n}silniční vozidlo -STR_ENGINE_PREVIEW_AIRCRAFT :{G=n}letadlo -STR_ENGINE_PREVIEW_SHIP :{G=f}loď +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :elektrická lokomotiva STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :{G=f}lokomotiva pro monorail STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE.acc :lokomotivu pro monorail STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :{G=f}lokomotiva Maglev STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE.acc :lokomotivu Maglev +STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=n}silniční vozidlo +STR_ENGINE_PREVIEW_TRAM_VEHICLE :tramvaj + +STR_ENGINE_PREVIEW_AIRCRAFT :{G=n}letadlo +STR_ENGINE_PREVIEW_SHIP :{G=f}loď + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cena: {CURRENCY_LONG} Hmotnost: {WEIGHT_SHORT}{}Rychlost: {VELOCITY} Výkon: {POWER}{}Cena provozu: {CURRENCY_LONG} ročně{}Kapacita: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cena: {CURRENCY_LONG} Váha: {WEIGHT_SHORT}{}Rychlost: {VELOCITY} Síla: {POWER} Maximální tažná síla: {6:FORCE}{}Provozní náklady: {4:CURRENCY_LONG}/rok{}Kapacita: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Max. rychlost: {VELOCITY}{}Kapacita: {CARGO_LONG}{}Cena provozu: {CURRENCY_LONG} ročně @@ -3700,14 +3799,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Přepne STR_REPLACE_ENGINES :lokomotivy STR_REPLACE_WAGONS :vagony STR_REPLACE_ALL_RAILTYPE :Všechna drážní vozidla +STR_REPLACE_ALL_ROADTYPE :Všechna silniční vozidla STR_REPLACE_HELP_RAILTYPE :{BLACK}Vyber typ kolejí, pro které chceš měnit lokomotivy +STR_REPLACE_HELP_ROADTYPE :{BLACK}Vyber typ silnice, pro které chceš nahrazovat vozidla STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Tady je zobrazeno, za jakou lokomotivu se ta v levém seznamu vyměňuje STR_REPLACE_RAIL_VEHICLES :Železniční lokomotivy STR_REPLACE_ELRAIL_VEHICLES :Elektrické lokomotivy STR_REPLACE_MONORAIL_VEHICLES :Lokomotivy pro monorail STR_REPLACE_MAGLEV_VEHICLES :Lokomotivy Maglev +STR_REPLACE_ROAD_VEHICLES :Silniční vozidla +STR_REPLACE_TRAM_VEHICLES :Tramvaje + STR_REPLACE_REMOVE_WAGON :{BLACK}Odebírání vagonů: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Funkce automatického vylepšování vlaků může udržovat stejnou délku vlaku odstraňovaním vagonů (od začátku vlaku), pokud by změna mašiny vlak prodloužila @@ -3851,7 +3955,7 @@ STR_REFIT_CAPTION :{WHITE}{VEHICLE STR_REFIT_TITLE :{GOLD}Zvolit druh nákladu: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nová kapacita: {GOLD}{CARGO_LONG}{}{BLACK}Cena přestavby: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Nová kapacita: {GOLD}{CARGO_LONG}{}{BLACK}Příjem za přestavbu: {GREEN}{CURRENCY_LONG} -STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Nová kapacita: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cena za předělání: {RED}{CURRENCY_LONG} +STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Nová kapacita: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cena přestavby: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Nová kapacita: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Výnos z přestavby: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Vybere vozidla k obnově. Tažení myší vybere více vozidel. Kliknutí na prázdné místo vybere celé vozidlo. Ctrl+Click vybere vozidlo a následující řetěz @@ -3927,6 +4031,7 @@ STR_ORDER_CONDITIONAL_AGE :Stáří vozidl STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Vyžaduje údržbu STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Vždy STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Zbývající životnost (v letech) +STR_ORDER_CONDITIONAL_MAX_RELIABILITY :Nejvyšší dosažitelná spolehlivost STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Jak porovnat vlastnost vozidla se zadanou hodnotou STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :se rovná @@ -4428,7 +4533,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Je nutn STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Žádné použitelné koleje STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Je nutné nejprve odstranit koleje STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Silnice je jednosměrná nebo zablokovaná -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Železniční přejezd není povolen pro tento typ kolejí +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Tento typ kolejí nedovoluje výstavbu železničních přejezdů +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Tento typ silnice nedovoluje výstavbu železničních přejezdů. STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Zde nelze postavit semafory... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Zde nelze postavit koleje... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Odsud nelze odstranit koleje... @@ -4448,6 +4554,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Odsud ne STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Odsud nelze odstranit tramvajovou trať... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... není zde žádná silnice STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... není zde žádná tramvajová trať +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Zde nelze změnit typ silnice... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Zde nelze změnit druh tramvajové tratě... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Neexistuje vhodná silnice +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}Neexistuje vhodná tramvajová trať +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... nevhodný druh silnice +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... nevhodný typ tramvajové tratě # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Zde nelze postavit průplav... @@ -4507,6 +4619,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Nelze vy STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Nelze vymazat skupinu... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Nelze přejmenovat skupinu... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Nelze nastavit nadřazenou skupinu +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... skupina nemůže patřit do skupiny, která patří pod ní STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Nelze odstranit všechna vozidla ze skupiny... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Nelze přidat vozidlo do skupiny... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Nelze přidat sdílená vozidla do skupiny... diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 78ee9195b9..090997d49f 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -358,6 +358,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landskab STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Bygenerering STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industrigenerering STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Bygning af vej +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Sporvejskonstruktion STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant træer. Shift skifter mellem at bygge og vise prisoverslag. STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Placér skilt STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Placér objekt. Shift viser tidsestimat @@ -1184,6 +1185,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Tillad landskab STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Tillad landskabsformning under bygninger og spor uden at fjerne dem STR_CONFIG_SETTING_CATCHMENT :Tillad mere realistisk størrelse på stationernes opland: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Har forskellige størrelser oplande til forskellige typer af stationer og lufthavne +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Selskabers stationer kan betjene industrier med tilknyttede neutrale stationer: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Når aktiveret kan industries med tilknyttede stationer (så som Boreplatforme) også betjenes af andre selskabers stationer i nærheden. Når deaktiveret, kan disse industrier kun betjenes af deres egen tilknyttede station. Andre stationer i nærheden kan ikke betjene dem, og industriens tilknyttede station vil heller ikke betjene andet end industrien. STR_CONFIG_SETTING_EXTRADYNAMITE :Tillad nedriving af flere by-ejede veje, broer og tunneler: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Gør det nemmere at fjerne by-ejede infrastruktur og bygninger STR_CONFIG_SETTING_TRAIN_LENGTH :Den maksimale længde af tog: {STRING} @@ -1200,8 +1203,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Stejlhed af skr STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Skrånings stejlhed for vejkøretøjer: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Stejlhed af skrå felter for vej køretøjer. Højere værdier gør det vanskeligere at bestige en bakke -STR_CONFIG_SETTING_FORBID_90_DEG :Forbyd skibe og tog at dreje 90 grader: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 graders drejninger forekommer når et horisontalt spor er direkte efterfulgt af et lodret spor stykke på det tilstødende felt, hvorved toget drejer 90 grader ved kørsel på feltets kant stedet for de sædvanlige 45 grader for andre spor kombinationer. Dette gælder også for drejeradius af skibe +STR_CONFIG_SETTING_FORBID_90_DEG :Forbyd tog at dreje 90 grader: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 graders drejninger forekommer når et vandret sporstykke er direkte efterfulgt af et lodret sporstykke på det tilstødende felt. Således drejer toget 90 grader når det passerer feltets kant, i stedet for de sædvanlige 45 grader for andre sporkombinationer. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Tillad sammenkædning af stationer der ikke ligger direkte op ad hinanden: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Tillad at tilføje dele til en station uden direkte at berøre eksisterende dele. Ctrl+Klik for at sætte nye dele STR_CONFIG_SETTING_INFLATION :Inflation: {STRING} @@ -1257,8 +1260,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Fly hastigheds- STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Indstil den relative hastighed af fly i forhold til andre køretøjstyper, for at reducere mængden af indkomst for transport med fly STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Antal flystyrt: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Angiv chancen for et flystyrt sker -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ingen +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Angiv sandsynligheden for at fly styrter ned.{}* Store fly har altid en risiko for at styrte når de lander på små lufthavne. +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ingen* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :reduceret STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Tillad gennemkørsels-stop på veje ejet af en by: {STRING} @@ -1583,6 +1586,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Hvis denne inds STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbudt STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Tilladt STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Tilladt, tilpasset by-layout +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Godsgenerering i byer: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Hvor meget gods der bliver produceret af byers bygninger, i forhold til byens samlede indbyggertal.{}Kvadratisk vækst: En by med dobbelt indbyggertal genererer fire gange så mange passagerer.{}Lineær vækst: En by med dobbelt indbyggertal genererer dobbelt så mange passagerer. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Kvadratisk (original) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineær STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Placering af træer i spillet: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Kontroller den tilfældige fremkomst af træer i løbet af spillet. Dette vil påvirke industrier der afhænger træers vækst, f.eks. savværker @@ -1710,7 +1717,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Fragtdi STR_CONFIG_SETTING_AI :{ORANGE}Modstandere STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computerstyrede spillere -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Anbefalet) @@ -1794,13 +1800,9 @@ STR_QUIT_NO :{BLACK}Nej # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2138,7 +2140,7 @@ STR_NETWORK_CHAT_ALL :[Alle] {STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Skriv tekst i netværks-chat # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Ingen netværksheder fundet eller kompilet uden ENABLE_NETWORK +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Ingen netværksheder fundet STR_NETWORK_ERROR_NOSERVER :{WHITE}Kunne ikke finde nogen netværksspil STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Serveren besvarede ikke denne forspørgsel STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Kunne ikke tilslutte grundet NewGRF ulighed @@ -2431,6 +2433,8 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Byg en s STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Skift mellem bygning/fjernelse af veje STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Skift mellem bygning/fjernelse af sporveje +STR_ROAD_NAME_TRAM :Sporvej + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Retning af værksted STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Vælg retning for værksted @@ -3355,8 +3359,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spor-stykker: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vej-stykker: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Vej -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Sporvogne STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vand-felter: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanaler STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stationer: @@ -3436,6 +3438,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Ikke-grupperede STR_GROUP_DEFAULT_SHIPS :Ikke-grupperede skibe STR_GROUP_DEFAULT_AIRCRAFTS :Ikke-grupperede fly + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupper - klik på en gruppe for at vise alle køretøjer i gruppen STR_GROUP_CREATE_TOOLTIP :{BLACK}Klik for at oprette en gruppe STR_GROUP_DELETE_TOOLTIP :{BLACK}Slet den valgte gruppe @@ -3462,10 +3465,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nye elektriske STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nye monorailkøretøjer STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nye magnetskinnekøretøjer -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Jernbanekøretøjer STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nye køretøjer + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Jernbanekøretøjer STR_BUY_VEHICLE_SHIP_CAPTION :Nye skibe STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nyt fly +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Pris: {GOLD}{CURRENCY_LONG}{BLACK} Vægt: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Hastighed: {GOLD}{VELOCITY}{BLACK} Styrke: {GOLD}{POWER} @@ -3500,11 +3506,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Køb kø STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Køb skib STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Køb et fly + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Køb det markerede lokomotiv/togvogn. Shift skifter mellem at købe og vise prisoverslag. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Køb det markerede køretøj. Shift skifter mellem at købe og vise prisoverslag. STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Køb det markerede skib. Shift skifter mellem at købe og vise prisoverslag. STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Køb det markerede fly. Shift skifter mellem at købe og vise prisoverslag. + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Omdøb STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Omdøb STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Omdøb @@ -3613,13 +3621,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Du er v # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Besked fra køretøjsfabrikken STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Vi har lige designet et nyt {STRING} - er du interesseret i et års ekslusiv testkørsel, så vi kan se hvordan det klarer sig inden vi gør det frit tilgængeligt? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :jernbanelokomotiv -STR_ENGINE_PREVIEW_ROAD_VEHICLE :vejkøretøj -STR_ENGINE_PREVIEW_AIRCRAFT :fly -STR_ENGINE_PREVIEW_SHIP :skib STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monoraillokomotiv STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :magnettog +STR_ENGINE_PREVIEW_ROAD_VEHICLE :vejkøretøj + +STR_ENGINE_PREVIEW_AIRCRAFT :fly +STR_ENGINE_PREVIEW_SHIP :skib + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Pris: {CURRENCY_LONG} Vægt: {WEIGHT_SHORT}{}Hastighed: {VELOCITY} Styrke: {POWER}{}Driftsomkostninger: {CURRENCY_LONG}/år{}Kapacitet: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Pris: {CURRENCY_LONG} Vægt: {WEIGHT_SHORT}{}Hastighed: {VELOCITY} Hestekræfter: {POWER} Maks. Trækkraft: {6:FORCE}{}Driftsomkostning: {4:CURRENCY_LONG}/år{}Kapacitet: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Pris: {CURRENCY_LONG} Maks. hast.: {VELOCITY}{}Kapacitet: {CARGO_LONG}{}Driftsomkostninger: {CURRENCY_LONG}/år @@ -3665,6 +3676,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Eltog STR_REPLACE_MONORAIL_VEHICLES :Monorail STR_REPLACE_MAGLEV_VEHICLES :Magnetskinnetog + STR_REPLACE_REMOVE_WAGON :{BLACK}Fjern vogn: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Få autoudskift til at bevare længden af tog ved at fjerne vogne (startende fra fronten), hvis autoudskiftningen gør toget længere. @@ -4386,7 +4398,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Det er n STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ingen brugbar jernbane STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Det er nødvendigt at fjerne jernbaneskinnerne først STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vejen er ensrettet eller blokeret -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Niveaukrydsning ikke tilladt for denne type skinner +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Niveaukrydsning ikke tilladt for denne type skinner STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan ikke bygge signaler her... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan ikke bygge jernbane her... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan ikke fjerne jernbane herfra... diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 7c34329d6a..6ab4d95992 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -237,6 +237,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Selectee STR_BUTTON_SORT_BY :{BLACK}Sorteren op STR_BUTTON_LOCATION :{BLACK}Locatie STR_BUTTON_RENAME :{BLACK}Hernoemen +STR_BUTTON_CATCHMENT :{BLACK}Dekking +STR_TOOLTIP_CATCHMENT :{BLACK}Schakelt weergave van dekkingsgebied om STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Venster sluiten STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Vensternaam - sleep om venster te verplaatsen @@ -265,6 +267,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Wanneer STR_BUTTON_DEFAULT :{BLACK}Standaard STR_BUTTON_CANCEL :{BLACK}Annuleren STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Waarschuwing: het kan zijn dat serverbeheerders tekst niet kunnen lezen die hier wordt ingevoerd. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . @@ -338,6 +341,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Inzoomen STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Uitzoomen STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Spoorwegen bouwen STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Wegen bouwen +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Tramsporen bouwen STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Dokken en havens bouwen STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Vliegvelden bouwen STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Hiermee open je de landschapsbalk om land te verhogen/verlagen, bomen te planten, enz. @@ -358,6 +362,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscha STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Stadsontwikkeling STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industrieontwikkeling STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Wegenbouw +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Tramsporen bouwen STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Bomen planten. Shift schakelt tussen planten/inschatting van de kosten STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Bord plaatsen STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Object plaatsen. Shift schakelt tussen bouwen/inschatting van de kosten @@ -933,6 +938,9 @@ STR_GAME_OPTIONS_CURRENCY_GEL :Georgische Lari STR_GAME_OPTIONS_CURRENCY_IRR :Iraanse Rial (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Nieuwe Russische Roebel (RUB) STR_GAME_OPTIONS_CURRENCY_MXN :Mexicaanse peso (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :Nieuwe Taiwanse dollar (NTD) +STR_GAME_OPTIONS_CURRENCY_CNY :Chinese Renminbi (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dollar (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Wegvoertuigen @@ -1184,6 +1192,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Omgeving aanpas STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Staat het aanpassen van funderingen onder gebouwen en sporen toe zonder deze te verwijderen STR_CONFIG_SETTING_CATCHMENT :Meer realistische verzorgingsgebieden toestaan: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Verzorgingsgebieden met verschillende groottes voor verschillende typen stations en luchthavens +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Stations van het bedrijf kunnen leveren aan industrieën met bijbehorend neutraal station: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Wanneer dit is ingeschakeld, kunnen industrieën met bijbehorende stations (zoals olievelden) ook worden voorzien door stations van het bedrijf die in de buurt zijn gebouwd. Wanneer dit is uitgeschakeld, kunnen deze industrieën alleen worden voorzien door het bijbehorende station. Eventuele stations van het bedrijif in de buurt kunnen niet aan ze leveren; ook levert het bijbehorende station alleen aan de industrie zelf. STR_CONFIG_SETTING_EXTRADYNAMITE :Verwijderen van meer stedelijke wegen, bruggen en tunnels toestaan: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Maakt het gemakkelijker om door de stad beheerde infrastructuur en gebouwen te verwijderen. STR_CONFIG_SETTING_TRAIN_LENGTH :Maximale lengte van treinen: {STRING} @@ -1201,7 +1211,7 @@ STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Hellingsteilheid voor wegvoertuigen: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steilheid van een schuine tegel voor een wegvoertuig. Hogere waarden maken het moeilijker om een heuvel te beklimmen STR_CONFIG_SETTING_FORBID_90_DEG :Treinen en schepen mogen niet 90° draaien: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Draaiingen met 90° treden op wanneer een horizontale baan direct gevolgd wordt door een verticaal baanstuk op de aangrenzende tegel, waardoor de trein daarna 90 graden draait wanneer de tegelrand wordt overgestoken in plaats van de gebruikelijke 45 graden voor andere spoorcombinaties. Dit geldt ook voor de draaicirkel van schepen +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Draaiingen met 90° treden op wanneer een horizontale baan direct gevolgd wordt door een verticaal baanstuk op de aangrenzende tegel, waardoor de trein daarna 90 graden draait wanneer de tegelrand wordt overgestoken in plaats van de gebruikelijke 45 graden voor andere spoorcombinaties. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Samenvoegen van indirect aansluitende stations toestaan: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Staat toe dat er aanvullende onderdelen aan een station worden geplaatst zonder dat reeds bestaande onderdelen beïnvloed worden. Ctrl+klik is vereist tijdens het plaatsen van nieuwe onderdelen. STR_CONFIG_SETTING_INFLATION :Inflatie: {STRING} @@ -1258,7 +1268,7 @@ STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Stel de relatie STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Aantal neerstortende vliegtuigen: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Bepaalt de kans op neerstorten van een vliegtuig -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Geen +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Geen* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Verminderd STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normaal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Haltes plaatsen op door stad beheerde wegen toestaan: {STRING} @@ -1481,6 +1491,9 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Computerspelers STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Computerspelers toestaan in netwerkspellen STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :Aantal opcodes voordat scripts worden gestopt: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximumaantal berekeningsstappen die een script kan maken in een beurt +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Max. geheugengebruik per script: {STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :De hoeveelheid geheugen die een script mag gebruiken voordat het geforceerd wordt beëindigd. Voor grote kaarten moet deze waarde misschien verhoogd worden. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Onderhoudstermijnen in procenten: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Kiest of onderhoud van de voertuigen wordt geactiveerd door verstreken tijd sinds het laatste onderhoud of door het zakken van de betrouwbaarheid met een bepaald percentage van de maximale betrouwbaarheid @@ -1543,6 +1556,8 @@ STR_CONFIG_SETTING_SMOOTH_ECONOMY :Vloeiende econo STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Wanneer dit is ingeschakeld, verandert de productie van industrieën vaker en in kleinere stappen. Deze instelling heeft meestal geen effect als de industriesoorten worden geleverd door een NewGRF. STR_CONFIG_SETTING_ALLOW_SHARES :Kopen van aandelen in andere bedrijven toestaan: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Wanneer ingeschakeld is het toegestaan om bedrijfsaandelen te kopen en te verkopen. Aandelen zullen alleen beschikbaar zijn voor bedrijven die een bepaalde leeftijd hebben bereikt +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :Minimale leeftijd van bedrijf om aandelen te kunnen verhandelen: {STRING} +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Hiermee wordt de minimale leeftijd van een bedrijf ingesteld waarna anderen aandelen in dat bedrijf kunnen gaan kopen en verkopen. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage van routeopbrengst in overdrachtssysteem: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage van het inkomen besteed aan de intermediaire delen in feedersystemen waardoor er meer controle over de inkomsten is STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Bij slepen, seinen plaatsen om de: {STRING} @@ -1583,6 +1598,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Wanneer deze in STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Verboden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Toestaan STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Toestaan, eigen wegpatroon +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Genereren van vracht in steden: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Hoeveel vracht wordt geproduceerd door huizen in steden, in relatie tot de totale bevolking van de stad.{}Kwadratische groei: een stad die twee keer zo groot is, genereert vier keer zo veel passagiers.{}Lineaire groei: een stad die twee keer zo groot is, genereert twee keer zo veel passagiers. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Kwadratisch (origineel) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineair STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Plaatsing van bomen in het spel: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Beheert het willekeurig verschijnen van bomen tijdens het spel. Dit kan gevolgen hebben voor industrietakken die afhankelijk zijn van groei van bomen, bijvoorbeeld houtzagerijen. @@ -1710,7 +1729,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Vrachtd STR_CONFIG_SETTING_AI :{ORANGE}Tegenstanders STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computerspelers -STR_CONFIG_SETTING_PATHFINDER_OPF :Origineel STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Aanbevolen) @@ -1794,13 +1812,9 @@ STR_QUIT_NO :{BLACK}Nee # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2138,7 +2152,7 @@ STR_NETWORK_CHAT_ALL :[Iedereen] {STR STR_NETWORK_CHAT_OSKTITLE :{BLACK}Geef tekst voor netwerkchat # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Geen netwerkapparaten gevonden of gecompileerd zonder ENABLE_NETWORK +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Geen netwerkapparaten gevonden STR_NETWORK_ERROR_NOSERVER :{WHITE}Kon geen enkel netwerkspel vinden STR_NETWORK_ERROR_NOCONNECTION :{WHITE}De server beantwoordde het verzoek niet STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Kan geen verbinding maken, je hebt niet dezelfde NewGRF-bestanden als de server @@ -2430,6 +2444,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Wegtunne STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Tramtunnel bouwen. Shift schakelt tussen bouwen/inschatting van de kosten. STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Kies tussen bouwen en verwijderen bij wegenbouw STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Kies tussen bouwen en verwijderen bij tramspooraanleg +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Converteer/opwaardeer het type weg. Shift schakelt tussen bouwen/inschatting van de kosten. +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Converteer/opwaardeer het type tram. Shift schakelt tussen bouwen/inschatting van de kosten. + +STR_ROAD_NAME_ROAD :Weg +STR_ROAD_NAME_TRAM :Tramspoor # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Richting van garage @@ -2614,8 +2633,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Geaccepteerde vracht: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Spoortype: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Wegtype: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tramtype: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Spoorsnelheidslimiet: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Snelheidslimiet weg: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tramsnelheidslimiet: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rotsen @@ -2725,6 +2747,7 @@ STR_FRAMERATE_SPEED_FACTOR :{BLACK}Huidige STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}Hoe snel het spel momenteel draait, vergeleken met de verwachte snelheid bij een normale simulatiesnelheid. STR_FRAMERATE_CURRENT :{WHITE}Huidig STR_FRAMERATE_AVERAGE :{WHITE}Gemiddeld +STR_FRAMERATE_MEMORYUSE :{WHITE}Geheugen STR_FRAMERATE_DATA_POINTS :{BLACK}Gegevens gebaseerd op {COMMA} metingen STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_WARN :{YELLOW}{DECIMAL} ms @@ -2732,6 +2755,9 @@ STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} frames/s STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} frames/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} frames/s +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! @@ -3098,6 +3124,8 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Plaats hernoeme # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE} Gemeenteraad van {TOWN} +STR_LOCAL_AUTHORITY_ZONE :{BLACK}Zone +STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}Zone weergeven binnen de gemeentegrenzen STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Reputatie van transportbedrijven: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Beschikbare acties: @@ -3355,8 +3383,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spoordelen: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seinen STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Wegdelen: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Weg -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramsporen +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Tramdelen: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Watertegels: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalen STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -3436,6 +3463,8 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Niet-gegroepeer STR_GROUP_DEFAULT_SHIPS :Niet-gegroepeerde schepen STR_GROUP_DEFAULT_AIRCRAFTS :Niet-gegroepeerde vliegtuigen +STR_GROUP_COUNT_WITH_SUBGROUP :{TINY_FONT}{COMMA} (+{COMMA}) + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groepen - Klik op een groep voor een lijst van alle voertuigen in deze groep. Klik en sleep om hiërarchie te beheren STR_GROUP_CREATE_TOOLTIP :{BLACK}Klik om een groep te creëren STR_GROUP_DELETE_TOOLTIP :{BLACK}Verwijder de geselecteerde groep @@ -3462,12 +3491,18 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nieuwe elektris STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nieuwe monorailvoertuigen STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nieuwe zweefspoorvoertuigen -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nieuwe spoorvoertuigen STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nieuwe wegvoertuigen +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :Nieuwe trams + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nieuwe spoorvoertuigen +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :Nieuwe wegvoertuigen STR_BUY_VEHICLE_SHIP_CAPTION :Nieuwe schepen STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nieuwe vliegtuigen +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} Gewicht: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} (ombouwkosten: {GOLD}{CURRENCY_LONG}{BLACK}) Gewicht: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Snelheid: {GOLD}{VELOCITY}{BLACK} Vermogen: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Snelheid: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Snelheid op oceaan: {GOLD}{VELOCITY} @@ -3478,8 +3513,10 @@ STR_PURCHASE_INFO_REFITTABLE :(ombouwbaar) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Ontworpen: {GOLD}{NUM}{BLACK} Levensduur: {GOLD}{COMMA} jaar STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. betrouwbaarheid: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Kosten: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} (ombouwkosten: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Gewicht: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} Snelheid: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Kosten: {GOLD}{CURRENCY_LONG}{BLACK} (ombouwkosten: {GOLD}{CURRENCY_LONG}{BLACK}) Snelheid: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capaciteit: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Aangedreven wagons: {GOLD}+{POWER}{BLACK} Gewicht: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Om te bouwen naar: {GOLD}{STRING} @@ -3500,11 +3537,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Wegvoert STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Schip kopen STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Vliegtuig kopen +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Voertuig kopen en ombouwen +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Voertuig kopen en ombouwen +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Schip kopen en ombouwen +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Vliegtuig kopen en ombouwen + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Geselecteerd spoorvoertuig bouwen. Shift+klik geeft de verwachte kosten zonder te kopen. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Koop het geselecteerde wegvoertuig. Shift+klik geeft de verwachte kosten zonder te kopen. STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Koop het geselecteerde schip. Shift+klik geeft de verwachte kosten zonder te kopen STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Koop het geselecteerde vliegtuig. Shift+klik geeft de verwachte kosten zonder te kopen. +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koop de geselecteerde trein en bouw hem om. Shift+klik geeft de verwachte kosten zonder te kopen. +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koop het geselecteerde wegvoertuig en bouw het om. Shift+klik geeft de geschatte kosten zonder te kopen. +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koop het geselecteerde schip en bouw het om. Shift+klik geeft de verwachte kosten zonder te kopen. +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Koop het geselecteerde vliegtuig en bouw het om. Shift+klik geeft de verwachte kosten zonder te kopen. + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Hernoemen STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Hernoemen STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Hernoemen @@ -3613,13 +3660,18 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Je staa # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Bericht van voertuigenfabrikant STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We hebben zojuist een nieuwe {STRING} ontworpen - ben je geïnteresseerd in een jaar lang exclusief gebruik van dit voertuig, zodat we kunnen zien of het goed werkt voordat we het wereldwijd beschikbaar maken? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :spoorlocomotief -STR_ENGINE_PREVIEW_ROAD_VEHICLE :wegvoertuig -STR_ENGINE_PREVIEW_AIRCRAFT :vliegtuig -STR_ENGINE_PREVIEW_SHIP :schip +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :elektrische locomotief STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monoraillocomotief STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :zweeflocomotief +STR_ENGINE_PREVIEW_ROAD_VEHICLE :wegvoertuig +STR_ENGINE_PREVIEW_TRAM_VEHICLE :tram + +STR_ENGINE_PREVIEW_AIRCRAFT :vliegtuig +STR_ENGINE_PREVIEW_SHIP :schip + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Kosten: {CURRENCY_LONG} Gewicht: {WEIGHT_SHORT}{}Snelheid: {VELOCITY} Kracht: {POWER}{}Lopende kosten: {CURRENCY_LONG}/jr{}Capaciteit: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Kosten: {CURRENCY_LONG} Gewicht: {WEIGHT_SHORT}{}Snelheid: {VELOCITY} Kracht: {POWER} Max. T.E.: {6:FORCE}{}Lopende kosten: {4:CURRENCY_LONG}/yr{}Capaciteit: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Kosten: {CURRENCY_LONG} Max.snelheid: {VELOCITY}{}Capaciteit: {CARGO_LONG}{}Gebruikskosten: {CURRENCY_LONG}/jaar @@ -3657,14 +3709,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Wissel t STR_REPLACE_ENGINES :Motoren STR_REPLACE_WAGONS :Wagons STR_REPLACE_ALL_RAILTYPE :Alle treinen +STR_REPLACE_ALL_ROADTYPE :Alle wegvoertuigen STR_REPLACE_HELP_RAILTYPE :{BLACK}Selecteer een spoortype waar je locomotieven voor wilt vervangen +STR_REPLACE_HELP_ROADTYPE :{BLACK}Kies het type weg waar je voertuigen voor wilt vervangen STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Dit geeft weer waarmee de links geselecteerde locomotief vervangen wordt STR_REPLACE_RAIL_VEHICLES :Spoorvoertuigen STR_REPLACE_ELRAIL_VEHICLES :Elektrische spoorvoertuigen STR_REPLACE_MONORAIL_VEHICLES :Monorailvoertuigen STR_REPLACE_MAGLEV_VEHICLES :Magneetzweefspoorvoertuigen +STR_REPLACE_ROAD_VEHICLES :Wegvoertuigen +STR_REPLACE_TRAM_VEHICLES :Trams + STR_REPLACE_REMOVE_WAGON :{BLACK}Wagons verwijderen: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}De te vervangen trein behoudt zijn lengte door wagons weg te halen (startend aan de voorkant), als het vervangen de trein langer zou maken @@ -4386,7 +4443,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Verwijde STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Geen bruikbaar spoor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Moet spoor eerst verwijderen STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Weg is eenrichtingsverkeer of geblokkeerd -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Gelijkvloerse kruisingen zijn niet toegestaan voor dit type spoor +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Gelijkvloerse kruisingen zijn niet toegestaan voor dit type spoor +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Gelijkvloerse kruisingen zijn niet toegestaan voor dit type weg STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan hier geen seinen plaatsen... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan hier geen spoor leggen... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan hier geen spoor verwijderen... @@ -4406,6 +4464,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Kan hier STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Kan de tramrails hier niet verwijderen... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}...er is geen weg STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}...er is geen tramlijn +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Kan wegtype hier niet converteren... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Kan tramtype hier niet converteren... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Geen geschikte weg +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}Geen geschikt tramspoor +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... weg niet geschikt +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... treinspoor niet geschikt # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Kan hier geen kanaal bouwen... @@ -4458,6 +4522,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Kan groe STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Kan deze groep niet verwijderen... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Kan deze groep niet hernoemen... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Kan huidige groep niet instellen... +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... lussen in de groepshiërarchie zijn niet toegestaan STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Kan niet alle voertuigen van deze groep verwijderen... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Kan niet alle voertuigen aan deze groep toevoegen... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Kan niet alle gedeelde voertuigen aan deze groep toevoegen... diff --git a/src/lang/english.txt b/src/lang/english.txt index f6b441e4cd..743706638f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -240,6 +240,8 @@ STR_BUTTON_FILTER_SELECT_NONE :Select None STR_BUTTON_SORT_BY :{BLACK}Sort by STR_BUTTON_LOCATION :{BLACK}Location STR_BUTTON_RENAME :{BLACK}Rename +STR_BUTTON_CATCHMENT :{BLACK}Coverage +STR_TOOLTIP_CATCHMENT :{BLACK}Toggle coverage area display STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Close window STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Window title - drag this to move window @@ -269,6 +271,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}By enabl STR_BUTTON_DEFAULT :{BLACK}Default STR_BUTTON_CANCEL :{BLACK}Cancel STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Warning: Server administrators may be able to read any text entered here. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . @@ -344,6 +347,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Zoom the STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Zoom the view out STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Build roads +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Build tramways STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Build ship docks STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Build airports STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Open the landscaping toolbar to raise/lower land, plant trees, etc. @@ -364,6 +368,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscap STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Town generation STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry generation STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Tramway construction STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate @@ -942,6 +947,9 @@ STR_GAME_OPTIONS_CURRENCY_GEL :Georgian Lari ( STR_GAME_OPTIONS_CURRENCY_IRR :Iranian Rial (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :New Russian Ruble (RUB) STR_GAME_OPTIONS_CURRENCY_MXN :Mexican Peso (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :New Taiwan Dollar (NTD) +STR_GAME_OPTIONS_CURRENCY_CNY :Chinese Renminbi (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dollar (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Road vehicles @@ -1193,6 +1201,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Allow landscapi STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Allow landscaping under buildings and tracks without removing them STR_CONFIG_SETTING_CATCHMENT :Allow more realistically sized catchment areas: {STRING2} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Have differently sized catchment areas for different types of stations and airports +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Company stations can serve industries with attached neutral stations: {STRING2} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :When enabled, industries with attached stations (such as Oil Rigs) may also be served by company owned stations built nearby. When disabled, these industries may only be served by their attached stations. Any nearby company stations won't be able to serve them, nor will the attached station serve anything else other than the industry STR_CONFIG_SETTING_EXTRADYNAMITE :Allow removal of more town-owned roads, bridges and tunnels: {STRING2} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Make it easier to remove town-owned infrastructure and buildings STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum length of trains: {STRING2} @@ -1209,8 +1219,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Steepness of a STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Slope steepness for road vehicles: {STRING2} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a road vehicle. Higher values make it more difficult to climb a hill -STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains and ships from making 90° turns: {STRING2} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degree when traversing the tile edge instead of the usual 45 degrees for other track combinations. This also applies to the turning radius of ships +STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains from making 90° turns: {STRING2} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degree when traversing the tile edge instead of the usual 45 degrees for other track combinations. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Allow to join stations not directly adjacent: {STRING2} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Allow adding parts to a station without directly touching the existing parts. Needs Ctrl+Click while placing the new parts STR_CONFIG_SETTING_INFLATION :Inflation: {STRING2} @@ -1266,8 +1276,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Plane speed fac STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Set the relative speed of planes compared to other vehicle types, to reduce the amount of income of transport by aircraft STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Number of plane crashes: {STRING2} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of an aircraft crash happening -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of a random aircraft crash happening.{}* Large airplanes always have a risk of crashing when landing on small airports +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduced STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Allow drive-through road stops on town owned roads: {STRING2} @@ -1325,8 +1335,8 @@ STR_CONFIG_SETTING_TERRAIN_TYPE :Terrain type: { STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(TerraGenesis only) Hilliness of the landscape STR_CONFIG_SETTING_INDUSTRY_DENSITY :Industry density: {STRING2} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Set how many industries should be generated and what level should be maintained during the game -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maximum distance from edge for Oil refineries: {STRING2} -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Oil refineries are only constructed near the map border, that is at the coast for island maps +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maximum distance from edge for Oil industries: {STRING2} +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Limit for how far from the map border oil refineries and oil rigs can be constructed. On island maps this ensures they are near the coast. On maps larger than 256 tiles, this value is scaled up. STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Snow line height: {STRING2} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Control at what height snow starts in sub-arctic landscape. Snow also affects industry generation and town growth requirements STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Roughness of terrain: {STRING2} @@ -1492,6 +1502,9 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Allow AIs in mu STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Allow AI computer players to participate in multiplayer games STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes before scripts are suspended: {STRING2} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximum number of computation steps that a script can take in one turn +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Max memory usage per script: {STRING2} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :How much memory a single script may consume before it's forcibly terminated. This may need to be increased for large maps. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Service intervals are in percents: {STRING2} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Choose whether servicing of vehicles is triggered by the time passed since last service or by reliability dropping by a certain percentage of the maximum reliability @@ -1554,6 +1567,8 @@ STR_CONFIG_SETTING_SMOOTH_ECONOMY :Enable smooth e STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :When enabled, industry production changes more often, and in smaller steps. This setting has usually no effect, if industry types are provided by a NewGRF STR_CONFIG_SETTING_ALLOW_SHARES :Allow buying shares from other companies: {STRING2} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :When enabled, allow buying and selling of company shares. Shares will only be available for companies reaching a certain age +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :Minimum company age to trade shares: {STRING2} +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Set the minimum age of a company for others to be able to buy and sell shares from them. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :When dragging, place signals every: {STRING2} @@ -1594,6 +1609,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Enabling this s STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbidden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Allowed STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Allowed, custom town layout +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Town cargo generation: {STRING2} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :How much cargo is produced by houses in towns, relative to the overall population of the town.{}Quadratic growth: A town twice the size generates four times as many passengers.{}Linear growth: A town twice the size generates twice the amount of passengers. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Quadratic (original) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Linear STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In game placement of trees: {STRING2} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills @@ -1721,7 +1740,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Cargo d STR_CONFIG_SETTING_AI :{ORANGE}Competitors STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recommended) @@ -1825,13 +1843,9 @@ STR_QUIT_NO :{BLACK}No # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2169,7 +2183,7 @@ STR_NETWORK_CHAT_ALL :[All] {RAW_STRI STR_NETWORK_CHAT_OSKTITLE :{BLACK}Enter text for network chat # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found or compiled without ENABLE_NETWORK +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found STR_NETWORK_ERROR_NOSERVER :{WHITE}Could not find any network games STR_NETWORK_ERROR_NOCONNECTION :{WHITE}The server didn't answer the request STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Could not connect due to NewGRF mismatch @@ -2451,7 +2465,6 @@ STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramway STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Build road section. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build road section using the Autoroad mode. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_FULLROAD :{BLACK}Build road section using the Autoroad mode with only full tile roads. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate @@ -2466,6 +2479,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Build ro STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tramway tunnel. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Convert/Upgrade the type of road. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Convert/Upgrade the type of tram. Shift toggles building/showing cost estimate + +STR_ROAD_NAME_ROAD :Road +STR_ROAD_NAME_TRAM :Tramway # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation @@ -2651,8 +2669,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Cargo accepted: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Rail type: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Road type: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tram type: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rail speed limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Road speed limit: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tram speed limit: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocks @@ -2762,6 +2783,7 @@ STR_FRAMERATE_SPEED_FACTOR :{BLACK}Current STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}How fast the game is currently running, compared to the expected speed at normal simulation rate. STR_FRAMERATE_CURRENT :{WHITE}Current STR_FRAMERATE_AVERAGE :{WHITE}Average +STR_FRAMERATE_MEMORYUSE :{WHITE}Memory STR_FRAMERATE_DATA_POINTS :{BLACK}Data based on {COMMA} measurements STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_WARN :{YELLOW}{DECIMAL} ms @@ -2769,6 +2791,9 @@ STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} frames/s STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} frames/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} frames/s +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! @@ -3135,6 +3160,8 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Rename Town # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} local authority +STR_LOCAL_AUTHORITY_ZONE :{BLACK}Zone +STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}Show zone within local authority boundaries STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transport company ratings: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Actions available: @@ -3392,8 +3419,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Tram pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -3473,6 +3499,8 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Ungrouped road STR_GROUP_DEFAULT_SHIPS :Ungrouped ships STR_GROUP_DEFAULT_AIRCRAFTS :Ungrouped aircraft +STR_GROUP_COUNT_WITH_SUBGROUP :{TINY_FONT}{COMMA} (+{COMMA}) + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groups - click on a group to list all vehicles of this group. Drag and drop groups to arrange hierarchy. STR_GROUP_CREATE_TOOLTIP :{BLACK}Click to create a group STR_GROUP_DELETE_TOOLTIP :{BLACK}Delete the selected group @@ -3499,12 +3527,18 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Ra STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :New Tram Vehicles + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :New Road Vehicles STR_BUY_VEHICLE_SHIP_CAPTION :New Ships STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Speed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Speed on ocean: {GOLD}{VELOCITY} @@ -3515,8 +3549,10 @@ STR_PURCHASE_INFO_REFITTABLE :(refittable) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designed: {GOLD}{NUM}{BLACK} Life: {GOLD}{COMMA} year{P "" s} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Reliability: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cost: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Weight: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Speed: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) Speed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Powered Wagons: {GOLD}+{POWER}{BLACK} Weight: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Refittable to: {GOLD}{STRING2} @@ -3537,11 +3573,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehi STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Ship +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Aircraft + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted train vehicle. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted road vehicle. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted ship. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted aircraft. Shift+Click shows estimated cost without purchase + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename @@ -3650,13 +3696,18 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railway locomotive -STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle -STR_ENGINE_PREVIEW_AIRCRAFT :aircraft -STR_ENGINE_PREVIEW_SHIP :ship +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :electrified railway locomotive STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive +STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle +STR_ENGINE_PREVIEW_TRAM_VEHICLE :tramway vehicle + +STR_ENGINE_PREVIEW_AIRCRAFT :aircraft +STR_ENGINE_PREVIEW_SHIP :ship + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr @@ -3694,14 +3745,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch b STR_REPLACE_ENGINES :Engines STR_REPLACE_WAGONS :Wagons STR_REPLACE_ALL_RAILTYPE :All rail vehicles +STR_REPLACE_ALL_ROADTYPE :All road vehicles STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the rail type you want to replace engines for +STR_REPLACE_HELP_ROADTYPE :{BLACK}Choose the road type you want to replace engines for STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any STR_REPLACE_RAIL_VEHICLES :Rail Vehicles STR_REPLACE_ELRAIL_VEHICLES :Electrified Rail Vehicles STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles +STR_REPLACE_ROAD_VEHICLES :Road Vehicles +STR_REPLACE_TRAM_VEHICLES :Tramway Vehicles + STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing wagons (starting at the front), if replacing the engine would make the train longer @@ -4423,7 +4479,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Level crossings not allowed for this road type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... @@ -4443,6 +4500,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't re STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove tramway from here... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... there is no road STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... there is no tramway +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Can't convert road type here... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Can't convert tram type here... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}No suitable road +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}No suitable tramway +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... incompatible road +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... incompatible tramway # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Can't build canals here... @@ -4495,6 +4558,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Can't cr STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Can't delete this group... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Can't rename group... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Can't set parent group... +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... loops in the group hierarchy are not allowed STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Can't remove all vehicles from this group... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Can't add the vehicle to this group... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Can't add shared vehicles to group... diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index 217d88a83e..4805ce2158 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -1664,7 +1664,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Cargo d STR_CONFIG_SETTING_AI :{ORANGE}Competitors STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recommended) @@ -1745,13 +1744,9 @@ STR_QUIT_NO :{BLACK}No # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2377,6 +2372,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tr STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select road vehicle depot orientation @@ -3228,8 +3224,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -3303,6 +3297,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Ungrouped road STR_GROUP_DEFAULT_SHIPS :Ungrouped ships STR_GROUP_DEFAULT_AIRCRAFTS :Ungrouped aircraft + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groups - click on a group to list all vehicles of this group. Drag and drop groups to arrange hierarchy. STR_GROUP_CREATE_TOOLTIP :{BLACK}Click to create a group STR_GROUP_DELETE_TOOLTIP :{BLACK}Delete the selected group @@ -3324,10 +3319,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Ra STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_SHIP_CAPTION :New Ships STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} @@ -3360,11 +3358,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehi STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename @@ -3461,13 +3461,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railway locomotive -STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle -STR_ENGINE_PREVIEW_AIRCRAFT :aircraft -STR_ENGINE_PREVIEW_SHIP :ship STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive +STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle + +STR_ENGINE_PREVIEW_AIRCRAFT :aircraft +STR_ENGINE_PREVIEW_SHIP :ship + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr @@ -3504,6 +3507,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Electrified Rai STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles + STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing wagons (starting at the front), if replacing the engine would make the train longer @@ -4221,7 +4225,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Level crossings not allowed for this rail type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 48b9d04cc2..556a29ebbc 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -237,6 +237,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Select f STR_BUTTON_SORT_BY :{BLACK}Sort by STR_BUTTON_LOCATION :{BLACK}Location STR_BUTTON_RENAME :{BLACK}Rename +STR_BUTTON_CATCHMENT :{BLACK}Coverage +STR_TOOLTIP_CATCHMENT :{BLACK}Toggle coverage area display STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Close window STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Window title - drag this to move window @@ -266,6 +268,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}By enabl STR_BUTTON_DEFAULT :{BLACK}Default STR_BUTTON_CANCEL :{BLACK}Cancel STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Warning: Server administrators may be able to read any text entered here. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . @@ -339,6 +342,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Zoom the STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Zoom the view out STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railroad track STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Build roads +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Build streetcar lines STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Build ship docks STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Build airports STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Open the landscaping toolbar to raise/lower land, plant trees, etc. @@ -359,6 +363,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscap STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Town generation STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry generation STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Streetcar line construction STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate @@ -934,6 +939,9 @@ STR_GAME_OPTIONS_CURRENCY_GEL :Georgian Lari ( STR_GAME_OPTIONS_CURRENCY_IRR :Iranian Rial (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :New Russian Ruble (RUB) STR_GAME_OPTIONS_CURRENCY_MXN :Mexican Peso (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :New Taiwan Dollar (NTD) +STR_GAME_OPTIONS_CURRENCY_CNY :Chinese Renminbi (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kong Dollar (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Road vehicles @@ -1185,6 +1193,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Allow terraform STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Allow terraforming under buildings and tracks without removing them STR_CONFIG_SETTING_CATCHMENT :Allow more realistically sized catchment areas: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Have differently sized catchment areas for different types of stations and airports +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Company stations can serve industries that have built-in neutral stations: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :When enabled, industries with attached stations (such as Oil Rigs) may also be served by company owned stations built nearby. When disabled, these industries may only be served by their attached stations. Any nearby company stations won't be able to serve them, nor will the attached station serve anything else other than the industry STR_CONFIG_SETTING_EXTRADYNAMITE :Allow removal of more town-owned roads, bridges and tunnels: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Make it easier to remove town-owned infrastructure and buildings STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum length of trains: {STRING} @@ -1201,8 +1211,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Steepness of a STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Slope steepness for road vehicles: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a road vehicle. Higher values make it more difficult to climb a hill -STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains and ships from making 90° turns: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degree when traversing the tile edge instead of the usual 45 degrees for other track combinations. This also applies to the turning radius of ships +STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains from making 90° turns: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degrees when traversing the tile edge instead of the usual 45 degrees for other track combinations. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Allow joining stations not directly adjacent: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Allow adding parts to a station without directly touching the existing parts. Needs Ctrl+Click while placing the new parts STR_CONFIG_SETTING_INFLATION :Inflation: {STRING} @@ -1258,8 +1268,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Plane speed fac STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Set the relative speed of planes compared to other vehicle types, to reduce the amount of income of transport by aircraft STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Number of plane crashes: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of an aircraft crash happening -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of a random aircraft crash happening.{}* Large airplanes always have a risk of crashing when landing on small airports +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None* STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduced STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Allow drive-through road stops on town owned roads: {STRING} @@ -1482,6 +1492,9 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Allow AIs in mu STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Allow AI computer players to participate in multiplayer games STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes before scripts are suspended: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximum number of computation steps that a script can take in one turn +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Max memory usage per script: {STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :How much memory a single script may consume before it's forcibly terminated. This may need to be increased for large maps. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Maintenance intervals are in percents: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Choose whether maintenance of vehicles is triggered by the time passed since last maintenance or by reliability dropping by a certain percentage of the maximum reliability @@ -1584,6 +1597,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Enabling this s STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbidden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Allowed STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Allowed, custom town layout +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Town cargo generation: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :How much cargo is produced by houses in towns, relative to the overall population of the town.{}Quadratic growth: A town twice the size generates four times as many passengers.{}Linear growth: A town twice the size generates twice the amount of passengers. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Quadratic (original) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Linear STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In-game placement of trees: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills @@ -1711,7 +1728,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Cargo d STR_CONFIG_SETTING_AI :{ORANGE}Competitors STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recommended) @@ -1795,13 +1811,9 @@ STR_QUIT_NO :{BLACK}No # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2139,7 +2151,7 @@ STR_NETWORK_CHAT_ALL :[All] {STRING}: STR_NETWORK_CHAT_OSKTITLE :{BLACK}Enter text for network chat # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found or compiled without ENABLE_NETWORK +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found STR_NETWORK_ERROR_NOSERVER :{WHITE}Could not find any network games STR_NETWORK_ERROR_NOCONNECTION :{WHITE}The server didn't answer the request STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Could not connect due to NewGRF mismatch @@ -2431,6 +2443,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Build ro STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build streetcar tunnel. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for streetcar track construction +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Convert/Upgrade the type of road. Shift toggles building/showing cost estimate +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Convert/Upgrade the type of streetcar. Shift toggles building/showing cost estimate + +STR_ROAD_NAME_ROAD :Road +STR_ROAD_NAME_TRAM :Streetcar line # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation @@ -2615,8 +2632,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Cargo accepted: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Rail type: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Road type: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Streetcar type: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rail speed limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Road speed limit: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tram speed limit: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocks @@ -2726,6 +2746,7 @@ STR_FRAMERATE_SPEED_FACTOR :{BLACK}Current STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}How fast the game is currently running, compared to the expected speed at normal simulation rate. STR_FRAMERATE_CURRENT :{WHITE}Current STR_FRAMERATE_AVERAGE :{WHITE}Average +STR_FRAMERATE_MEMORYUSE :{WHITE}Memory STR_FRAMERATE_DATA_POINTS :{BLACK}Data based on {COMMA} measurements STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_WARN :{YELLOW}{DECIMAL} ms @@ -2733,6 +2754,9 @@ STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} frames/s STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} frames/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} frames/s +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! @@ -3356,8 +3380,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Streetcar +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Streetcar pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: @@ -3437,6 +3460,8 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Ungrouped road STR_GROUP_DEFAULT_SHIPS :Ungrouped ships STR_GROUP_DEFAULT_AIRCRAFTS :Ungrouped aircraft +STR_GROUP_COUNT_WITH_SUBGROUP :{TINY_FONT}{COMMA} (+{COMMA}) + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groups - click on a group to list all vehicles of this group. Drag and drop groups to arrange hierarchy. STR_GROUP_CREATE_TOOLTIP :{BLACK}Click to create a group STR_GROUP_DELETE_TOOLTIP :{BLACK}Delete the selected group @@ -3463,12 +3488,18 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Ra STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :New Streetcars + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :New Road Vehicles STR_BUY_VEHICLE_SHIP_CAPTION :New Ships STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Speed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Speed on ocean: {GOLD}{VELOCITY} @@ -3479,8 +3510,10 @@ STR_PURCHASE_INFO_REFITTABLE :(refittable) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designed: {GOLD}{NUM}{BLACK} Life: {GOLD}{COMMA} year{P "" s} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Reliability: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cost: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Weight: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Speed: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} (Refit Cost: {GOLD}{CURRENCY_LONG}{BLACK}) Speed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Powered Wagons: {GOLD}+{POWER}{BLACK} Weight: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Refittable to: {GOLD}{STRING} @@ -3501,11 +3534,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehi STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Vehicle +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Ship +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Buy and Refit Aircraft + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted train vehicle. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted road vehicle. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted ship. Shift+Click shows estimated cost without purchase +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Buy and refit the highlighted aircraft. Shift+Click shows estimated cost without purchase + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename @@ -3614,13 +3657,18 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available ? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railroad locomotive -STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle -STR_ENGINE_PREVIEW_AIRCRAFT :aircraft -STR_ENGINE_PREVIEW_SHIP :ship +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :electrified railway locomotive STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive +STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle +STR_ENGINE_PREVIEW_TRAM_VEHICLE :streetcar + +STR_ENGINE_PREVIEW_AIRCRAFT :aircraft +STR_ENGINE_PREVIEW_SHIP :ship + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr @@ -3658,14 +3706,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch b STR_REPLACE_ENGINES :Engines STR_REPLACE_WAGONS :Cars STR_REPLACE_ALL_RAILTYPE :All rail vehicles +STR_REPLACE_ALL_ROADTYPE :All road vehicles STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the rail type you want to replace engines for +STR_REPLACE_HELP_ROADTYPE :{BLACK}Choose the road type you want to replace engines for STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any STR_REPLACE_RAIL_VEHICLES :Rail Vehicles STR_REPLACE_ELRAIL_VEHICLES :Electrified Rail Vehicles STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles +STR_REPLACE_ROAD_VEHICLES :Road Vehicles +STR_REPLACE_TRAM_VEHICLES :Streetcars + STR_REPLACE_REMOVE_WAGON :{BLACK}Car removal: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing cars (starting at the front), if replacing the engine would make the train longer @@ -4387,7 +4440,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must rem STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railroad track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railroad track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Grade crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Grade crossings not allowed for this rail type +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Level crossings not allowed for this road type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railroad track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railroad track from here... @@ -4407,6 +4461,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't re STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove streetcar track from here... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... there is no road STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... there is no streetcar track +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Can't convert road type here... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Can't convert streetcar type here... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}No suitable road +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}No suitable streetcar line +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... incompatible road +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... incompatible streetcar line # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Can't build canals here... @@ -4459,6 +4519,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Can't cr STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Can't delete this group... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Can't rename group... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Can't set parent group... +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... loops in the group hierarchy are not allowed STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Can't remove all vehicles from this group... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Can't add the vehicle to this group... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Can't add shared vehicles to group... diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index c82ca05527..b7f657523c 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -1368,7 +1368,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Industr STR_CONFIG_SETTING_AI :{ORANGE}Konkurantoj STR_CONFIG_SETTING_AI_NPC :{ORANGE}Komputil-ludantoj -STR_CONFIG_SETTING_PATHFINDER_OPF :Originale STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Rekomendite) @@ -1427,13 +1426,9 @@ STR_QUIT_NO :{BLACK}Ne # Supported OSes STR_OSNAME_WINDOWS :Vindozo -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unikso STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2006,6 +2001,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Konstruu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Konstrui tramtunelon. Baskulu inter konstrui/(kosto)taksi per maljuskliga klavo STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Ĉu konstrui ĉu forigi por vojkonstruado + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Direkto de la stratveturila garaĝo STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Elekti direkton de la stratveturila garaĝo @@ -2777,6 +2773,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Sengrupaj strat STR_GROUP_DEFAULT_SHIPS :Sengrupaj ŝipoj STR_GROUP_DEFAULT_AIRCRAFTS :Sengrupaj aviadiloj + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupoj - klaku grupon por listigi ĉiujn veturilojn de tiu ĉi grupo. Trenu/faligu grupojn por ordigi ĝin STR_GROUP_CREATE_TOOLTIP :{BLACK}Klaku por krei grupon STR_GROUP_DELETE_TOOLTIP :{BLACK}Viŝu la selektitan grupon @@ -2795,10 +2792,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Novaj Elektraj STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Novaj Unurelaj Veturiloj STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Novaj Maglevaj Veturiloj -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Novaj stratveturiloj STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Novaj stratveturiloj + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Novaj stratveturiloj STR_BUY_VEHICLE_SHIP_CAPTION :Novaj Ŝipoj STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Novaj Aviadiloj +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Kosto: {GOLD}{CURRENCY_LONG}{BLACK} Pezo: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Rapido: {GOLD}{VELOCITY}{BLACK} Forto: {GOLD}{POWER} @@ -2830,11 +2830,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Aĉeti V STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Aĉeti Ŝipon STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Aĉeti Aviadilon + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Aĉeti la emfazitan trajnveturilon. Montri taksitaj kostoj sen aĉeti per maljuskliga klavo + Klaki STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Aĉeti la emfazitan stratveturilon. Montri taksitaj kostoj sen aĉeti per maljuskliga klavo + Klaki STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Aĉeti la emfazitan ŝipon. Montri taksitaj kostoj sen aĉeti per maljuskliga klavo + Klaki STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Aĉeti la emfazitan aviadilon. Montri taksitaj kostoj sen aĉeti per maljuskliga klavo + Klaki + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Alinomi STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Alinomi STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Alinomi @@ -2938,13 +2940,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Vi vend # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Mesaĝo de veturil-produktanto STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Nova {STRING} estas inventita - ĉu vi ŝatus jaron ekskluzive uzi la veturilon, por ke ni povu vidi ĝian funkciadon antaŭ ol ĝi estos plene havebla? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :fervoja lokomotivo -STR_ENGINE_PREVIEW_ROAD_VEHICLE :stratveturilo -STR_ENGINE_PREVIEW_AIRCRAFT :aviadilo -STR_ENGINE_PREVIEW_SHIP :ŝipo STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :unurellokomotivo STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :magleva lokomotivo +STR_ENGINE_PREVIEW_ROAD_VEHICLE :stratveturilo + +STR_ENGINE_PREVIEW_AIRCRAFT :aviadilo +STR_ENGINE_PREVIEW_SHIP :ŝipo + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Kosto: {CURRENCY_LONG} Pezo: {WEIGHT_SHORT}{}Rapido: {VELOCITY} Forto: {POWER}{}Irkosto: po {CURRENCY_LONG} jare{}Kapablo: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Kosto: {CURRENCY_LONG} Pezo: {WEIGHT_SHORT}{}Rapido: {VELOCITY} Povo: {POWER} Maks. T.E.: {6:FORCE}{}Irkosto: {4:CURRENCY_LONG}/jaro{}Kapacito: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Kosto: {CURRENCY_LONG} Maks. Rapido: {VELOCITY}{}Kapacito: {CARGO_LONG}{}Irkosto: {CURRENCY_LONG}/jaro @@ -2978,6 +2983,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Elektraj Relaj STR_REPLACE_MONORAIL_VEHICLES :Unurelaj Veturiloj STR_REPLACE_MAGLEV_VEHICLES :Maglevaj Veturiloj + STR_REPLACE_REMOVE_WAGON :{BLACK}Vagonforigo: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Ĉe aŭtomata anstataŭigo tenu saman longecon de la trajno per forigo de vagonoj (defronte), se per nova maŝino la trajno plilongiĝas @@ -3647,7 +3653,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Unue vi STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nekonvena fervojtrako STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Antaŭe devas la trako esti detruita STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Strato estas unudirekta aŭ blokita -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Traknivelaj pasejoj ne permesa por ĉi tio fervojtipo +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Traknivelaj pasejoj ne permesa por ĉi tio fervojtipo STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ne povas konstrui signalojn ĉi tie... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ne povas konstrui trakon ĉi tie... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Ne povas forigi trakon de ĉi tie... diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index a124d7d988..d08868d79f 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -980,7 +980,9 @@ STR_GAME_OPTIONS_CURRENCY_ZAR :Lõuna-Aafrika STR_GAME_OPTIONS_CURRENCY_CUSTOM :Omatehtud... STR_GAME_OPTIONS_CURRENCY_GEL :Gruusia lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iraani rial (IRR) +STR_GAME_OPTIONS_CURRENCY_RUB :Uus Vene rubla (RUB) STR_GAME_OPTIONS_CURRENCY_MXN :Mehhiko Peeso (MXN) +STR_GAME_OPTIONS_CURRENCY_HKD :Hong Kongi dollar (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Sõidukid @@ -1043,7 +1045,9 @@ STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Tavaline STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Topeltsuurus STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Ruudu suurus +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Vali kasutatav liideseelementide suurus +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :Ruudu suurus STR_GAME_OPTIONS_BASE_GRF :{BLACK}Alusgraafika kogu STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Valib kasutatava alusgraafika kogu @@ -1745,7 +1749,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Kaubaja STR_CONFIG_SETTING_AI :{ORANGE}Konkurendid STR_CONFIG_SETTING_AI_NPC :{ORANGE}Arvuti -STR_CONFIG_SETTING_PATHFINDER_OPF :Algne STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(soovitatud) @@ -1828,13 +1831,9 @@ STR_QUIT_NO :{BLACK}Ei # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2464,6 +2463,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Ehita tr STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Lülitu maanteede ehitamise ja lammutamise vahel STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Lülitu trammitee ehitamise ja lammutamise vahel + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Depoo suund STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Vali depoole suund @@ -2646,6 +2646,7 @@ STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Lennujaa STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Vastuvõetavad veosed: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Trammi tüüp: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Raudtee kiiruspiirang: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Lubatud piirkiirus: {LTBLUE}{VELOCITY} @@ -2748,6 +2749,7 @@ STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD # Framerate display window STR_FRAMERATE_CAPTION :{WHITE}Kaadrisagedus +STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP :{BLACK}Simuleeritud mänguhetkede arv sekundis. STR_FRAMERATE_RATE_BLITTER_TOOLTIP :{BLACK}Renderdatud videokaadrite arv sekundis. STR_FRAMERATE_AVERAGE :{WHITE}Keskmine STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms @@ -2757,6 +2759,7 @@ STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMA STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} kaadrit/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} kaadrit/s ############ Leave those lines in this order!! +STR_FRAMERATE_GAMELOOP :{BLACK}Mängutsükli lõppkokkuvõte: STR_FRAMERATE_GL_AIRCRAFT :{BLACK} Õhusõiduki sammud: STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Ahelgraafiku viide: STR_FRAMERATE_DRAWING :{BLACK}Graafika renderdamine: @@ -3338,8 +3341,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE} {COMPAN STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Raudtee tükid: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaalid STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Tee tükid: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Tee -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Trammitee STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Veekogu ruudud: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanalid STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Jaamad: @@ -3413,6 +3414,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Rühmitamata s STR_GROUP_DEFAULT_SHIPS :Rühmitamata laevad STR_GROUP_DEFAULT_AIRCRAFTS :Rühmitamata õhusõidukid + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Rühm - Klõpsa rühmal, et kõiki seal olevaid sõidukeid järjestada STR_GROUP_CREATE_TOOLTIP :{BLACK}Klõpsa rühma loomiseks STR_GROUP_DELETE_TOOLTIP :{BLACK}Eemalda valitud rühm @@ -3428,6 +3430,7 @@ STR_GROUP_REMOVE_ALL_VEHICLES :Eemalda kõik s STR_GROUP_RENAME_CAPTION :{BLACK}Rühma nime vahetamine STR_GROUP_PROFIT_THIS_YEAR :Kasum sellel aastal: +STR_GROUP_OCCUPANCY_VALUE :{NUM}% # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Uued rööbassõidukid @@ -3435,10 +3438,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Uus elektriraud STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Uus monorelsssõiduk STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Uus magnethõljuksõiduk -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Rööbassõidukid STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Uued mootorsõidukid + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Rööbassõidukid STR_BUY_VEHICLE_SHIP_CAPTION :Uued laevad STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Uus lennuk +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Hind: {GOLD}{CURRENCY_LONG}{BLACK} Tühimass: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Tippkiirus: {GOLD}{VELOCITY}{BLACK} Võimsus: {GOLD}{POWER} @@ -3453,6 +3459,7 @@ STR_PURCHASE_INFO_RELIABILITY :{BLACK}Parim te STR_PURCHASE_INFO_COST :{BLACK}Hind: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Mass: {GOLD}{WEIGHT_SHORT} {WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Hind: {GOLD}{CURRENCY_LONG}{BLACK} Tippkiirus: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Hind: {GOLD}{CURRENCY_LONG}{BLACK} (Ümberseadistamise maksumus: {GOLD}{CURRENCY_LONG}{BLACK}) Kiirus: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Kandevõime: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Kiirendavad vagunid: {GOLD}+{POWER}{BLACK} Mass: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Ümberseadistatav: {GOLD}{STRING} @@ -3471,11 +3478,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Ehita ve STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Ehita laev STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Ehita lennuk + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valitud raudteesõiduk. Shift+klõpsuga kuvatakse eeldatav ostuhind STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valitud mootorsõiduk. Shift+klõpsuga kuvatakse eeldatav ostuhind STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valitud laev. Shift+klõpsuga kuvatakse eeldatav ostuhind STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valitud õhusõiduk. Shift+klõpsuga kuvatakse eeldatav ostuhind + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Nimevahetus STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Nimevahetus STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Nimevahetus @@ -3584,13 +3593,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Sa oled # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Teade veovahendite tootjalt STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Me töötasime välja uue {STRING}. Kas te oleksite huvitatud selle ainuõiguslikust katsetamisest järgneva aasta jooksul, et me saaksime jälgida kuidas see toimib? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :raudteevedur -STR_ENGINE_PREVIEW_ROAD_VEHICLE :mootorsõiduk -STR_ENGINE_PREVIEW_AIRCRAFT :lennuk -STR_ENGINE_PREVIEW_SHIP :laev STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorelssvedur STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :magnethõljukvedur +STR_ENGINE_PREVIEW_ROAD_VEHICLE :mootorsõiduk + +STR_ENGINE_PREVIEW_AIRCRAFT :lennuk +STR_ENGINE_PREVIEW_SHIP :laev + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Hind: {CURRENCY_LONG} Tühimass: {WEIGHT_SHORT}{}Tippkiirus: {VELOCITY} Võimsus: {POWER}{}Käituskulud: {CURRENCY_LONG}/aastas{}Kandevõime: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Hind: {CURRENCY_LONG} Tühimass: {WEIGHT_SHORT}{}Kiirus: {VELOCITY} Võimsus: {POWER} Veojõud: {6:FORCE}{}Käituskulud: {4:CURRENCY_LONG}/aasta{}Mahutavus: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Hind: {CURRENCY_LONG} Tippkiirus: {VELOCITY}{}Kandevõime: {CARGO_LONG}{}Käituskulud: {CURRENCY_LONG}/a @@ -3634,6 +3646,8 @@ STR_REPLACE_ELRAIL_VEHICLES :Elektrirongid STR_REPLACE_MONORAIL_VEHICLES :Monorelssveerem STR_REPLACE_MAGLEV_VEHICLES :Magnethõljukveerem +STR_REPLACE_ROAD_VEHICLES :Maanteesõidukid + STR_REPLACE_REMOVE_WAGON :{BLACK}Vagunite eemaldus: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Sunni automaatset asendust hoidma rongi pikkust selleks (eest alustades) veeremit eemaldades, juhul kui uus vagun muudaks rongi pikemaks. @@ -4353,7 +4367,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Signaali STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Sobiv rongitee puudub STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Rööbastee tuleb eelnevalt lammutada STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Läbipääsmatu või ühesuunaline maantee -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ülesõidukohad on selle raudteetüübi puhul keelatud +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Ülesõidukohad on selle raudteetüübi puhul keelatud STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Siia ei saa signaale rajada... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Siia ei saa raudteed ehitada... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Siit ei saa raudteed lammutada... @@ -4373,6 +4387,7 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Siinset STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Siinset trammiteed ei saa lammutada... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... siin pole autoteed STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... siin pole trammiteed +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... sobimatu tee # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Siia ei saa kanaleid ehitada... @@ -4535,6 +4550,7 @@ STR_BASESOUNDS_DOS_DESCRIPTION :Algse Transport STR_BASESOUNDS_WIN_DESCRIPTION :Algse Transport Tycoon Deluxe Windowsi versiooni helid. STR_BASESOUNDS_NONE_DESCRIPTION :Helikogu ilma helideta. STR_BASEMUSIC_WIN_DESCRIPTION :Algse Transport Tycoon Deluxe Windowsi versiooni muusika. +STR_BASEMUSIC_DOS_DESCRIPTION :Algse Transport Tycoon Deluxe DOSi versiooni muusika. STR_BASEMUSIC_NONE_DESCRIPTION :Muusikakogu ilma muusikata. ##id 0x2000 diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index b738ba9bbe..890f085fca 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -1523,7 +1523,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Ídnað STR_CONFIG_SETTING_AI :{ORANGE}Kappingarneytar STR_CONFIG_SETTING_AI_NPC :{ORANGE}Teldu spælarir -STR_CONFIG_SETTING_PATHFINDER_OPF :Upprunaligur STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Viðmældur) @@ -1591,13 +1590,9 @@ STR_QUIT_NO :{BLACK}Nei # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2168,6 +2163,7 @@ STR_BRIDGE_TUBULAR_SILICON :Rør, silikon STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Vegagerð STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Sporvogna bygging + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Akfars goymslu ætt STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Vel hvønn veg akfars goymslan skal venda @@ -2894,8 +2890,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Innanker STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Jarnbreyta pettir: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Tekin STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vega pettir: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Vegur -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Sporvognur STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vatn puntar: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Siglingarennir STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Støðir: @@ -2968,6 +2962,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Óbólkaði akf STR_GROUP_DEFAULT_SHIPS :Óbólkaði skip STR_GROUP_DEFAULT_AIRCRAFTS :Óbólkaði flogfør + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Bólkar - trýst á ein bólk fyri at síggja øll flutningstól í hesum bólki STR_GROUP_CREATE_TOOLTIP :{BLACK}Trýst fyri at gera ein bólk STR_GROUP_DELETE_TOOLTIP :{BLACK}Strika valda bólkin @@ -2987,10 +2982,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nýggj ravmagns STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nýggj einsporaði jarnbreyta flutningstól STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nýggj maglev flutningstól -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nýggj jarnbreyta flutningstól STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nýggj akfør + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nýggj jarnbreyta flutningstól STR_BUY_VEHICLE_SHIP_CAPTION :Nýggj skip STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nýggj flogfør +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Kostnaður: {GOLD}{CURRENCY_LONG}{BLACK} Vekt: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Ferð: {GOLD}{VELOCITY}{BLACK} Megi: {GOLD}{POWER} @@ -3023,11 +3021,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Keyp akf STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Keyp skip STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Keyp flogfar + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Keyp undirstrikaða tok flutningstóli. Shift+trýst vísur kostnaðar meting uttan at keypa STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Keyp undirstrikaða akfari. Shift+trýst vísur kostnaðar meting uttan at keypa STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Keyp undirstrikaða skipi. Shift+trýst vísur kostnaðar meting uttan at keypa STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Keyp undirstrikaða flogfari. Shift+trýst vísur kostnaðar meting uttan at keypa + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Navngev STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Navngev STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Navngev @@ -3124,13 +3124,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Tú er # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Boð frá framleiðarinum av flutningstólinum STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Vit hava júst sniðgivi eitt nýtt {STRING} - hevði tú havt áhuga í einkarrættindum at nýtt hetta flutningstóli í eitt ár, so vit kunnu síggja hvussu ta virkar áðrenn vit gera ta tøkt á marknaðinum? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :jarnbreyta lokomotiv -STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=n}akfar -STR_ENGINE_PREVIEW_AIRCRAFT :{G=n}flogfar -STR_ENGINE_PREVIEW_SHIP :skip STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :einsporað lokomotiv STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev lokomotiv +STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=n}akfar + +STR_ENGINE_PREVIEW_AIRCRAFT :{G=n}flogfar +STR_ENGINE_PREVIEW_SHIP :skip + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Kostnaður: {CURRENCY_LONG} Vekt: {WEIGHT_SHORT}{}Ferð: {VELOCITY} Megi: {POWER}{}Rakstrar kostnaður: {CURRENCY_LONG}/ár{}Pláss: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Kostnaður: {CURRENCY_LONG} Vekt: {WEIGHT_SHORT}{}Ferð: {VELOCITY} Megi: {POWER} Maks. D.Ó.: {6:FORCE}{}Rakstrar kostnaður: {4:CURRENCY_LONG}/ár{}Pláss: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Kostnaður: {CURRENCY_LONG} Maks. Ferð: {VELOCITY}{}Pláss: {CARGO_LONG}{}Rakstrar kostnaður: {CURRENCY_LONG}/ár @@ -3167,6 +3170,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Ravmagns jarnbr STR_REPLACE_MONORAIL_VEHICLES :Einsporaði jarnbreyta flutningstól STR_REPLACE_MAGLEV_VEHICLES :Maglev flutningstól + STR_REPLACE_REMOVE_WAGON :{BLACK}Vogn burturrudding: {ORANGE}{STRING} # Vehicle view @@ -3792,7 +3796,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Neyðugt STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ikki hóskandi jarnbreyt STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Neyðugt at beina burtur jarnbreyt fyrst STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Vegur er einvegis ella blokeraður -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Javnir krossvegir ikki loyvdir fyri hetta slagi av tok bana +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Javnir krossvegir ikki loyvdir fyri hetta slagi av tok bana STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kann ikki byggja jarnbreytatekin her... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kann ikki byggja jarnbreyt her... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kann ikki beina burtur jarnbreyt hagani... diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 6e2cd8a19a..c53ad92781 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -237,6 +237,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Valitse STR_BUTTON_SORT_BY :{BLACK}Lajittele STR_BUTTON_LOCATION :{BLACK}Sijainti STR_BUTTON_RENAME :{BLACK}Nimeä uudelleen +STR_BUTTON_CATCHMENT :{BLACK}Vaikutusalue +STR_TOOLTIP_CATCHMENT :{BLACK}Valitse, näytetäänkö vaikutusalue STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Sulje ikkuna STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Ikkunan otsake – siirrä ikkunaa vetämällä tästä @@ -265,6 +267,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Kun otat STR_BUTTON_DEFAULT :{BLACK}Oletus STR_BUTTON_CANCEL :{BLACK}Peruuta STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Varoitus: Palvelimen ylläpitäjät saattavat nähdä kaiken tähän kirjoittamasi. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :§1234567890+´ qwertyuiopå¨asdfghjklöä' zxcvbnm,.- . @@ -338,6 +341,7 @@ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Lähenn STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Loitonna näkymää STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Rakenna rautateitä STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Rakenna teitä +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Rakenna raitioteitä STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Rakenna satamia STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Rakenna lentokenttiä STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Avaa maastonmuokkaustyökalupalkki maan kohottamiseen/madaltamiseen, puiden istuttamiseen, jne. @@ -358,6 +362,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Maaston STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Kuntien luonti STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Teollisuuden luonti STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Tienrakennus +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Raitiotien rakentaminen STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Istuta puita. Shift vaihtaa istutustilan ja kustannusarvion välillä STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Sijoita kyltti STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Sijoita objekti. Shift vaihtaa rakennustilan ja kustannusarvion välillä @@ -933,6 +938,9 @@ STR_GAME_OPTIONS_CURRENCY_GEL :Georgian lari ( STR_GAME_OPTIONS_CURRENCY_IRR :Iranin rial (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Uusi Venäjän rupla (RUB) STR_GAME_OPTIONS_CURRENCY_MXN :Meksikon peso (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :Uusi Taiwanin dollari (TWD) +STR_GAME_OPTIONS_CURRENCY_CNY :Kiinan renminbi (CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :Hongkongin dollari (HKD) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Kulkuneuvot @@ -1184,6 +1192,8 @@ STR_CONFIG_SETTING_AUTOSLOPE :Salli maaston m STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Sallii maaston muokkaamisen rakennusten ja ratojen alta tuhoamatta niitä STR_CONFIG_SETTING_CATCHMENT :Realistisemman kokoiset vaikutusalueet: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Erityyppisillä asemilla ja lentokentillä on eri kokoiset vaikutusalueet +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES :Yhtiöiden asemat voivat palvella laitoksia, joilla on omat asemat: {STRING} +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :Mikäli käytössä, asemilla valmiiksi varustettuja teollisuuslaitoksia (kuten öljylauttoja) voivat palvella myös yhtiöiden lähistölle rakentamat asemat. Mikäli pois käytöstä, tällaisia laitoksia voivat palvella vain niiden omat asemat. Lähistöllä olevat yhtiöiden asemat eivät tällöin voi palvella näitä laitoksia, eivätkä laitosten asemat palvele muita kuin näitä laitoksia STR_CONFIG_SETTING_EXTRADYNAMITE :Kunnan omistamien teiden, siltojen ja tunneleiden raivaaminen sallittu: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Tekee kuntien omistaman infrastruktuurin ja rakennusten tuhoamisesta helpompaa STR_CONFIG_SETTING_TRAIN_LENGTH :Junien maksimipituus: {STRING} @@ -1200,8 +1210,8 @@ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Mäkien jyrkkyy STR_CONFIG_SETTING_PERCENTAGE :{COMMA}{NBSP}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Mäkien jyrkkyys ajoneuvoille: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Mäkien jyrkkyys ajoneuvoille. Korkeammat arvot tekevät mäkien nousemisesta vaikeampaa -STR_CONFIG_SETTING_FORBID_90_DEG :90 asteen käännökset kielletty junilta ja laivoilta: {STRING} -STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 asteen käännöksiä esiintyy kun vaakasuuntaista rataa seuraa pystysuuntainen rata viereisellä ruudulla, tämä vaatii junan kääntymään 90 astetta ruutujen reunalla normaalin 45 asteen sijasta. Tämä asetus vaikuttaa myös laivojen kääntymissäteeseen +STR_CONFIG_SETTING_FORBID_90_DEG :90 asteen käännökset kielletty junilta: {STRING} +STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 asteen käännöksiä esiintyy kun vaakasuuntaista rataa seuraa pystysuuntainen rata viereisellä ruudulla, tämä vaatii junan kääntymään 90 astetta ruutujen reunalla normaalin 45 asteen sijasta. STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Salli ei-vierekkäisten asemien yhdistäminen: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Mahdollistaa aseman osien rakentamisen vaikka ne eivät olisi kosketuksissa olemassaoleviin aseman osiin. Vaatii Ctrl-näppäimen painamisen rakennettaessa STR_CONFIG_SETTING_INFLATION :Inflaatio: {STRING} @@ -1257,8 +1267,8 @@ STR_CONFIG_SETTING_PLANE_SPEED :Lentokoneiden n STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Määritä lentokoneiden suhteellinen nopeus verrattuna toisiin kulkuneuvotyyppeihin STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Lento-onnettomuuksien määrä: {STRING} -STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Määrittää lento-onnettomuuksien todennäköisyyden -STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ei yhtään +STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Määrittää lento-onnettomuuksien todennäköisyyden.{}¹ Isot lentokoneet voivat kuitenkin aina tuhoutua pienille lentokentille laskeutuessaan. +STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ei yhtään¹ STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Vähennetty STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Tavallinen STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Läpiajettavat pysäkit kuntien omistamille teille: {STRING} @@ -1316,8 +1326,8 @@ STR_CONFIG_SETTING_TERRAIN_TYPE :Maaston tyyppi: STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Vain TerraGenesis) Maaston mäkisyys STR_CONFIG_SETTING_INDUSTRY_DENSITY :Teollisuuden määrä: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Määritä, kuinka paljon teollisuutta tulisi luoda ja millä tasolla teollisuuden tulisi pysytellä pelin aikana -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Suurin sallittu etäisyys kartan reunoilta öljynjalostamoille: {STRING} -STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Öljynjalostamoja rakennetaan ainoastaan kartan reunoille eli rannikoille saarikartoilla +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Suurin sallittu etäisyys kartan reunoilta öljyteollisuudelle: {STRING} +STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Öljynjalostamojen ja öljylauttojen suurin etäisyys kartan reunasta. Saarikartoilla tämä takaa sen, että ne ovat lähellä rannikkoa. Yli 256 ruudun kartoilla tätä arvoa suurennetaan suhteessa kartan kokoon. STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Lumirajan korkeus: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Määritä, millä korkeudella lumiraja on pohjoisessa maastotyypissä. Lumi vaikuttaa teollisuuslaitosten luontiin sekä kuntien kasvuedellytyksiin STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Maaston epätasaisuus: {STRING} @@ -1481,6 +1491,9 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Salli tekoälyt STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Sallii tietokonepelaajien osallistumisen moninpeleihin STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodet ennen skriptin pysäyttämistä: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Suurin sallittu määrä laskutoimituksia, jonka skripti voi suorittaa yhden vuoron aikana +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Skriptikohtainen muistinkäyttö enintään: {STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :Kuinka paljon muistia yksittäinen skripti saa käyttää, ennen kuin se pakotetaan lopettamaan. Jos kartta on iso, tätä arvoa voi joutua suurentamaan. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Huoltovälit ovat prosentteina: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Määritä, aiheuttaako edellisestä huollosta kulunut aika vai luotettavuuden laskeminen kulkuneuvon huoltamisen @@ -1543,6 +1556,8 @@ STR_CONFIG_SETTING_SMOOTH_ECONOMY :Tasainen talous STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Mikäli käytössä, teollisuuden tuotanto muuttuu useammin ja vähemmän kerrallaan. Tällä asetuksella ei ole yleensä vaikutusta mikäli teollisuustyypit ovat NewGRF:n tarjoamia STR_CONFIG_SETTING_ALLOW_SHARES :Salli toisten yhtiöiden osakkeiden ostaminen: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Mikäli käytössä, toisten yhtiöiden osakkeiden ostaminen ja myyminen on mahdollista. Osakkeet ovat saatavilla vain yhtiöille, jotka ovat saavuttaneet tietyn iän +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :Yhtiön vähimmäisikä osakekaupoille: {STRING} +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :Aseta yhtiölle vähimmäisikä, jonka jälkeen muut voivat ostaa ja myydä yhtiön osakkeita. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Syöttöjärjestelmään maksettavan tuoton osuus: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Osuus tuotosta, joka annetaan välittäjille syöttöjärjestelmissä STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Opastimien väli vedettäessä: {STRING} @@ -1583,6 +1598,10 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Mikäli käytö STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Kielletty STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Sallittu STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Sallittu, oma tiekaava +STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Taajamarahdin luonti: {STRING} +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Talojen tuottaman rahdin määrä suhteessa kunnan asukaslukuun.{}Neliöllinen kasvu: Kaksinkertainen asukasmäärä tuottaa matkustajia nelinkertaisesti.{}Lineaarinen kasvu: Kaksinkertainen asukasmäärä tuottaa matkustajia kaksinkertaisesti. +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL :Neliöllinen (alkuperäinen) +STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineaarinen STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Puiden istutus pelissä: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Määrittää puiden sattumanvaraisen luomisen. Tämä voi vaikuttaa teollisuuslaitoksiin jotka ovat riippuvaisia puiden kasvamisesta, esimerkiksi sahat @@ -1710,7 +1729,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Rahdin STR_CONFIG_SETTING_AI :{ORANGE}Kilpailijat STR_CONFIG_SETTING_AI_NPC :{ORANGE}Tietokonepelaajat -STR_CONFIG_SETTING_PATHFINDER_OPF :Alkuperäinen STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Suositeltu) @@ -1794,13 +1812,9 @@ STR_QUIT_NO :{BLACK}Ei # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2138,7 +2152,7 @@ STR_NETWORK_CHAT_ALL :[Kaikki] {STRIN STR_NETWORK_CHAT_OSKTITLE :{BLACK}Syötä teksti verkkokeskustelua varten # Network messages -STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Verkkolaitteita ei löytynyt tai käännetty ilman ENABLE_NETWORK-valintaa +STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Verkkolaitteita ei löytynyt STR_NETWORK_ERROR_NOSERVER :{WHITE}Verkkopelejä ei löytynyt STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Palvelin ei vastannut pyyntöön STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Yhteyden muodostaminen epäonnistui NewGRF-virheen vuoksi @@ -2430,6 +2444,11 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Rakenna STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Rakenna raitiotietunneli. Shift vaihtaa rakennustilan ja kustannusarvion välillä STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Tien rakentaminen/siirtäminen päälle/pois STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Vaihda raitiotien rakentamisen ja purkamisen välillä +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Muunna tai päivitä tien tyyppi. Shift vaihtaa muuntotilan ja kustannusarvion välillä +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Muunna tai päivitä raitiotien tyyppi. Shift vaihtaa muuntotilan ja kustannusarvion välillä + +STR_ROAD_NAME_ROAD :Tie +STR_ROAD_NAME_TRAM :Raitiotie # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Autovarikon suunta @@ -2614,8 +2633,11 @@ STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Vastaanottaa rahtia: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Raidetyyppi: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_ROAD_TYPE :{BLACK}Tien tyyppi: {LTBLUE}{STRING} +STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Raitiotien tyyppi: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Radan nopeusrajoitus: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Tien nopeusrajoitus: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Raitiotien nopeusrajoitus: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Kalliota @@ -2725,6 +2747,7 @@ STR_FRAMERATE_SPEED_FACTOR :{BLACK}Pelin ny STR_FRAMERATE_SPEED_FACTOR_TOOLTIP :{BLACK}Pelin tämänhetkinen nopeus verrattuna normaalilla simulaationopeudella odotettavissa olevaan STR_FRAMERATE_CURRENT :{WHITE}Nykyinen STR_FRAMERATE_AVERAGE :{WHITE}Keskiarvo +STR_FRAMERATE_MEMORYUSE :{WHITE}Muisti STR_FRAMERATE_DATA_POINTS :{BLACK}Data perustuu {COMMA} mittaukseen STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_WARN :{YELLOW}{DECIMAL} ms @@ -2732,6 +2755,9 @@ STR_FRAMERATE_MS_BAD :{RED}{DECIMAL} STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} kuvaa/s STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} kuvaa/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} kuvaa/s +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! @@ -3098,6 +3124,8 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Nimeä kunta # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN}: viranomaiset +STR_LOCAL_AUTHORITY_ZONE :{BLACK}Alue +STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}Näytä paikallisviranomaisten hallinnoiman alueen raja STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Kuljetusyhtiön arvioinnit: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Toiminnot: @@ -3355,8 +3383,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rautatiepalat: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Opastimet STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Teiden palat: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Tie -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Raitiotie +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Raitiotiepalat: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vesiruudut: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanavat STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Asemat: @@ -3436,6 +3463,8 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Muut ajoneuvot STR_GROUP_DEFAULT_SHIPS :Muut laivat STR_GROUP_DEFAULT_AIRCRAFTS :Muut lentokoneet +STR_GROUP_COUNT_WITH_SUBGROUP :{TINY_FONT}{COMMA} (+{COMMA}) + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Ryhmät – napsauta ryhmää nähdäksesi kaikki kulkuneuvot tässä ryhmässä. Järjestä ryhmiä vetämällä ja pudottamalla. STR_GROUP_CREATE_TOOLTIP :{BLACK}Luo ryhmä STR_GROUP_DELETE_TOOLTIP :{BLACK}Poista valittu ryhmä @@ -3462,12 +3491,18 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Uusi sähköjun STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Uusi yksiraidejuna STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Uusi Maglev-juna -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Uudet junat STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Uusia ajoneuvoja +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :Uusia raitiovaunuja + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Uudet junat +STR_BUY_VEHICLE_ROAD_VEHICLE_ALL_CAPTION :Uusia ajoneuvoja STR_BUY_VEHICLE_SHIP_CAPTION :Uusia laivoja STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Uusi lentokone +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Hinta: {GOLD}{CURRENCY_LONG}{BLACK} Paino: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}Hinta: {GOLD}{CURRENCY_LONG}{BLACK} (Sovituskustannus: {GOLD}{CURRENCY_LONG}{BLACK}) Paino: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Nopeus: {GOLD}{VELOCITY}{BLACK} Teho: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Nopeus: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Nopeus merellä: {GOLD}{VELOCITY} @@ -3478,8 +3513,10 @@ STR_PURCHASE_INFO_REFITTABLE :(sovitettava) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Suunniteltu: {GOLD}{NUM}{BLACK} Elinikä: {GOLD}{COMMA} vuo{P si tta} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Enimmäisluotettavuus: {GOLD}{COMMA}{NBSP}% STR_PURCHASE_INFO_COST :{BLACK}Hinta: {GOLD}{CURRENCY_LONG} +STR_PURCHASE_INFO_COST_REFIT :{BLACK}Hinta: {GOLD}{CURRENCY_LONG}{BLACK} (Sovituskustannus: {GOLD}{CURRENCY_LONG}{BLACK}) STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Paino: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Hinta: {GOLD}{CURRENCY_LONG}{BLACK} Nopeus: {GOLD}{VELOCITY} +STR_PURCHASE_INFO_COST_REFIT_SPEED :{BLACK}Hinta: {GOLD}{CURRENCY_LONG}{BLACK} (Sovituskustannus: {GOLD}{CURRENCY_LONG}{BLACK}) Nopeus: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Kapasiteetti: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Moottoroidut vaunut: {GOLD}+{POWER}{BLACK} Paino: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Sovitettavissa: {GOLD}{STRING} @@ -3500,11 +3537,21 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Osta ajo STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Osta laiva STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Osta lentokone +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Osta ja sovita yksikkö +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Osta ja sovita ajoneuvo +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Osta ja sovita laiva +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}Osta ja sovita lentokone + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valittu yksikkö. Shift+Klik näyttää kustannusarvion ostamatta STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valittu ajoneuvo. Shift+Klik näyttää kustannusarvion ostamatta STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Osta valittu laiva. Shift+Klik näyttää kustannusarvion ostamatta STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Osta korostettu lentokone. Shift+Klik näyttää kustannusarvion ostamatta +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Osta ja sovita valittu yksikkö. Shift+Klik näyttää kustannusarvion ostamatta +STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Osta ja sovita valittu ajoneuvo. Shift+Klik näyttää kustannusarvion ostamatta +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Osta ja sovita valittu laiva. Shift+Klik näyttää kustannusarvion ostamatta +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}Osta ja sovita valittu lentokone. Shift+Klik näyttää kustannusarvion ostamatta + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Nimeä STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Nimeä STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Nimeä @@ -3613,13 +3660,18 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Olet my # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Viesti kulkuneuvovalmistajalta STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Olemme juuri suunnitelleet uuden {STRING} – oletteko kiinnostunut vuoden yksinoikeutetusta kokeilusta, jotta näemme miten tuote suoriutuu ennen kuin julkistamme sen yleiseen käyttöön? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :veturin -STR_ENGINE_PREVIEW_ROAD_VEHICLE :ajoneuvon -STR_ENGINE_PREVIEW_AIRCRAFT :lentokoneen -STR_ENGINE_PREVIEW_SHIP :laivan +STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :sähköradan veturi STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :yksiraiteisen veturin STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev-veturin +STR_ENGINE_PREVIEW_ROAD_VEHICLE :ajoneuvon +STR_ENGINE_PREVIEW_TRAM_VEHICLE :raitiovaunu + +STR_ENGINE_PREVIEW_AIRCRAFT :lentokoneen +STR_ENGINE_PREVIEW_SHIP :laivan + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Hinta: {CURRENCY_LONG} Paino: {WEIGHT_SHORT}{}Nopeus: {VELOCITY} Teho: {POWER}{}Käyttökustannukset: {CURRENCY_LONG}/vuosi{}Kapasiteetti: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Hinta: {CURRENCY_LONG} Paino: {WEIGHT_SHORT}{}Nopeus: {VELOCITY} Teho: {POWER} Maks. vetovoima: {6:FORCE}{}Käyttökustannukset: {4:CURRENCY_LONG}/v{}Kapasiteetti: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Hinta: {CURRENCY_LONG} Maks. nopeus: {VELOCITY}{}Kapasiteetti: {CARGO_LONG}{}Käyttökustannukset: {CURRENCY_LONG}/v @@ -3657,14 +3709,19 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Vaihda t STR_REPLACE_ENGINES :Veturit STR_REPLACE_WAGONS :Vaunut STR_REPLACE_ALL_RAILTYPE :Kaikki junat +STR_REPLACE_ALL_ROADTYPE :Kaikki ajoneuvot STR_REPLACE_HELP_RAILTYPE :{BLACK}Valitse rautatietyyppi, jolle veturikorvaukset tehdään. +STR_REPLACE_HELP_ROADTYPE :{BLACK}Valitse tien tyyppi, jolle ajoneuvojen korvaukset tehdään STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Näyttää, millä vasemmalta valittu veturi korvataan, jos millään. STR_REPLACE_RAIL_VEHICLES :Junat STR_REPLACE_ELRAIL_VEHICLES :Sähköjunat STR_REPLACE_MONORAIL_VEHICLES :Yksiraiteiset STR_REPLACE_MAGLEV_VEHICLES :Maglev-junat +STR_REPLACE_ROAD_VEHICLES :Ajoneuvot +STR_REPLACE_TRAM_VEHICLES :Raitiovaunut + STR_REPLACE_REMOVE_WAGON :{BLACK}Vaunun poisto: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Automaattikorvauksessa junapituus pidetään samana poistamalla vaunuja (edestä) jos veturi pidentäisi junaa @@ -4386,7 +4443,8 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Opastime STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ei kelvollista rautatietä. STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Rautatie pitää poistaa ensin. STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Tie on yksisuuntainen tai suljettu -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Tasoristeykset eivät ole sallittu tälle raidetyypille +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Tasoristeykset eivät ole sallittu tälle raidetyypille +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Tasoristeykset eivät ole sallittuja tälle tietyypille STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Opastinta ei voi rakentaa. STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Rautatietä ei voi rakentaa. STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Rautatietä ei voi poistaa. @@ -4406,6 +4464,12 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Tietä e STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Tästä ei voi poistaa raitiotietä. STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... tässä ei ole tietä STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... tässä ei ole raitiotietä +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Tien tyyppiä ei voi muuntaa tässä... +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}Raitiotien tyyppiä ei voi muuntaa tässä... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Ei sopivaa tietä +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}Ei sopivaa raitiotietä +STR_ERROR_INCOMPATIBLE_ROAD :{WHITE}... yhteensopimaton tie +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... yhteensopimaton raitiotie # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Kanaalia ei voi rakentaa tähän... @@ -4458,6 +4522,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Ei voi l STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Ryhmää ei voi poistaa. STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Ryhmää ei voi nimetä. STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Pääryhmää ei voi määrittää... +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... ryhmähierarkiassa ei saa olla silmukoita STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Ryhmän kaikkia kulkuneuvoja ei voi poistaa. STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Ei voi lisätä kulkuneuvoa ryhmään. STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Ei voi lisätä jaettuja kulkuneuvoja ryhmään. diff --git a/src/lang/french.txt b/src/lang/french.txt index b531327fca..442b94b17d 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -39,7 +39,7 @@ STR_CARGO_PLURAL_WOOD :Bois STR_CARGO_PLURAL_IRON_ORE :Minerai de fer STR_CARGO_PLURAL_STEEL :Acier STR_CARGO_PLURAL_VALUABLES :Objets de valeur -STR_CARGO_PLURAL_COPPER_ORE :Cuivre +STR_CARGO_PLURAL_COPPER_ORE :Minerai de cuivre STR_CARGO_PLURAL_MAIZE :Maïs STR_CARGO_PLURAL_FRUIT :Fruits STR_CARGO_PLURAL_DIAMONDS :Diamants @@ -73,7 +73,7 @@ STR_CARGO_SINGULAR_WOOD :Bois STR_CARGO_SINGULAR_IRON_ORE :Minerai de fer STR_CARGO_SINGULAR_STEEL :Acier STR_CARGO_SINGULAR_VALUABLES :Objets de valeur -STR_CARGO_SINGULAR_COPPER_ORE :Cuivre +STR_CARGO_SINGULAR_COPPER_ORE :Minerai de cuivre STR_CARGO_SINGULAR_MAIZE :Maïs STR_CARGO_SINGULAR_FRUIT :Fruit STR_CARGO_SINGULAR_DIAMOND :Diamant @@ -107,7 +107,7 @@ STR_QUANTITY_WOOD :{WEIGHT_LONG} d STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} de minerai de fer STR_QUANTITY_STEEL :{WEIGHT_LONG} d'acier STR_QUANTITY_VALUABLES :{COMMA}{NBSP}sac{P "" s} d'objets de valeur -STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} de cuivre +STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} de minerai de cuivre STR_QUANTITY_MAIZE :{WEIGHT_LONG} de maïs STR_QUANTITY_FRUIT :{WEIGHT_LONG} de fruits STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}sac{P "" s} de diamants @@ -238,6 +238,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Choisir STR_BUTTON_SORT_BY :{BLACK}Trier par STR_BUTTON_LOCATION :{BLACK}Emplacement STR_BUTTON_RENAME :{BLACK}Renommer +STR_BUTTON_CATCHMENT :{BLACK}Couverture +STR_TOOLTIP_CATCHMENT :{BLACK}Basculer l'affichage de la zone couverte STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Fermer la fenêtre STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Titre de fenêtre - Faire glisser pour déplacer la fenêtre @@ -266,6 +268,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}En activ STR_BUTTON_DEFAULT :{BLACK}Défaut STR_BUTTON_CANCEL :{BLACK}Annuler STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Attention{NBSP}: Les administrateurs du serveur pourraient lire tout texte entré ici. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :²&é"'(-è_çà)= azertyuiop^$qsdfghjklmù* @@ -2999,6 +3057,7 @@ STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}为标 STR_TOWN_DIRECTORY_CAPTION :{WHITE}城镇 STR_TOWN_DIRECTORY_NONE :{ORANGE}- 没有 - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) +STR_TOWN_DIRECTORY_CITY :{ORANGE}{TOWN}{YELLOW} (都市){BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK} 城镇名称 点击名称可以将屏幕中心{}移动到城镇所在的位置. 单击的同时按住Ctrl会在新视点中显示城镇位置 STR_TOWN_POPULATION :{BLACK}所有城镇人口总数:{COMMA} @@ -3006,6 +3065,7 @@ STR_TOWN_POPULATION :{BLACK}所有 STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (都市) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}人口:{ORANGE}{COMMA}{BLACK} 房屋:{ORANGE}{COMMA} +STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX :{BLACK}{CARGO_LIST} 上月:{ORANGE}{COMMA}{BLACK} 最大:{ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}城镇发展所必需的货物: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{RED} 需要: {ORANGE}{STRING} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} 冬季的需求 @@ -3030,6 +3090,7 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :重命名城镇 # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} 地方政府 +STR_LOCAL_AUTHORITY_ZONE :{BLACK}城区 STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}对运输公司评价: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}可执行的操作: @@ -3058,7 +3119,8 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}贿赂 # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} 目标 STR_GOALS_SPECTATOR_CAPTION :{WHITE}全球目标: -STR_GOALS_GLOBAL_TITLE :{BLACK}全球目标: +STR_GOALS_SPECTATOR :全局目标 +STR_GOALS_GLOBAL_TITLE :{BLACK}全局目标: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- 无目标 - STR_GOALS_SPECTATOR_NONE :{ORANGE}- 不适用 - @@ -3106,6 +3168,7 @@ STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}点击 # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY}的历史纪录 STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}全域历史纪录 +STR_STORY_BOOK_SPECTATOR :全域历史纪录 STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :第{NUM}页 STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}从下拉选单中选择想要查看的页面. @@ -3285,8 +3348,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}铁路: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}信号灯 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}道路: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}普通道路 -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}电车线路 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}水运: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}运河 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}站台: @@ -3310,6 +3371,7 @@ STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}将屏 STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}生产程度: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}此工业已经宣布即刻停业倒闭! +STR_INDUSTRY_VIEW_REQUIRES_N_CARGO :{BLACK}需要: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{STRING}{BLACK}{3:STRING} STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW}{STRING}{BLACK}: {CARGO_SHORT} 等待中{STRING} @@ -3362,6 +3424,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :未分组汽车 STR_GROUP_DEFAULT_SHIPS :未分组船只 STR_GROUP_DEFAULT_AIRCRAFTS :未分组飞机 + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}组 - 点击一个组别以显示所有隶属此组的车辆。拖曳组别标签以重新排列组别的次序和层级。 STR_GROUP_CREATE_TOOLTIP :{BLACK}创建分组 STR_GROUP_DELETE_TOOLTIP :{BLACK}删除分组 @@ -3387,12 +3450,17 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :购买电气化 STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :购买单轨列车 STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :购买磁悬浮列车 -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :新列车 STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :购买汽车 +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :新电车 + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :新列车 STR_BUY_VEHICLE_SHIP_CAPTION :购买船只 STR_BUY_VEHICLE_AIRCRAFT_CAPTION :购买飞机 +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}售价:{GOLD}{CURRENCY_LONG}{BLACK} 重量:{GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}售价: {GOLD}{CURRENCY_LONG}{BLACK} (改装花费: {GOLD}{CURRENCY_LONG}{BLACK}) 重量: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}速度:{GOLD}{VELOCITY}{BLACK} 功率:{GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}速度:{GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}在海洋上的速度: {GOLD}{VELOCITY} @@ -3409,6 +3477,7 @@ STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}运载 STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}功率:{GOLD}+{POWER}{BLACK} 重量:{GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}可改装为:{GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :所有类型 +STR_PURCHASE_INFO_NONE :无 STR_PURCHASE_INFO_ALL_BUT :除了 {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}最大牵引力:{GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}航行距离: {GOLD}{COMMA} 格 @@ -3424,11 +3493,15 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}购买 STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}购买船只 STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}购买飞机 +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}购买并改装 +STR_BUY_VEHICLE_AIRCRAFT_BUY_REFIT_VEHICLE_BUTTON :{BLACK}购买并改装飞机 + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}购买选定的列车,按住 Shift 键单击可以显示所需资金 STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}购买选定的汽车,按住 Shift 键单击可以显示所需资金 STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}购买选定的船只,按住 Shift 键单击可以显示所需资金 STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}购买选定的飞机,按住 Shift 键单击可以显示所需资金 + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}重命名 STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}重命名 STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}重命名 @@ -3537,13 +3610,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}你将 # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}来自供货商的消息 STR_ENGINE_PREVIEW_MESSAGE :{GOLD}我们新近设计了一款{STRING}{}您愿意在产品正式上市前试用一年吗? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :火车机车 -STR_ENGINE_PREVIEW_ROAD_VEHICLE :汽车 -STR_ENGINE_PREVIEW_AIRCRAFT :飞机 -STR_ENGINE_PREVIEW_SHIP :船只 STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :单轨机车 STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :磁悬浮机车 +STR_ENGINE_PREVIEW_ROAD_VEHICLE :汽车 + +STR_ENGINE_PREVIEW_AIRCRAFT :飞机 +STR_ENGINE_PREVIEW_SHIP :船只 + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}售价:{CURRENCY_LONG} 重量:{WEIGHT_SHORT}{}速度:{VELOCITY} 功率:{POWER}{}运行费用:{CURRENCY_LONG}/年{}运载能力: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}售价:{CURRENCY_LONG} 重量:{WEIGHT_SHORT}{}速度:{VELOCITY} 功率:{POWER} 最大牵引力:{6:FORCE}{}运行费用{4:CURRENCY_LONG}/年{}运载能力:{5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}售价:{CURRENCY_LONG} 最大速度:{VELOCITY}{}运载能力:{CARGO_LONG}{}运行成本:{CURRENCY_LONG} /年 @@ -3581,14 +3657,17 @@ STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}可以 STR_REPLACE_ENGINES :机车 STR_REPLACE_WAGONS :挂车 STR_REPLACE_ALL_RAILTYPE :所有铁路车辆 +STR_REPLACE_ALL_ROADTYPE :所有道路载具 STR_REPLACE_HELP_RAILTYPE :{BLACK}选择要更新的车辆对应的铁路类型 +STR_REPLACE_HELP_ROADTYPE :{BLACK}选择要更新的车辆对应的道路类型 STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}显示用来替换左侧被选定车辆的新车辆 STR_REPLACE_RAIL_VEHICLES :普通列车 STR_REPLACE_ELRAIL_VEHICLES :电力机车 STR_REPLACE_MONORAIL_VEHICLES :单轨列车 STR_REPLACE_MAGLEV_VEHICLES :磁悬浮列车 + STR_REPLACE_REMOVE_WAGON :{BLACK}清理挂车:{ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}当车辆升级可能造成列车变长时{}自动从最前面的挂车去掉若干节以保证列车长度不变 @@ -3674,6 +3753,7 @@ STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} STR_VEHICLE_INFO_MAX_SPEED :{BLACK}最大速度:{LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_TYPE :{BLACK}最高速度: {LTBLUE}{VELOCITY} {BLACK}飞机种类: {LTBLUE}{STRING} +STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE :{BLACK}最大速度: {LTBLUE}{VELOCITY} {BLACK}飞机类型: {LTBLUE}{STRING} {BLACK}续航里程: {LTBLUE}{COMMA} 格 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}重量:{LTBLUE}{WEIGHT_SHORT} {BLACK}功率:{LTBLUE}{POWER}{BLACK} 最大速度:{LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}重量:{LTBLUE}{WEIGHT_SHORT} {BLACK}功率:{LTBLUE}{POWER}{BLACK} 最大速度:{LTBLUE}{VELOCITY} {BLACK}最大牵引力:{LTBLUE}{FORCE} @@ -3807,6 +3887,7 @@ STR_ORDER_CONDITIONAL_AGE :寿命(年) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :需要维修 STR_ORDER_CONDITIONAL_UNCONDITIONALLY :总是 STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :剩余寿命年限 (年) +STR_ORDER_CONDITIONAL_MAX_RELIABILITY :最大可靠度 STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}如何比较车辆数据值与所给数据 STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :等于 @@ -4308,7 +4389,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}必须 STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}没有合适的轨道 STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}必须先拆除轨道 STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}这是单行道或这条路被堵死了 -STR_ERROR_CROSSING_DISALLOWED :{WHITE}该轨道类型不允许建设平交道 +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}该轨道类型不允许建设平交道 STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}不能在这里设置信号灯…… STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}不能在这里铺设轨道…… STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}不能从这里拆除轨道…… @@ -4328,6 +4409,8 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}不能 STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}无法移除此处的电车道... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... 这里没有道路 STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... 这里没有电车轨道 +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}无法转换道路类型 +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}没有合适的道路 # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}不能在这里兴建运河…… diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index 4ba647de92..995007c687 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -1752,7 +1752,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distrib STR_CONFIG_SETTING_AI :{ORANGE}Konkurenti STR_CONFIG_SETTING_AI_NPC :{ORANGE}Počítačový hráči -STR_CONFIG_SETTING_PATHFINDER_OPF :Pôvodný STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(odporučený) @@ -1835,13 +1834,9 @@ STR_QUIT_NO :{BLACK}Nie # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2469,6 +2464,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Postavi STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Prepnúť stavbu/odstraňovanie cesty STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Prepnúť stavbu/odstraňovanie električkovej dráhy + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Orientacia garaze STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Zvoľte orientáciu garáže @@ -3328,8 +3324,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrašt STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Políčka železnice: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Semafóry STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Políčka cesty: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Električka STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vodné políčka: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanále STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stanice: @@ -3403,6 +3397,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Nezaradené voz STR_GROUP_DEFAULT_SHIPS :Nezaradené lode STR_GROUP_DEFAULT_AIRCRAFTS :Nezaradené lietadlá + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Skupiny - klikni na skupinu pre zobrazenie všetkých vozidiel skupiny. Ťahaj a Pusti pre usporiadanie hierarchiu v skupine STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikni pre vytvorenie skupiny STR_GROUP_DELETE_TOOLTIP :{BLACK}Zrušiť vybranú skupinu @@ -3424,10 +3419,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nové elektrick STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nové jednokoľajové vlaky STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nové magnetické vlaky -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Železnicne vozidlá STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nové automobily + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Železnicne vozidlá STR_BUY_VEHICLE_SHIP_CAPTION :Nové lode STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nove Lietadlo +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Hmotnosť: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Rýchlosť: {GOLD}{VELOCITY}{BLACK} Výkon: {GOLD}{POWER} @@ -3460,11 +3458,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Kúpiť STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Kúpiť loď STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Kúpiť lietadlo + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Kúpiť vybraný vlak. Shift+klik zobrazí predpokladanú cenu bez nákupu. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Kúpiť vybrané vozidlo. Shift+klik zobrazí predpokladanú cenu bez nákupu STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Kúpiť vybranú loď. Shift+klik zobrazí predpokladanú cenu bez nákupu STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Kúpiť vybrané lietadlo. Shift+klik zobrazí predpokladanú cenu bez nákupu + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Premenovať STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Premenovať STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Premenovať @@ -3573,13 +3573,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Chystá # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Správa od výrobcu dopravných prostriedkov STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Práve sme navrhli nov{G "ý" "ú" "é"} {STRING} - máte záujem o právo exkluzívneho používania na 1 rok? Chceme otestovať vlastnosti tohto modelu pred jeho uvedením na trh. + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :{G=z}železničná lokomotíva -STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=m}automobil -STR_ENGINE_PREVIEW_AIRCRAFT :{G=s}lietadlo -STR_ENGINE_PREVIEW_SHIP :{G=z}loď STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :{G=z}jednokoľajová lokomotíva STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :{G=z}magnetická lokomotíva +STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=m}automobil + +STR_ENGINE_PREVIEW_AIRCRAFT :{G=s}lietadlo +STR_ENGINE_PREVIEW_SHIP :{G=z}loď + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cena: {CURRENCY_LONG} Hmotnosť: {WEIGHT_SHORT}{}Rýchlosť: {VELOCITY} Výkon: {POWER}{}Prevádzkové náklady: {CURRENCY_LONG}/rok{}Kapacita: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cena: {CURRENCY_LONG} Hmotnosť: {WEIGHT_SHORT}{}Rýchlosť: {VELOCITY} Sila: {POWER} Max. T.E.: {6:FORCE}{}Prevádzkové náklady: {4:CURRENCY_LONG}/yr{}Kapacita: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Max. Rýchlosť: {VELOCITY}{}Kapacita: {CARGO_LONG}{}Prevádzkové náklady: {CURRENCY_LONG}/rok @@ -3620,6 +3623,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Elektrické lok STR_REPLACE_MONORAIL_VEHICLES :Lokomotíva pre jednokoľajku STR_REPLACE_MAGLEV_VEHICLES :Lokomotíva pre magnetickú dráhu + STR_REPLACE_REMOVE_WAGON :{BLACK}Odstránenie vagónu: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Zachovanie pôvodnej dĺžky vlaku, odstránením vagónov (odpredu), keď by funkcia automatickej zmeny rušňa vlak predĺžila @@ -4338,7 +4342,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprv j STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Žiadne použiteľné železničné koľaje STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Musíš najskôr odstrániť železničné koľaje STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je jednosmerná alebo blokovaná. -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Nie sú povolené priecestia pre tento typ železníc +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Nie sú povolené priecestia pre tento typ železníc STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Nemôžeš tu stavať návestidlá... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nemôžeš tu stavať železničné koľaje... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nemôžeš tu odstrániť železničné koľaje... diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index 1970c28ef7..7ab44e1258 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -1839,7 +1839,6 @@ STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Razpore STR_CONFIG_SETTING_AI :{ORANGE}Tekmeci STR_CONFIG_SETTING_AI_NPC :{ORANGE}Računalniški igralci -STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Priporočeno) @@ -1922,13 +1921,9 @@ STR_QUIT_NO :{BLACK}Ne # Supported OSes STR_OSNAME_WINDOWS :Windows -STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X -STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku -STR_OSNAME_MORPHOS :MorphOS -STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS @@ -2557,6 +2552,7 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Zgradi p STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Preklopi gradnja/rušenje cestnih konstrukcij STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Preklop gradi/odstrani za tramvaj progo + # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Smer garaže STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Izberi smer garaže @@ -3416,8 +3412,6 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastr STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Kosi tirov: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signali STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Odseki cest: -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta -STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvaj STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Polja vode: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Postaje: @@ -3491,6 +3485,7 @@ STR_GROUP_DEFAULT_ROAD_VEHICLES :Cestna vozila b STR_GROUP_DEFAULT_SHIPS :Ladje brez skupine STR_GROUP_DEFAULT_AIRCRAFTS :Letala brez skupine + STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Skupine - Klikni na skupino za seznam vseh vozil v skupini STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikni za ustvarit skupino STR_GROUP_DELETE_TOOLTIP :{BLACK}Izbriši izbrano skupino @@ -3512,10 +3507,13 @@ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nova električn STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nova enotirna vozila STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nova magnetna vozila -STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nova tirna vozila STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nova cestna vozila + +############ range for vehicle availability starts +STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nova tirna vozila STR_BUY_VEHICLE_SHIP_CAPTION :Nove ladje STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nova letala +############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Teža: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Hitrost: {GOLD}{VELOCITY}{BLACK} Moč: {GOLD}{POWER} @@ -3548,11 +3546,13 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Kupi voz STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Kupi ladjo STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Kupi letalo + STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi izbrano železniško vozilo. Shift+Klik prikaže predviden strošek brez nakupa STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi izbrano cestno vozilo. Shift+Klik prikaže predviden strošek brez nakupa STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi izbrano ladjo. Shift+Klik prikaže predviden strošek brez nakupa STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi izbrano letalo. Shift+Klik prikaže predviden strošek brez nakupa + STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Preimenuj @@ -3661,13 +3661,16 @@ STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Priprav # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Sporočilo od proizvajalca vozila STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Na novo smo izdelali {STRING} - ali te zanima enoletna izključna pravica do{}uporabe tega vozila, preden ga ponudimo{}na trgu? + STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :železniška lokomotiva -STR_ENGINE_PREVIEW_ROAD_VEHICLE :cestno vozilo -STR_ENGINE_PREVIEW_AIRCRAFT :letalo -STR_ENGINE_PREVIEW_SHIP :ladja STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :enotirna lokomotiva STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :magnetna lokomotiva +STR_ENGINE_PREVIEW_ROAD_VEHICLE :cestno vozilo + +STR_ENGINE_PREVIEW_AIRCRAFT :letalo +STR_ENGINE_PREVIEW_SHIP :ladja + STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cena: {CURRENCY_LONG} Teža: {WEIGHT_SHORT}{}Hitrost: {VELOCITY} Moč: {POWER}{}Cena delovanja: {CURRENCY_LONG}/leto{}Zmogljivost: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cena: {CURRENCY_LONG} Teža: {WEIGHT_SHORT}{}Hitrost: {VELOCITY} Moč: {POWER} Max. T.E.: {6:FORCE}{}Stroški: {4:CURRENCY_LONG}/yr{}Zmogljivost: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Max. hitrost: {VELOCITY}{}Zmogljivost: {CARGO_LONG}{}Cena delovanja: {CURRENCY_LONG}/leto @@ -3709,6 +3712,7 @@ STR_REPLACE_ELRAIL_VEHICLES :Električna tir STR_REPLACE_MONORAIL_VEHICLES :Enotirna vozila STR_REPLACE_MAGLEV_VEHICLES :Magnetna tirna vozila + STR_REPLACE_REMOVE_WAGON :{BLACK}Odstranitev vagonov: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Dovoli samozamenjavi, da z odstranitvijo vagonov, začenši na začetku, ohrani isto dolžino vlaka, če bi ga menjava lokomotive podaljšala @@ -4428,7 +4432,7 @@ STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprej STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Ni primernih tračnic STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprej moraš odstraniti tračnice STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je enosmerna ali blokirana -STR_ERROR_CROSSING_DISALLOWED :{WHITE}Istonivojna križišča niso dovoljena za ta tip železnice +STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Istonivojna križišča niso dovoljena za ta tip železnice STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Tukaj ni mogoče zgraditi signalov... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Tukaj ni mogoče zgraditi železniških tirov... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Tukaj ni mogoče odstraniti železniških tirov... diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 54825bc3c5..c439b70acd 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -238,6 +238,8 @@ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Seleccio STR_BUTTON_SORT_BY :{BLACK}Ordenar por STR_BUTTON_LOCATION :{BLACK}Sitio STR_BUTTON_RENAME :{BLACK}Renombrar +STR_BUTTON_CATCHMENT :{BLACK}Cobertura +STR_TOOLTIP_CATCHMENT :{BLACK}Mostrar u ocultar área de cobertura STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Cerrar ventana STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Título de la ventana - arrastre para moverla @@ -266,6 +268,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Al activ STR_BUTTON_DEFAULT :{BLACK}Por defecto STR_BUTTON_CANCEL :{BLACK}Cancelar STR_BUTTON_OK :{BLACK}OK +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Advertencia: Los administradores del servidor podrían ser capaz de leer cualquier texto introducido aquí. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :º1234567890'¡\qwertyuiop`+asdfghjklñ´ç -#endif /* WITH_ICU_SORT */ +#endif /* WITH_ICU_I18N */ #include "strings_type.h" static const uint8 CASE_GENDER_LEN = 16; ///< The (maximum) length of a case/gender string. @@ -96,7 +96,7 @@ struct LanguageMetadata : public LanguagePackHeader { }; /** Type for the list of language meta data. */ -typedef SmallVector LanguageList; +typedef std::vector LanguageList; /** The actual list of language meta data. */ extern LanguageList _languages; @@ -104,9 +104,9 @@ extern LanguageList _languages; /** The currently loaded language. */ extern const LanguageMetadata *_current_language; -#ifdef WITH_ICU_SORT +#ifdef WITH_ICU_I18N extern icu::Collator *_current_collator; -#endif /* WITH_ICU_SORT */ +#endif /* WITH_ICU_I18N */ bool ReadLanguagePack(const LanguageMetadata *lang); const LanguageMetadata *GetLanguage(byte newgrflangid); diff --git a/src/linkgraph/demands.h b/src/linkgraph/demands.h index 8a639b8b15..6fe3768341 100644 --- a/src/linkgraph/demands.h +++ b/src/linkgraph/demands.h @@ -23,7 +23,7 @@ private: }; /** - * Stateless, thread safe demand hander. Doesn't do anything but call DemandCalculator. + * Stateless, thread safe demand handler. Doesn't do anything but call DemandCalculator. */ class DemandHandler : public ComponentHandler { public: diff --git a/src/linkgraph/init.h b/src/linkgraph/init.h index a39a0f8205..377c886311 100644 --- a/src/linkgraph/init.h +++ b/src/linkgraph/init.h @@ -6,7 +6,7 @@ #include "linkgraphjob_base.h" /** - * Stateless, thread safe initialization hander. Initializes node and edge + * Stateless, thread safe initialization handler. Initializes node and edge * annotations. */ class InitHandler : public ComponentHandler { diff --git a/src/linkgraph/linkgraph.cpp b/src/linkgraph/linkgraph.cpp index 34b3a4aa09..234b0be605 100644 --- a/src/linkgraph/linkgraph.cpp +++ b/src/linkgraph/linkgraph.cpp @@ -139,7 +139,10 @@ void LinkGraph::RemoveNode(NodeID id) node_edges[id] = node_edges[last_node]; } Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id; - this->nodes.Erase(this->nodes.Get(id)); + /* Erase node by swapping with the last element. Node index is referenced + * directly from station goods entries so the order and position must remain. */ + this->nodes[id] = this->nodes.back(); + this->nodes.pop_back(); this->edges.EraseColumn(id); /* Not doing EraseRow here, as having the extra invalid row doesn't hurt * and removing it would trigger a lot of memmove. The data has already @@ -159,7 +162,7 @@ NodeID LinkGraph::AddNode(const Station *st) const GoodsEntry &good = st->goods[this->cargo]; NodeID new_node = this->Size(); - this->nodes.Append(); + this->nodes.emplace_back(); /* Avoid reducing the height of the matrix as that is expensive and we * most likely will increase it again later which is again expensive. */ this->edges.Resize(new_node + 1U, @@ -281,7 +284,7 @@ void LinkGraph::Init(uint size) { assert(this->Size() == 0); this->edges.Resize(size, size); - this->nodes.Resize(size); + this->nodes.resize(size); for (uint i = 0; i < size; ++i) { this->nodes[i].Init(); diff --git a/src/linkgraph/linkgraph.h b/src/linkgraph/linkgraph.h index 799f22c780..7f2561e754 100644 --- a/src/linkgraph/linkgraph.h +++ b/src/linkgraph/linkgraph.h @@ -435,7 +435,7 @@ public: void RemoveEdge(NodeID to); }; - typedef SmallVector NodeVector; + typedef std::vector NodeVector; typedef SmallMatrix EdgeMatrix; /** Minimum effective distance for timeout calculation. */ @@ -496,7 +496,7 @@ public: * Get the current size of the component. * @return Size. */ - inline uint Size() const { return this->nodes.Length(); } + inline uint Size() const { return (uint)this->nodes.size(); } /** * Get date of last compression. diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index 6844092c2e..ebba160bf7 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -301,7 +301,7 @@ void LinkGraphOverlay::DrawStationDots(const DrawPixelInfo *dpi) const { for (StationSupplyList::const_iterator i(this->cached_stations.begin()); i != this->cached_stations.end(); ++i) { const Station *st = Station::GetIfValid(i->first); - if (st == NULL) continue; + if (st == nullptr) continue; Point pt = this->GetStationMiddle(st); if (!this->IsPointVisible(pt, dpi, 3 * this->scale)) continue; @@ -345,7 +345,7 @@ void LinkGraphOverlay::DrawStationDots(const DrawPixelInfo *dpi) const */ Point LinkGraphOverlay::GetStationMiddle(const Station *st) const { - if (this->window->viewport != NULL) { + if (this->window->viewport != nullptr) { return GetViewportStationMiddle(this->window->viewport, st); } else { /* assume this is a smallmap */ @@ -399,7 +399,7 @@ NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) { static const uint ENTRIES_PER_ROW = CeilDiv(NUM_CARGO, 5); NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE); - NWidgetHorizontal *row = NULL; + NWidgetHorizontal *row = nullptr; for (uint i = 0; i < NUM_CARGO; ++i) { if (i % ENTRIES_PER_ROW == 0) { if (row) panel->Add(row); @@ -563,7 +563,7 @@ bool LinkGraphLegendWindow::OnTooltip(Point pt, int widget, TooltipCloseConditio { if (IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) { if (this->IsWidgetDisabled(widget)) { - GuiShowTooltips(this, STR_LINKGRAPH_LEGEND_SELECT_COMPANIES, 0, NULL, close_cond); + GuiShowTooltips(this, STR_LINKGRAPH_LEGEND_SELECT_COMPANIES, 0, nullptr, close_cond); } else { uint64 params[2]; CompanyID cid = (CompanyID)(widget - WID_LGL_COMPANY_FIRST); diff --git a/src/linkgraph/linkgraph_gui.h b/src/linkgraph/linkgraph_gui.h index 17fcd28b28..b913bb1f4a 100644 --- a/src/linkgraph/linkgraph_gui.h +++ b/src/linkgraph/linkgraph_gui.h @@ -104,11 +104,11 @@ public: LinkGraphLegendWindow(WindowDesc *desc, int window_number); void SetOverlay(LinkGraphOverlay *overlay); - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize); - virtual void DrawWidget(const Rect &r, int widget) const; - virtual bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond); - virtual void OnClick(Point pt, int widget, int click_count); - virtual void OnInvalidateData(int data = 0, bool gui_scope = true); + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override; + void DrawWidget(const Rect &r, int widget) const override; + bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override; + void OnClick(Point pt, int widget, int click_count) override; + void OnInvalidateData(int data = 0, bool gui_scope = true) override; private: LinkGraphOverlay *overlay; diff --git a/src/linkgraph/linkgraph_type.h b/src/linkgraph/linkgraph_type.h index 6a3239b089..1e3a0ff661 100644 --- a/src/linkgraph/linkgraph_type.h +++ b/src/linkgraph/linkgraph_type.h @@ -21,7 +21,7 @@ static const LinkGraphID INVALID_LINK_GRAPH_JOB = UINT16_MAX; typedef uint16 NodeID; static const NodeID INVALID_NODE = UINT16_MAX; -enum DistributionType { +enum DistributionType : byte { DT_BEGIN = 0, DT_MIN = 0, DT_MANUAL = 0, ///< Manual distribution. No link graph calculations are run. @@ -37,7 +37,6 @@ enum DistributionType { * Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT DistributionTypeByte; // typedefing-enumification of DistributionType /** * Special modes for updating links. 'Restricted' means that vehicles with diff --git a/src/linkgraph/linkgraphjob.cpp b/src/linkgraph/linkgraphjob.cpp index 537303cf35..cd358f37f0 100644 --- a/src/linkgraph/linkgraphjob.cpp +++ b/src/linkgraph/linkgraphjob.cpp @@ -39,7 +39,6 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig) : * This is on purpose. */ link_graph(orig), settings(_settings_game.linkgraph), - thread(NULL), join_date(_date + _settings_game.linkgraph.recalc_time) { } @@ -61,10 +60,9 @@ void LinkGraphJob::EraseFlows(NodeID from) */ void LinkGraphJob::SpawnThread() { - if (!ThreadObject::New(&(LinkGraphSchedule::Run), this, &this->thread, "ottd:linkgraph")) { - this->thread = NULL; + if (!StartNewThread(&this->thread, "ottd:linkgraph", &(LinkGraphSchedule::Run), this)) { /* Of course this will hang a bit. - * On the other hand, if you want to play games which make this hang noticably + * On the other hand, if you want to play games which make this hang noticeably * on a platform without threads then you'll probably get other problems first. * OK: * If someone comes and tells me that this hangs for him/her, I'll implement a @@ -79,10 +77,8 @@ void LinkGraphJob::SpawnThread() */ void LinkGraphJob::JoinThread() { - if (this->thread != NULL) { - this->thread->Join(); - delete this->thread; - this->thread = NULL; + if (this->thread.joinable()) { + this->thread.join(); } } @@ -106,7 +102,7 @@ LinkGraphJob::~LinkGraphJob() /* The station can have been deleted. Remove all flows originating from it then. */ Station *st = Station::GetIfValid(from.Station()); - if (st == NULL) { + if (st == nullptr) { this->EraseFlows(node_id); continue; } @@ -126,7 +122,7 @@ LinkGraphJob::~LinkGraphJob() if (from[it->first].Flow() == 0) continue; StationID to = (*this)[it->first].Station(); Station *st2 = Station::GetIfValid(to); - if (st2 == NULL || st2->goods[this->Cargo()].link_graph != this->link_graph.index || + if (st2 == nullptr || st2->goods[this->Cargo()].link_graph != this->link_graph.index || st2->goods[this->Cargo()].node != it->first || (*lg)[node_id][it->first].LastUpdate() == INVALID_DATE) { /* Edge has been removed. Delete flows. */ @@ -179,7 +175,7 @@ LinkGraphJob::~LinkGraphJob() void LinkGraphJob::Init() { uint size = this->Size(); - this->nodes.Resize(size); + this->nodes.resize(size); this->edges.Resize(size, size); for (uint i = 0; i < size; ++i) { this->nodes[i].Init(this->link_graph[i].Supply()); @@ -244,7 +240,7 @@ void Path::Fork(Path *base, uint cap, int free_cap, uint dist) */ uint Path::AddFlow(uint new_flow, LinkGraphJob &job, uint max_saturation) { - if (this->parent != NULL) { + if (this->parent != nullptr) { LinkGraphJob::Edge edge = job[this->parent->node][this->node]; if (max_saturation != UINT_MAX) { uint usable_cap = edge.Capacity() * max_saturation / 100; @@ -274,6 +270,6 @@ Path::Path(NodeID n, bool source) : capacity(source ? UINT_MAX : 0), free_capacity(source ? INT_MAX : INT_MIN), flow(0), node(n), origin(source ? n : INVALID_NODE), - num_children(0), parent(NULL) + num_children(0), parent(nullptr) {} diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index b4587a7842..fa6ca618a1 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -12,7 +12,7 @@ #ifndef LINKGRAPHJOB_H #define LINKGRAPHJOB_H -#include "../thread/thread.h" +#include "../thread.h" #include "linkgraph.h" #include @@ -50,7 +50,7 @@ private: void Init(uint supply); }; - typedef SmallVector NodeAnnotationVector; + typedef std::vector NodeAnnotationVector; typedef SmallMatrix EdgeAnnotationMatrix; friend const SaveLoad *GetLinkGraphJobDesc(); @@ -59,7 +59,7 @@ private: protected: const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later. const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time. - ThreadObject *thread; ///< Thread the job is running in or NULL if it's running in the main thread. + std::thread thread; ///< Thread the job is running in or a default-constructed thread if it's running in the main thread. Date join_date; ///< Date when the job is to be joined. NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation. EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation. @@ -266,7 +266,7 @@ public: * Bare constructor, only for save/load. link_graph, join_date and actually * settings have to be brutally const-casted in order to populate them. */ - LinkGraphJob() : settings(_settings_game.linkgraph), thread(NULL), + LinkGraphJob() : settings(_settings_game.linkgraph), join_date(INVALID_DATE) {} LinkGraphJob(const LinkGraph &orig); @@ -403,9 +403,9 @@ public: */ inline void Detach() { - if (this->parent != NULL) { + if (this->parent != nullptr) { this->parent->num_children--; - this->parent = NULL; + this->parent = nullptr; } } @@ -415,7 +415,7 @@ public: protected: /** - * Some boundaries to clamp agains in order to avoid integer overflows. + * Some boundaries to clamp against in order to avoid integer overflows. */ enum PathCapacityBoundaries { PATH_CAP_MULTIPLIER = 16, diff --git a/src/linkgraph/linkgraphschedule.cpp b/src/linkgraph/linkgraphschedule.cpp index 8c508d8173..c5f797f184 100644 --- a/src/linkgraph/linkgraphschedule.cpp +++ b/src/linkgraph/linkgraphschedule.cpp @@ -69,13 +69,11 @@ void LinkGraphSchedule::JoinNext() } /** - * Run all handlers for the given Job. This method is tailored to - * ThreadObject::New. - * @param j Pointer to a link graph job. + * Run all handlers for the given Job. + * @param job Pointer to a link graph job. */ -/* static */ void LinkGraphSchedule::Run(void *j) +/* static */ void LinkGraphSchedule::Run(LinkGraphJob *job) { - LinkGraphJob *job = (LinkGraphJob *)j; for (uint i = 0; i < lengthof(instance.handlers); ++i) { instance.handlers[i]->Run(*job); } diff --git a/src/linkgraph/linkgraphschedule.h b/src/linkgraph/linkgraphschedule.h index ec22be3161..b7dfa9793f 100644 --- a/src/linkgraph/linkgraphschedule.h +++ b/src/linkgraph/linkgraphschedule.h @@ -53,7 +53,7 @@ public: static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day. static LinkGraphSchedule instance; - static void Run(void *j); + static void Run(LinkGraphJob *job); static void Clear(); void SpawnNext(); diff --git a/src/linkgraph/mcf.cpp b/src/linkgraph/mcf.cpp index 544584ef61..c64674237f 100644 --- a/src/linkgraph/mcf.cpp +++ b/src/linkgraph/mcf.cpp @@ -104,7 +104,7 @@ public: * @param job Job to iterate on. */ GraphEdgeIterator(LinkGraphJob &job) : job(job), - i(NULL, NULL, INVALID_NODE), end(NULL, NULL, INVALID_NODE) + i(nullptr, nullptr, INVALID_NODE), end(nullptr, nullptr, INVALID_NODE) {} /** @@ -262,7 +262,7 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths) Tedge_iterator iter(this->job); uint size = this->job.Size(); AnnoSet annos; - paths.resize(size, NULL); + paths.resize(size, nullptr); for (NodeID node = 0; node < size; ++node) { Tannotation *anno = new Tannotation(node, node == source_node); anno->UpdateAnnotation(); @@ -305,16 +305,16 @@ void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths) void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths) { Path *source = paths[source_id]; - paths[source_id] = NULL; + paths[source_id] = nullptr; for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) { Path *path = *i; - if (path == NULL) continue; + if (path == nullptr) continue; if (path->GetParent() == source) path->Detach(); - while (path != source && path != NULL && path->GetFlow() == 0) { + while (path != source && path != nullptr && path->GetFlow() == 0) { Path *parent = path->GetParent(); path->Detach(); if (path->GetNumChildren() == 0) { - paths[path->GetNode()] = NULL; + paths[path->GetNode()] = nullptr; delete path; } path = parent; @@ -404,7 +404,7 @@ bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next /* this node has already been searched */ if (at_next_pos == Path::invalid_path) return false; - if (at_next_pos == NULL) { + if (at_next_pos == nullptr) { /* Summarize paths; add up the paths with the same source and next hop * in one path each. */ PathList &paths = this->job[next_id].Paths(); @@ -450,7 +450,7 @@ bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next * could be found in this branch, thus it has to be searched again next * time we spot it. */ - path[next_id] = found ? NULL : Path::invalid_path; + path[next_id] = found ? nullptr : Path::invalid_path; return found; } @@ -474,11 +474,11 @@ bool MCF1stPass::EliminateCycles() { bool cycles_found = false; uint size = this->job.Size(); - PathVector path(size, NULL); + PathVector path(size, nullptr); for (NodeID node = 0; node < size; ++node) { /* Starting at each node in the graph find all cycles involving this * node. */ - std::fill(path.begin(), path.end(), (Path *)NULL); + std::fill(path.begin(), path.end(), (Path *)nullptr); cycles_found |= this->EliminateCycles(path, node, node); } return cycles_found; @@ -505,7 +505,7 @@ MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job) Edge edge = job[source][dest]; if (edge.UnsatisfiedDemand() > 0) { Path *path = paths[dest]; - assert(path != NULL); + assert(path != nullptr); /* Generally only allow paths that don't exceed the * available capacity. But if no demand has been assigned * yet, make an exception and allow any valid path *once*. */ diff --git a/src/linkgraph/refresh.cpp b/src/linkgraph/refresh.cpp index 501f063520..ef10de6fe4 100644 --- a/src/linkgraph/refresh.cpp +++ b/src/linkgraph/refresh.cpp @@ -28,11 +28,11 @@ /* static */ void LinkRefresher::Run(Vehicle *v, bool allow_merge, bool is_full_loading) { /* If there are no orders we can't predict anything.*/ - if (v->orders.list == NULL) return; + if (v->orders.list == nullptr) return; /* Make sure the first order is a useful order. */ const Order *first = v->orders.list->GetNextDecisionNode(v->GetOrder(v->cur_implicit_order_index), 0); - if (first == NULL) return; + if (first == nullptr) return; HopSet seen_hops; LinkRefresher refresher(v, &seen_hops, allow_merge, is_full_loading); @@ -75,7 +75,7 @@ LinkRefresher::LinkRefresher(Vehicle *vehicle, HopSet *seen_hops, bool allow_mer memset(this->capacities, 0, sizeof(this->capacities)); /* Assemble list of capacities and set last loading stations to 0. */ - for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) { + for (Vehicle *v = this->vehicle; v != nullptr; v = v->Next()) { this->refit_capacities.push_back(RefitDesc(v->cargo_type, v->cargo_cap, v->refit_cap)); if (v->refit_cap > 0) { assert(v->cargo_type < NUM_CARGO); @@ -94,7 +94,7 @@ bool LinkRefresher::HandleRefit(CargoID refit_cargo) this->cargo = refit_cargo; RefitList::iterator refit_it = this->refit_capacities.begin(); bool any_refit = false; - for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) { + for (Vehicle *v = this->vehicle; v != nullptr; v = v->Next()) { const Engine *e = Engine::Get(v->engine_type); if (!HasBit(e->info.refit_mask, this->cargo)) { ++refit_it; @@ -164,10 +164,10 @@ void LinkRefresher::ResetRefit() */ const Order *LinkRefresher::PredictNextOrder(const Order *cur, const Order *next, uint8 flags, uint num_hops) { - /* next is good if it's either NULL (then the caller will stop the + /* next is good if it's either nullptr (then the caller will stop the * evaluation) or if it's not conditional and the caller allows it to be * chosen (by setting USE_NEXT). */ - while (next != NULL && (!HasBit(flags, USE_NEXT) || next->IsType(OT_CONDITIONAL))) { + while (next != nullptr && (!HasBit(flags, USE_NEXT) || next->IsType(OT_CONDITIONAL))) { /* After the first step any further non-conditional order is good, * regardless of previous USE_NEXT settings. The case of cur and next or @@ -177,7 +177,7 @@ const Order *LinkRefresher::PredictNextOrder(const Order *cur, const Order *next if (next->IsType(OT_CONDITIONAL)) { const Order *skip_to = this->vehicle->orders.list->GetNextDecisionNode( this->vehicle->orders.list->GetOrderAt(next->GetConditionSkipToOrder()), num_hops); - if (skip_to != NULL && num_hops < this->vehicle->orders.list->GetNumOrders()) { + if (skip_to != nullptr && num_hops < this->vehicle->orders.list->GetNumOrders()) { /* Make copies of capacity tracking lists. There is potential * for optimization here: If the vehicle never refits we don't * need to copy anything. Also, if we've seen the branched link @@ -204,7 +204,7 @@ void LinkRefresher::RefreshStats(const Order *cur, const Order *next) { StationID next_station = next->GetDestination(); Station *st = Station::GetIfValid(cur->GetDestination()); - if (st != NULL && next_station != INVALID_STATION && next_station != st->index) { + if (st != nullptr && next_station != INVALID_STATION && next_station != st->index) { for (CargoID c = 0; c < NUM_CARGO; c++) { /* Refresh the link and give it a minimum capacity. */ @@ -226,7 +226,7 @@ void LinkRefresher::RefreshStats(const Order *cur, const Order *next) * loading. Don't do that if the vehicle has been waiting for longer than the entire * order list is supposed to take, though. If that is the case the total duration is * probably far off and we'd greatly overestimate the capacity by increasing.*/ - if (this->is_full_loading && this->vehicle->orders.list != NULL && + if (this->is_full_loading && this->vehicle->orders.list != nullptr && st->index == vehicle->last_station_visited && this->vehicle->orders.list->GetTotalDuration() > (Ticks)this->vehicle->current_order_time) { @@ -250,7 +250,7 @@ void LinkRefresher::RefreshStats(const Order *cur, const Order *next) /** * Iterate over orders starting at \a cur and \a next and refresh links * associated with them. \a cur and \a next can be equal. If they're not they - * must be "neigbours" in their order list, which means \a next must be directly + * must be "neighbours" in their order list, which means \a next must be directly * reachable from \a cur without passing any further OT_GOTO_STATION or * OT_IMPLICIT orders in between. * @param cur Current order being evaluated. @@ -260,7 +260,7 @@ void LinkRefresher::RefreshStats(const Order *cur, const Order *next) */ void LinkRefresher::RefreshLinks(const Order *cur, const Order *next, uint8 flags, uint num_hops) { - while (next != NULL) { + while (next != nullptr) { if ((next->IsType(OT_GOTO_DEPOT) || next->IsType(OT_GOTO_STATION)) && next->IsRefit()) { SetBit(flags, WAS_REFIT); @@ -288,7 +288,7 @@ void LinkRefresher::RefreshLinks(const Order *cur, const Order *next, uint8 flag } next = this->PredictNextOrder(cur, next, flags, num_hops); - if (next == NULL) break; + if (next == nullptr) break; Hop hop(cur->index, next->index, this->cargo); if (this->seen_hops->find(hop) != this->seen_hops->end()) { break; diff --git a/src/main_gui.cpp b/src/main_gui.cpp index 5ffe3277b7..7cc327e7ba 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp @@ -53,7 +53,6 @@ static int _rename_what = -1; void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd) { -#ifdef ENABLE_NETWORK if (result.Failed() || !_settings_game.economy.give_money) return; /* Inform the company of the action of one of its clients (controllers). */ @@ -66,25 +65,22 @@ void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2 } else { NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, CLIENT_ID_SERVER, p1); } -#endif /* ENABLE_NETWORK */ } void HandleOnEditText(const char *str) { switch (_rename_what) { -#ifdef ENABLE_NETWORK - case 3: { // Give money, you can only give money in excess of loan - const Company *c = Company::GetIfValid(_local_company); - if (c == NULL) break; - Money money = min(c->money - c->current_loan, (Money)(atoi(str) / _currency->rate)); + case 3: { // Give money, you can only give money in excess of loan + const Company *c = Company::GetIfValid(_local_company); + if (c == nullptr) break; + Money money = min(c->money - c->current_loan, (Money)(atoi(str) / _currency->rate)); - uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0 + uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0 - /* Give 'id' the money, and subtract it from ourself */ - DoCommandP(0, money_c, _rename_id, CMD_GIVE_MONEY | CMD_MSG(STR_ERROR_INSUFFICIENT_FUNDS), CcGiveMoney, str); - break; - } -#endif /* ENABLE_NETWORK */ + /* Give 'id' the money, and subtract it from ourself */ + DoCommandP(0, money_c, _rename_id, CMD_GIVE_MONEY | CMD_MSG(STR_ERROR_INSUFFICIENT_FUNDS), CcGiveMoney, str); + break; + } default: NOT_REACHED(); } @@ -124,14 +120,12 @@ void CcPlaySound_EXPLOSION(const CommandCost &result, TileIndex tile, uint32 p1, if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_12_EXPLOSION, tile); } -#ifdef ENABLE_NETWORK void ShowNetworkGiveMoneyWindow(CompanyID company) { _rename_id = company; _rename_what = 3; - ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, NULL, CS_NUMERAL, QSF_NONE); + ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, nullptr, CS_NUMERAL, QSF_NONE); } -#endif /* ENABLE_NETWORK */ /** @@ -145,7 +139,7 @@ bool DoZoomInOutWindow(ZoomStateChange how, Window *w) { ViewPort *vp; - assert(w != NULL); + assert(w != nullptr); vp = w->viewport; switch (how) { @@ -179,7 +173,7 @@ bool DoZoomInOutWindow(ZoomStateChange how, Window *w) w->viewport->follow_vehicle = INVALID_VEHICLE; break; } - if (vp != NULL) { // the vp can be null when how == ZOOM_NONE + if (vp != nullptr) { // the vp can be null when how == ZOOM_NONE vp->virtual_left = w->viewport->scrollpos_x; vp->virtual_top = w->viewport->scrollpos_y; } @@ -190,7 +184,7 @@ bool DoZoomInOutWindow(ZoomStateChange how, Window *w) void ZoomInOrOutToCursorWindow(bool in, Window *w) { - assert(w != NULL); + assert(w != nullptr); if (_game_mode != GM_MENU) { ViewPort *vp = w->viewport; @@ -267,7 +261,7 @@ struct MainWindow : Window this->refresh.SetInterval(LINKGRAPH_DELAY); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (!this->refresh.Elapsed(delta_ms)) return; @@ -282,7 +276,7 @@ struct MainWindow : Window this->GetWidget(WID_M_VIEWPORT)->SetDirty(this); } - virtual void OnPaint() + void OnPaint() override { this->DrawWidgets(); if (_game_mode == GM_MENU) { @@ -302,7 +296,7 @@ struct MainWindow : Window } } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { if (hotkey == GHK_QUIT) { HandleExitGameRequest(); @@ -412,11 +406,10 @@ struct MainWindow : Window DoCommandP(0, 0, 1, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY)); break; -#ifdef ENABLE_NETWORK case GHK_CHAT: // smart chat; send to team if any, otherwise to all if (_networking) { const NetworkClientInfo *cio = NetworkClientInfo::GetByClientID(_network_own_client_id); - if (cio == NULL) break; + if (cio == nullptr) break; ShowNetworkChatQueryWindow(NetworkClientPreferTeamChat(cio) ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas); } @@ -429,7 +422,7 @@ struct MainWindow : Window case GHK_CHAT_COMPANY: // send text to all team mates if (_networking) { const NetworkClientInfo *cio = NetworkClientInfo::GetByClientID(_network_own_client_id); - if (cio == NULL) break; + if (cio == nullptr) break; ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas); } @@ -440,14 +433,13 @@ struct MainWindow : Window ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, CLIENT_ID_SERVER); } break; -#endif default: return ES_NOT_HANDLED; } return ES_HANDLED; } - virtual void OnScroll(Point delta) + void OnScroll(Point delta) override { this->viewport->scrollpos_x += ScaleByZoom(delta.x, this->viewport->zoom); this->viewport->scrollpos_y += ScaleByZoom(delta.y, this->viewport->zoom); @@ -456,16 +448,16 @@ struct MainWindow : Window this->refresh.SetInterval(LINKGRAPH_DELAY); } - virtual void OnMouseWheel(int wheel) + void OnMouseWheel(int wheel) override { if (_settings_client.gui.scrollwheel_scrolling != 2) { ZoomInOrOutToCursorWindow(wheel < 0, this); } } - virtual void OnResize() + void OnResize() override { - if (this->viewport != NULL) { + if (this->viewport != nullptr) { NWidgetViewport *nvp = this->GetWidget(WID_M_VIEWPORT); nvp->UpdateViewportCoordinates(this); this->refresh.SetInterval(LINKGRAPH_DELAY); @@ -477,7 +469,7 @@ struct MainWindow : Window * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* Forward the message to the appropriate toolbar (ingame or scenario editor) */ @@ -537,18 +529,16 @@ static Hotkey global_hotkeys[] = { Hotkey('X' | WKC_CTRL, "transparency_toolbar", GHK_TRANSPARENCY_TOOLBAR), Hotkey('X', "toggle_transparency", GHK_TRANSPARANCY), Hotkey(WKC_NONE, "borrow_all", GHK_BORROW_ALL), -#ifdef ENABLE_NETWORK Hotkey(_ghk_chat_keys, "chat", GHK_CHAT), Hotkey(_ghk_chat_all_keys, "chat_all", GHK_CHAT_ALL), Hotkey(_ghk_chat_company_keys, "chat_company", GHK_CHAT_COMPANY), Hotkey(_ghk_chat_server_keys, "chat_server", GHK_CHAT_SERVER), -#endif HOTKEY_LIST_END }; HotkeyList MainWindow::hotkeys("global", global_hotkeys); static WindowDesc _main_window_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_MAIN_WINDOW, WC_NONE, 0, _nested_main_window_widgets, lengthof(_nested_main_window_widgets), diff --git a/src/map.cpp b/src/map.cpp index 85590c3e88..53e26ed73e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -29,8 +29,8 @@ uint _map_size_y; ///< Size of the map along the Y uint _map_size; ///< The number of tiles on the map uint _map_tile_mask; ///< _map_size - 1 (to mask the mapsize) -Tile *_m = NULL; ///< Tiles of the map -TileExtended *_me = NULL; ///< Extended Tiles of the map +Tile *_m = nullptr; ///< Tiles of the map +TileExtended *_me = nullptr; ///< Extended Tiles of the map /** @@ -254,12 +254,12 @@ uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir) * @param proc: callback testing function pointer. * @param user_data to be passed to the callback function. Depends on the implementation * @return result of the search - * @pre proc != NULL + * @pre proc != nullptr * @pre size > 0 */ bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data) { - assert(proc != NULL); + assert(proc != nullptr); assert(size > 0); if (size % 2 == 1) { @@ -292,12 +292,12 @@ bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, v * @param proc callback testing function pointer. * @param user_data to be passed to the callback function. Depends on the implementation * @return result of the search - * @pre proc != NULL + * @pre proc != nullptr * @pre radius > 0 */ bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOnSearchProc proc, void *user_data) { - assert(proc != NULL); + assert(proc != nullptr); assert(radius > 0); uint x = TileX(*tile) + w + 1; diff --git a/src/misc.cpp b/src/misc.cpp index f26d8e4909..24bd689b1a 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -28,6 +28,9 @@ #include "core/pool_type.hpp" #include "game/game.hpp" #include "linkgraph/linkgraphschedule.h" +#include "station_kdtree.h" +#include "town_kdtree.h" +#include "viewport_kdtree.h" #include "safeguards.h" @@ -44,6 +47,7 @@ void InitializeAirportGui(); void InitializeDockGui(); void InitializeGraphGui(); void InitializeObjectGui(); +void InitializeTownGui(); void InitializeIndustries(); void InitializeObjects(); void InitializeTrees(); @@ -75,6 +79,10 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin LinkGraphSchedule::Clear(); PoolBase::Clean(PT_NORMAL); + RebuildStationKdtree(); + RebuildTownKdtree(); + RebuildViewportKdtree(); + ResetPersistentNewGRFData(); InitializeSound(); @@ -90,6 +98,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin InitializeDockGui(); InitializeGraphGui(); InitializeObjectGui(); + InitializeTownGui(); InitializeAIGui(); InitializeTrees(); InitializeIndustries(); @@ -104,9 +113,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin InitializeCheats(); InitTextEffects(); -#ifdef ENABLE_NETWORK NetworkInitChatMessage(); -#endif /* ENABLE_NETWORK */ InitializeAnimatedTiles(); InitializeEconomy(); diff --git a/src/misc/binaryheap.hpp b/src/misc/binaryheap.hpp index 5bd2b794ac..11e419711a 100644 --- a/src/misc/binaryheap.hpp +++ b/src/misc/binaryheap.hpp @@ -72,7 +72,7 @@ public: { this->Clear(); free(this->data); - this->data = NULL; + this->data = nullptr; } protected: diff --git a/src/misc/blob.hpp b/src/misc/blob.hpp index b1a5b667df..fafeb80780 100644 --- a/src/misc/blob.hpp +++ b/src/misc/blob.hpp @@ -86,9 +86,9 @@ public: /** move constructor - take ownership of blob data */ inline ByteBlob(BlobHeader * const & src) { - assert(src != NULL); + assert(src != nullptr); header = src; - *const_cast(&src) = NULL; + *const_cast(&src) = nullptr; } /** destructor */ @@ -154,13 +154,13 @@ protected: header = &src[1]; } - /** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */ + /** blob header accessor - use it rather than using the pointer arithmetic directly - non-const version */ inline BlobHeader& Hdr() { return *(header - 1); } - /** blob header accessor - use it rather than using the pointer arithmetics directly - const version */ + /** blob header accessor - use it rather than using the pointer arithmetic directly - const version */ inline const BlobHeader& Hdr() const { return *(header - 1); @@ -221,7 +221,7 @@ public: /** append new bytes at the end of existing data bytes - reallocates if necessary */ inline void AppendRaw(const void *p, size_t num_bytes) { - assert(p != NULL); + assert(p != nullptr); if (num_bytes > 0) { memcpy(Append(num_bytes), p, num_bytes); } @@ -317,8 +317,8 @@ public: OnTransfer(const OnTransfer& src) : header(src.header) { - assert(src.header != NULL); - *const_cast(&src.header) = NULL; + assert(src.header != nullptr); + *const_cast(&src.header) = nullptr; } OnTransfer(CBlobT& src) : header(src.header) @@ -328,7 +328,7 @@ public: ~OnTransfer() { - assert(header == NULL); + assert(header == nullptr); } }; diff --git a/src/misc/countedptr.hpp b/src/misc/countedptr.hpp index e7b28a6267..1364197dc1 100644 --- a/src/misc/countedptr.hpp +++ b/src/misc/countedptr.hpp @@ -34,8 +34,8 @@ protected: Tcls *m_pT; public: - /** default (NULL) construct or construct from a raw pointer */ - inline CCountedPtr(Tcls *pObj = NULL) : m_pT(pObj) + /** default (nullptr) construct or construct from a raw pointer */ + inline CCountedPtr(Tcls *pObj = nullptr) : m_pT(pObj) { AddRef(); } @@ -53,19 +53,19 @@ public: } protected: - /** add one ref to the underlaying object */ + /** add one ref to the underlying object */ inline void AddRef() { - if (m_pT != NULL) m_pT->AddRef(); + if (m_pT != nullptr) m_pT->AddRef(); } public: /** release smart pointer (and decrement ref count) if not null */ inline void Release() { - if (m_pT != NULL) { + if (m_pT != nullptr) { Tcls *pT = m_pT; - m_pT = NULL; + m_pT = nullptr; pT->Release(); } } @@ -73,21 +73,21 @@ public: /** dereference of smart pointer - const way */ inline const Tcls *operator->() const { - assert(m_pT != NULL); + assert(m_pT != nullptr); return m_pT; } /** dereference of smart pointer - non const way */ inline Tcls *operator->() { - assert(m_pT != NULL); + assert(m_pT != nullptr); return m_pT; } /** raw pointer casting operator - const way */ inline operator const Tcls*() const { - assert(m_pT == NULL); + assert(m_pT == nullptr); return m_pT; } @@ -100,7 +100,7 @@ public: /** operator & to support output arguments */ inline Tcls** operator&() { - assert(m_pT == NULL); + assert(m_pT == nullptr); return &m_pT; } @@ -121,16 +121,16 @@ public: /** assignment operator helper */ inline void Assign(Tcls *pT); - /** one way how to test for NULL value */ + /** one way how to test for nullptr value */ inline bool IsNull() const { - return m_pT == NULL; + return m_pT == nullptr; } - /** another way how to test for NULL value */ + /** another way how to test for nullptr value */ //inline bool operator == (const CCountedPtr &sp) const {return m_pT == sp.m_pT;} - /** yet another way how to test for NULL value */ + /** yet another way how to test for nullptr value */ //inline bool operator != (const CCountedPtr &sp) const {return m_pT != sp.m_pT;} /** assign pointer w/o incrementing ref count */ @@ -144,7 +144,7 @@ public: inline Tcls *Detach() { Tcls *pT = m_pT; - m_pT = NULL; + m_pT = nullptr; return pT; } }; @@ -154,10 +154,10 @@ inline void CCountedPtr::Assign(Tcls *pT) { /* if they are the same, we do nothing */ if (pT != m_pT) { - if (pT != NULL) pT->AddRef(); // AddRef new pointer if any + if (pT != nullptr) pT->AddRef(); // AddRef new pointer if any Tcls *pTold = m_pT; // save original ptr m_pT = pT; // update m_pT to new value - if (pTold != NULL) pTold->Release(); // release old ptr if any + if (pTold != nullptr) pTold->Release(); // release old ptr if any } } diff --git a/src/misc/dbg_helpers.h b/src/misc/dbg_helpers.h index acc1437d09..2e2a1a7e9a 100644 --- a/src/misc/dbg_helpers.h +++ b/src/misc/dbg_helpers.h @@ -155,8 +155,8 @@ struct DumpTarget { { static size_t type_id = ++LastTypeId(); - if (s == NULL) { - /* No need to dump NULL struct. */ + if (s == nullptr) { + /* No need to dump nullptr struct. */ WriteLine("%s = ", name); return; } diff --git a/src/misc/fixedsizearray.hpp b/src/misc/fixedsizearray.hpp index c694ff7a17..ec1d58bf3e 100644 --- a/src/misc/fixedsizearray.hpp +++ b/src/misc/fixedsizearray.hpp @@ -94,7 +94,7 @@ public: Clear(); /* free the memory block occupied by items */ free(((byte*)data) - HeaderSize); - data = NULL; + data = nullptr; } /** Clear (destroy) all items */ diff --git a/src/misc/getoptdata.cpp b/src/misc/getoptdata.cpp index 7859594dd9..d80898f083 100644 --- a/src/misc/getoptdata.cpp +++ b/src/misc/getoptdata.cpp @@ -26,7 +26,7 @@ int GetOptData::GetOpt() const OptionData *odata; char *s = this->cont; - if (s == NULL) { + if (s == nullptr) { if (this->numleft == 0) return -1; // No arguments left -> finished. s = this->argv[0]; @@ -37,8 +37,8 @@ int GetOptData::GetOpt() /* Is it a long option? */ for (odata = this->options; odata->flags != ODF_END; odata++) { - if (odata->longname != NULL && !strcmp(odata->longname, s)) { // Long options always use the entire argument. - this->cont = NULL; + if (odata->longname != nullptr && !strcmp(odata->longname, s)) { // Long options always use the entire argument. + this->cont = nullptr; goto set_optval; } } @@ -49,19 +49,19 @@ int GetOptData::GetOpt() /* Is it a short option? */ for (odata = this->options; odata->flags != ODF_END; odata++) { if (odata->shortname != '\0' && *s == odata->shortname) { - this->cont = (s[1] != '\0') ? s + 1 : NULL; + this->cont = (s[1] != '\0') ? s + 1 : nullptr; set_optval: // Handle option value of *odata . - this->opt = NULL; + this->opt = nullptr; switch (odata->flags) { case ODF_NO_VALUE: return odata->id; case ODF_HAS_VALUE: case ODF_OPTIONAL_VALUE: - if (this->cont != NULL) { // Remainder of the argument is the option value. + if (this->cont != nullptr) { // Remainder of the argument is the option value. this->opt = this->cont; - this->cont = NULL; + this->cont = nullptr; return odata->id; } /* No more arguments, either return an error or a value-less option. */ diff --git a/src/misc/getoptdata.h b/src/misc/getoptdata.h index 4ce916aa1e..4777c85b5a 100644 --- a/src/misc/getoptdata.h +++ b/src/misc/getoptdata.h @@ -25,12 +25,12 @@ struct OptionData { byte id; ///< Unique identification of this option data, often the same as #shortname. char shortname; ///< Short option letter if available, else use \c '\0'. uint16 flags; ///< Option data flags. @see OptionDataFlags - const char *longname; ///< Long option name including '-'/'--' prefix, use \c NULL if not available. + const char *longname; ///< Long option name including '-'/'--' prefix, use \c nullptr if not available. }; /** Data storage for parsing command line options. */ struct GetOptData { - char *opt; ///< Option value, if available (else \c NULL). + char *opt; ///< Option value, if available (else \c nullptr). int numleft; ///< Number of arguments left in #argv. char **argv; ///< Remaining command line arguments. const OptionData *options; ///< Command line option descriptions. @@ -43,11 +43,11 @@ struct GetOptData { * @param options Command line option descriptions. */ GetOptData(int argc, char **argv, const OptionData *options) : - opt(NULL), + opt(nullptr), numleft(argc), argv(argv), options(options), - cont(NULL) + cont(nullptr) { } @@ -58,7 +58,7 @@ struct GetOptData { * General macro for creating an option. * @param id Identification of the option. * @param shortname Short option name. Use \c '\0' if not used. - * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. + * @param longname Long option name including leading '-' or '--'. Use \c nullptr if not used. * @param flags Flags of the option. */ #define GETOPT_GENERAL(id, shortname, longname, flags) { id, shortname, flags, longname } @@ -66,21 +66,21 @@ struct GetOptData { /** * Short option without value. * @param shortname Short option name. Use \c '\0' if not used. - * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. + * @param longname Long option name including leading '-' or '--'. Use \c nullptr if not used. */ #define GETOPT_NOVAL(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_NO_VALUE) /** * Short option with value. * @param shortname Short option name. Use \c '\0' if not used. - * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. + * @param longname Long option name including leading '-' or '--'. Use \c nullptr if not used. */ #define GETOPT_VALUE(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_HAS_VALUE) /** * Short option with optional value. * @param shortname Short option name. Use \c '\0' if not used. - * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. + * @param longname Long option name including leading '-' or '--'. Use \c nullptr if not used. * @note Options with optional values are hopelessly ambiguous, eg "-opt -value", avoid them. */ #define GETOPT_OPTVAL(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_OPTIONAL_VALUE) @@ -90,23 +90,23 @@ struct GetOptData { * Short option without value. * @param shortname Short option name. Use \c '\0' if not used. */ -#define GETOPT_SHORT_NOVAL(shortname) GETOPT_NOVAL(shortname, NULL) +#define GETOPT_SHORT_NOVAL(shortname) GETOPT_NOVAL(shortname, nullptr) /** * Short option with value. * @param shortname Short option name. Use \c '\0' if not used. */ -#define GETOPT_SHORT_VALUE(shortname) GETOPT_VALUE(shortname, NULL) +#define GETOPT_SHORT_VALUE(shortname) GETOPT_VALUE(shortname, nullptr) /** * Short option with optional value. * @param shortname Short option name. Use \c '\0' if not used. * @note Options with optional values are hopelessly ambiguous, eg "-opt -value", avoid them. */ -#define GETOPT_SHORT_OPTVAL(shortname) GETOPT_OPTVAL(shortname, NULL) +#define GETOPT_SHORT_OPTVAL(shortname) GETOPT_OPTVAL(shortname, nullptr) /** Option terminator. */ -#define GETOPT_END() { '\0', '\0', ODF_END, NULL} +#define GETOPT_END() { '\0', '\0', ODF_END, nullptr} #endif /* GETOPTDATA_H */ diff --git a/src/misc/hashtable.hpp b/src/misc/hashtable.hpp index 1078f1861d..49f321bff3 100644 --- a/src/misc/hashtable.hpp +++ b/src/misc/hashtable.hpp @@ -21,42 +21,42 @@ struct CHashTableSlotT Titem_ *m_pFirst; - inline CHashTableSlotT() : m_pFirst(NULL) {} + inline CHashTableSlotT() : m_pFirst(nullptr) {} /** hash table slot helper - clears the slot by simple forgetting its items */ inline void Clear() { - m_pFirst = NULL; + m_pFirst = nullptr; } /** hash table slot helper - linear search for item with given key through the given blob - const version */ inline const Titem_ *Find(const Key &key) const { - for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { + for (const Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) { if (pItem->GetKey() == key) { /* we have found the item, return it */ return pItem; } } - return NULL; + return nullptr; } /** hash table slot helper - linear search for item with given key through the given blob - non-const version */ inline Titem_ *Find(const Key &key) { - for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { + for (Titem_ *pItem = m_pFirst; pItem != nullptr; pItem = pItem->GetHashNext()) { if (pItem->GetKey() == key) { /* we have found the item, return it */ return pItem; } } - return NULL; + return nullptr; } /** hash table slot helper - add new item to the slot */ inline void Attach(Titem_ &new_item) { - assert(new_item.GetHashNext() == NULL); + assert(new_item.GetHashNext() == nullptr); new_item.SetHashNext(m_pFirst); m_pFirst = &new_item; } @@ -66,12 +66,12 @@ struct CHashTableSlotT { if (m_pFirst == &item_to_remove) { m_pFirst = item_to_remove.GetHashNext(); - item_to_remove.SetHashNext(NULL); + item_to_remove.SetHashNext(nullptr); return true; } Titem_ *pItem = m_pFirst; for (;;) { - if (pItem == NULL) { + if (pItem == nullptr) { return false; } Titem_ *pNextItem = pItem->GetHashNext(); @@ -79,7 +79,7 @@ struct CHashTableSlotT pItem = pNextItem; } pItem->SetHashNext(item_to_remove.GetHashNext()); - item_to_remove.SetHashNext(NULL); + item_to_remove.SetHashNext(nullptr); return true; } @@ -87,27 +87,27 @@ struct CHashTableSlotT inline Titem_ *Detach(const Key &key) { /* do we have any items? */ - if (m_pFirst == NULL) { - return NULL; + if (m_pFirst == nullptr) { + return nullptr; } /* is it our first item? */ if (m_pFirst->GetKey() == key) { Titem_ &ret_item = *m_pFirst; m_pFirst = m_pFirst->GetHashNext(); - ret_item.SetHashNext(NULL); + ret_item.SetHashNext(nullptr); return &ret_item; } /* find it in the following items */ Titem_ *pPrev = m_pFirst; - for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) { + for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != nullptr; pPrev = pItem, pItem = pItem->GetHashNext()) { if (pItem->GetKey() == key) { /* we have found the item, unlink and return it */ pPrev->SetHashNext(pItem->GetHashNext()); - pItem->SetHashNext(NULL); + pItem->SetHashNext(nullptr); return pItem; } } - return NULL; + return nullptr; } }; @@ -211,7 +211,7 @@ public: int hash = CalcHash(key); Slot &slot = m_slots[hash]; Titem_ *item = slot.Detach(key); - if (item != NULL) { + if (item != nullptr) { m_num_items--; } return item; @@ -221,7 +221,7 @@ public: Titem_& Pop(const Tkey &key) { Titem_ *item = TryPop(key); - assert(item != NULL); + assert(item != nullptr); return *item; } @@ -250,7 +250,7 @@ public: { int hash = CalcHash(new_item); Slot &slot = m_slots[hash]; - assert(slot.Find(new_item.GetKey()) == NULL); + assert(slot.Find(new_item.GetKey()) == nullptr); slot.Attach(new_item); m_num_items++; } diff --git a/src/misc/str.hpp b/src/misc/str.hpp index 1d9802288c..42e4631581 100644 --- a/src/misc/str.hpp +++ b/src/misc/str.hpp @@ -7,7 +7,7 @@ * See the GNU 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 str.hpp String formating? */ +/** @file str.hpp String formatting? */ #ifndef STR_HPP #define STR_HPP @@ -91,7 +91,7 @@ struct CStrA : public CBlobT return strcmp(base::Data(), other.Data()) < 0; } - /** Add formated string (like vsprintf) at the end of existing contents. */ + /** Add formatted string (like vsprintf) at the end of existing contents. */ int AddFormatL(const char *format, va_list args) { size_t addSize = max(strlen(format), 16); @@ -126,7 +126,7 @@ struct CStrA : public CBlobT return ret; } - /** Add formated string (like sprintf) at the end of existing contents. */ + /** Add formatted string (like sprintf) at the end of existing contents. */ int CDECL WARN_FORMAT(2, 3) AddFormat(const char *format, ...) { va_list args; @@ -136,7 +136,7 @@ struct CStrA : public CBlobT return ret; } - /** Assign formated string (like sprintf). */ + /** Assign formatted string (like sprintf). */ int CDECL WARN_FORMAT(2, 3) Format(const char *format, ...) { base::Free(); diff --git a/src/misc_cmd.cpp b/src/misc_cmd.cpp index e7da13c7aa..e00ad9d9c3 100644 --- a/src/misc_cmd.cpp +++ b/src/misc_cmd.cpp @@ -154,12 +154,10 @@ CommandCost CmdPause(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, case PM_PAUSED_GAME_SCRIPT: break; -#ifdef ENABLE_NETWORK case PM_PAUSED_JOIN: case PM_PAUSED_ACTIVE_CLIENTS: if (!_networking) return CMD_ERROR; break; -#endif /* ENABLE_NETWORK */ default: return CMD_ERROR; } @@ -168,23 +166,19 @@ CommandCost CmdPause(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, ShowQuery( STR_NEWGRF_UNPAUSE_WARNING_TITLE, STR_NEWGRF_UNPAUSE_WARNING, - NULL, + nullptr, AskUnsafeUnpauseCallback ); } else { -#ifdef ENABLE_NETWORK PauseMode prev_mode = _pause_mode; -#endif /* ENABLE_NETWORK */ if (p2 == 0) { - _pause_mode = _pause_mode & ~p1; + _pause_mode = static_cast(_pause_mode & (byte)~p1); } else { - _pause_mode = _pause_mode | p1; + _pause_mode = static_cast(_pause_mode | (byte)p1); } -#ifdef ENABLE_NETWORK NetworkHandlePauseChange(prev_mode, (PauseMode)p1); -#endif /* ENABLE_NETWORK */ } SetWindowDirty(WC_STATUS_BAR, 0); @@ -229,12 +223,12 @@ CommandCost CmdChangeBankBalance(TileIndex tile, DoCommandFlag flags, uint32 p1, if (flags & DC_EXEC) { /* Change company bank balance of company. */ - Backup cur_company(_current_company, company, FILE_LINE); + Backup cur_company(_current_company, company, FILE_LINE); SubtractMoneyFromCompany(CommandCost(expenses_type, -delta)); cur_company.Restore(); } - /* This command doesn't cost anyting for deity. */ + /* This command doesn't cost anything for deity. */ CommandCost zero_cost(expenses_type, 0); return zero_cost; } @@ -265,7 +259,7 @@ CommandCost CmdGiveMoney(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (flags & DC_EXEC) { /* Add money to company */ - Backup cur_company(_current_company, dest_company, FILE_LINE); + Backup cur_company(_current_company, dest_company, FILE_LINE); SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, -amount.GetCost())); cur_company.Restore(); } diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index b2f7c50cc7..473a92ee5d 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -88,7 +88,7 @@ public: return pt; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_LI_BACKGROUND) return; @@ -112,7 +112,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_LI_BACKGROUND) return; @@ -160,7 +160,7 @@ public: #undef LANDINFOD_LEVEL } - virtual void OnInit() + void OnInit() override { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); @@ -189,13 +189,16 @@ public: td.airport_tile_name = STR_NULL; td.railtype = STR_NULL; td.rail_speed = 0; + td.roadtype = STR_NULL; td.road_speed = 0; - td.population = 0; + td.tramtype = STR_NULL; + td.tram_speed = 0; + td.population = 0; - td.grf = NULL; + td.grf = nullptr; CargoArray acceptance; - AddAcceptedCargo(tile, acceptance, NULL); + AddAcceptedCargo(tile, acceptance, nullptr); GetTileDesc(tile, &td); uint line_nr = 0; @@ -218,7 +221,7 @@ public: /* Cost to clear/revenue when cleared */ StringID str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A; Company *c = Company::GetIfValid(_local_company); - if (c != NULL) { + if (c != nullptr) { assert(_current_company == _local_company); CommandCost costclear = DoCommand(tile, 0, 0, DC_QUERY_COST, CMD_LANDSCAPE_CLEAR); if (costclear.Succeeded()) { @@ -247,7 +250,7 @@ public: /* Local authority */ SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); - if (t != NULL) { + if (t != nullptr) { SetDParam(0, STR_TOWN_NAME); SetDParam(1, t->index); } @@ -310,6 +313,13 @@ public: line_nr++; } + /* Road type name */ + if (td.roadtype != STR_NULL) { + SetDParam(0, td.roadtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + /* Road speed limit */ if (td.road_speed != 0) { SetDParam(0, td.road_speed); @@ -317,8 +327,22 @@ public: line_nr++; } + /* Tram type name */ + if (td.tramtype != STR_NULL) { + SetDParam(0, td.tramtype); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_TYPE, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + + /* Tram speed limit */ + if (td.tram_speed != 0) { + SetDParam(0, td.tram_speed); + GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); + line_nr++; + } + /* NewGRF name */ - if (td.grf != NULL) { + if (td.grf != nullptr) { SetDParamStr(0, td.grf); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_NEWGRF_NAME, lastof(this->landinfo_data[line_nr])); line_nr++; @@ -359,12 +383,12 @@ public: if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0'; } - virtual bool IsNewGRFInspectable() const + bool IsNewGRFInspectable() const override { return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), this->tile); } - virtual void ShowNewGRFInspectWindow() const + void ShowNewGRFInspectWindow() const override { ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile); } @@ -374,7 +398,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; switch (data) { @@ -431,7 +455,7 @@ static const NWidgetPart _nested_about_widgets[] = { }; static WindowDesc _about_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, _nested_about_widgets, lengthof(_nested_about_widgets) @@ -448,6 +472,7 @@ static const char * const _credits[] = { " Ulf Hermann (fonsinchen) - Cargo Distribution (since 1.3)", " Christoph Elsenhans (frosch) - General coding (since 0.6)", " Lo\xC3\xAF""c Guilloux (glx) - General / Windows Expert (since 0.4.5)", + " Charles Pigott (LordAro) - General / Correctness police (since 1.9)", " 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)", @@ -518,12 +543,12 @@ struct AboutWindow : public Window { this->timer.SetInterval(TIMER_INTERVAL); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_A_WEBSITE) SetDParamStr(0, "Website: http://www.openttd.org"); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_A_SCROLLING_TEXT) return; @@ -539,7 +564,7 @@ struct AboutWindow : public Window { *size = maxdim(*size, d); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_A_SCROLLING_TEXT) return; @@ -554,7 +579,7 @@ struct AboutWindow : public Window { } } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { uint count = this->timer.CountElapsed(delta_ms); if (count > 0) { @@ -687,7 +712,7 @@ static const NWidgetPart _nested_tooltips_widgets[] = { }; static WindowDesc _tool_tips_desc( - WDP_MANUAL, NULL, 0, 0, // Coordinates and sizes are not used, + WDP_MANUAL, nullptr, 0, 0, // Coordinates and sizes are not used, WC_TOOLTIPS, WC_NONE, WDF_NO_FOCUS, _nested_tooltips_widgets, lengthof(_nested_tooltips_widgets) @@ -716,7 +741,7 @@ struct TooltipsWindow : public Window CLRBITS(this->flags, WF_WHITE_BORDER); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. * Add a fixed distance 2 so the tooltip floats free from both bars. @@ -736,7 +761,7 @@ struct TooltipsWindow : public Window return pt; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { /* There is only one widget. */ for (uint i = 0; i != this->paramcount; i++) SetDParam(i, this->params[i]); @@ -749,7 +774,7 @@ struct TooltipsWindow : public Window size->height += 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { /* There is only one widget. */ GfxFillRect(r.left, r.top, r.right, r.bottom, PC_BLACK); @@ -761,7 +786,7 @@ struct TooltipsWindow : public Window DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->string_id, TC_FROMSTRING, SA_CENTER); } - virtual void OnMouseLoop() + void OnMouseLoop() override { /* Always close tooltips when the cursor is not in our window. */ if (!_cursor.in_window) { @@ -929,7 +954,7 @@ Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, co * @param w Window the edit box is in. * @param wid Widget index. * @param pt Position to test. - * @return Pointer to the character at the position or NULL if no character is at the position. + * @return Pointer to the character at the position or nullptr if no character is at the position. */ const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const { @@ -947,7 +972,7 @@ const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point int top = wi->pos_y + WD_FRAMERECT_TOP; int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; - if (!IsInsideMM(pt.y, top, bottom)) return NULL; + if (!IsInsideMM(pt.y, top, bottom)) return nullptr; /* Clamp caret position to be inside our current width. */ const Textbuf *tb = &this->text; @@ -990,6 +1015,7 @@ struct QueryStringWindow : public Window { QueryString editbox; ///< Editbox. QueryStringFlags flags; ///< Flags controlling behaviour of the window. + Dimension warning_size; ///< How much space to use for the warning text QueryStringWindow(StringID str, StringID caption, uint max_bytes, uint max_chars, WindowDesc *desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) : Window(desc), editbox(max_bytes, max_chars) @@ -1016,13 +1042,28 @@ struct QueryStringWindow : public Window this->flags = flags; this->InitNested(WN_QUERY_STRING); + this->UpdateWarningStringSize(); this->parent = parent; this->SetFocusedWidget(WID_QS_TEXT); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWarningStringSize() + { + if (this->flags & QSF_PASSWORD) { + assert(this->nested_root->smallest_x > 0); + this->warning_size.width = this->nested_root->current_x - (WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT); + this->warning_size.height = GetStringHeight(STR_WARNING_PASSWORD_SECURITY, this->warning_size.width); + this->warning_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + } else { + this->warning_size = Dimension{ 0, 0 }; + } + + this->ReInit(); + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_QS_DEFAULT && (this->flags & QSF_ENABLE_DEFAULT) == 0) { /* We don't want this widget to show! */ @@ -1030,19 +1071,34 @@ struct QueryStringWindow : public Window resize->width = 0; size->width = 0; } + + if (widget == WID_QS_WARNING) { + *size = this->warning_size; + } } - virtual void SetStringParameters(int widget) const + void DrawWidget(const Rect &r, int widget) const override + { + if (widget != WID_QS_WARNING) return; + + if (this->flags & QSF_PASSWORD) { + DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT - WD_FRAMERECT_RIGHT, + r.top + WD_FRAMERECT_TOP + WD_FRAMETEXT_TOP, r.bottom - WD_FRAMERECT_BOTTOM - WD_FRAMETEXT_BOTTOM, + STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER); + } + } + + void SetStringParameters(int widget) const override { if (widget == WID_QS_CAPTION) SetDParam(0, this->editbox.caption); } void OnOk() { - if (this->editbox.orig == NULL || strcmp(this->editbox.text.buf, this->editbox.orig) != 0) { - /* If the parent is NULL, the editbox is handled by general function + if (this->editbox.orig == nullptr || strcmp(this->editbox.text.buf, this->editbox.orig) != 0) { + /* If the parent is nullptr, the editbox is handled by general function * HandleOnEditText */ - if (this->parent != NULL) { + if (this->parent != nullptr) { this->parent->OnQueryTextFinished(this->editbox.text.buf); } else { HandleOnEditText(this->editbox.text.buf); @@ -1051,7 +1107,7 @@ struct QueryStringWindow : public Window } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_QS_DEFAULT: @@ -1070,10 +1126,10 @@ struct QueryStringWindow : public Window ~QueryStringWindow() { - if (!this->editbox.handled && this->parent != NULL) { + if (!this->editbox.handled && this->parent != nullptr) { Window *parent = this->parent; - this->parent = NULL; // so parent doesn't try to delete us again - parent->OnQueryTextFinished(NULL); + this->parent = nullptr; // so parent doesn't try to delete us again + parent->OnQueryTextFinished(nullptr); } } }; @@ -1086,6 +1142,7 @@ static const NWidgetPart _nested_query_string_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_QS_TEXT), SetMinimalSize(256, 12), SetFill(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_QS_WARNING), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_DEFAULT), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_DEFAULT, STR_NULL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_CANCEL), SetMinimalSize(86, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), @@ -1106,7 +1163,7 @@ static WindowDesc _query_string_desc( * @param caption StringID of text shown in caption of querywindow * @param maxsize maximum size in bytes or characters (including terminating '\0') depending on flags * @param parent pointer to a Window that will handle the events (ok/cancel) of this - * window. If NULL, results are handled by global function HandleOnEditText + * window. If nullptr, results are handled by global function HandleOnEditText * @param afilter filters out unwanted character input * @param flags various flags, @see QueryStringFlags */ @@ -1143,10 +1200,10 @@ struct QueryWindow : public Window { ~QueryWindow() { - if (this->proc != NULL) this->proc(this->parent, false); + if (this->proc != nullptr) this->proc(this->parent, false); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_Q_CAPTION: @@ -1160,7 +1217,7 @@ struct QueryWindow : public Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_Q_TEXT) return; @@ -1170,7 +1227,7 @@ struct QueryWindow : public Window { *size = d; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_Q_TEXT) return; @@ -1178,7 +1235,7 @@ struct QueryWindow : public Window { this->message, TC_FROMSTRING, SA_CENTER); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_Q_YES: { @@ -1187,11 +1244,11 @@ struct QueryWindow : public Window { QueryCallbackProc *proc = this->proc; Window *parent = this->parent; /* Prevent the destructor calling the callback function */ - this->proc = NULL; + this->proc = nullptr; delete this; - if (proc != NULL) { + if (proc != nullptr) { proc(parent, true); - proc = NULL; + proc = nullptr; } break; } @@ -1201,15 +1258,15 @@ struct QueryWindow : public Window { } } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { /* ESC closes the window, Enter confirms the action */ switch (keycode) { case WKC_RETURN: case WKC_NUM_ENTER: - if (this->proc != NULL) { + if (this->proc != nullptr) { this->proc(this->parent, true); - this->proc = NULL; + this->proc = nullptr; } FALLTHROUGH; @@ -1236,7 +1293,7 @@ static const NWidgetPart _nested_query_widgets[] = { }; static WindowDesc _query_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WDF_MODAL, _nested_query_widgets, lengthof(_nested_query_widgets) @@ -1247,13 +1304,13 @@ static WindowDesc _query_desc( * The window is aligned to the centre of its parent. * @param caption string shown as window caption * @param message string that will be shown for the window - * @param parent pointer to parent window, if this pointer is NULL the parent becomes + * @param parent pointer to parent window, if this pointer is nullptr the parent becomes * the main window WC_MAIN_WINDOW * @param callback callback function pointer to set in the window descriptor */ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) { - if (parent == NULL) parent = FindWindowById(WC_MAIN_WINDOW, 0); + if (parent == nullptr) parent = FindWindowById(WC_MAIN_WINDOW, 0); const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { diff --git a/src/mixer.cpp b/src/mixer.cpp index 6014f6082e..5f3eeb42ad 100644 --- a/src/mixer.cpp +++ b/src/mixer.cpp @@ -39,7 +39,7 @@ struct MixerChannel { static MixerChannel _channels[8]; static uint32 _play_rate = 11025; static uint32 _max_size = UINT_MAX; -static MxStreamCallback _music_stream = NULL; +static MxStreamCallback _music_stream = nullptr; /** * The theoretical maximum volume for a single sound sample. Multiple sound @@ -175,11 +175,11 @@ MixerChannel *MxAllocateChannel() for (mc = _channels; mc != endof(_channels); mc++) { if (!mc->active) { free(mc->memory); - mc->memory = NULL; + mc->memory = nullptr; return mc; } } - return NULL; + return nullptr; } void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit) @@ -238,6 +238,6 @@ bool MxInitialize(uint rate) { _play_rate = rate; _max_size = UINT_MAX / _play_rate; - _music_stream = NULL; /* rate may have changed, any music source is now invalid */ + _music_stream = nullptr; /* rate may have changed, any music source is now invalid */ return true; } diff --git a/src/music.cpp b/src/music.cpp index 3d0e40bf9b..43a9508fad 100644 --- a/src/music.cpp +++ b/src/music.cpp @@ -25,11 +25,11 @@ * @param filename Name of CAT file to read from * @param entrynum Index of entry whose name to read * @return Pointer to string, caller is responsible for freeing memory, - * NULL if entrynum does not exist. + * nullptr if entrynum does not exist. */ char *GetMusicCatEntryName(const char *filename, size_t entrynum) { - if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL; + if (!FioCheckFileExists(filename, BASESET_DIR)) return nullptr; FioOpenFile(CONFIG_SLOT, filename, BASESET_DIR); uint32 ofs = FioReadDword(); @@ -43,7 +43,7 @@ char *GetMusicCatEntryName(const char *filename, size_t entrynum) name[namelen] = '\0'; return name; } - return NULL; + return nullptr; } /** @@ -52,12 +52,12 @@ char *GetMusicCatEntryName(const char *filename, size_t entrynum) * @param entrynum Index of entry to read * @param[out] entrylen Receives length of data read * @return Pointer to buffer with data read, caller is responsible for freeind memory, - * NULL if entrynum does not exist. + * nullptr if entrynum does not exist. */ byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen) { entrylen = 0; - if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL; + if (!FioCheckFileExists(filename, BASESET_DIR)) return nullptr; FioOpenFile(CONFIG_SLOT, filename, BASESET_DIR); uint32 ofs = FioReadDword(); @@ -72,7 +72,7 @@ byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entryl FioReadBlock(data, entrylen); return data; } - return NULL; + return nullptr; } INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia, MusicSet) @@ -99,13 +99,13 @@ template template /* static */ bool BaseMedia::DetermineBestSet() { - if (BaseMedia::used_set != NULL) return true; + if (BaseMedia::used_set != nullptr) return true; - const Tbase_set *best = NULL; - for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { + const Tbase_set *best = nullptr; + for (const Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { if (c->GetNumMissing() != 0) continue; - if (best == NULL || + if (best == nullptr || (best->fallback && !c->fallback) || best->valid_files < c->valid_files || (best->valid_files == c->valid_files && @@ -115,7 +115,7 @@ template } BaseMedia::used_set = best; - return BaseMedia::used_set != NULL; + return BaseMedia::used_set != nullptr; } bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename) @@ -129,7 +129,7 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f uint tracknr = 1; for (uint i = 0; i < lengthof(this->songinfo); i++) { const char *filename = this->files[i].filename; - if (names == NULL || StrEmpty(filename) || this->files[i].check_result == MD5File::CR_NO_FILE) { + if (names == nullptr || StrEmpty(filename) || this->files[i].check_result == MD5File::CR_NO_FILE) { this->songinfo[i].songname[0] = '\0'; continue; } @@ -137,12 +137,12 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f this->songinfo[i].filename = filename; // non-owned pointer IniItem *item = catindex->GetItem(_music_file_names[i], false); - if (item != NULL && !StrEmpty(item->value)) { + if (item != nullptr && !StrEmpty(item->value)) { /* Song has a CAT file index, assume it's MPS MIDI format */ this->songinfo[i].filetype = MTT_MPSMIDI; this->songinfo[i].cat_index = atoi(item->value); char *songname = GetMusicCatEntryName(filename, this->songinfo[i].cat_index); - if (songname == NULL) { + if (songname == nullptr) { DEBUG(grf, 0, "Base music set song missing from CAT file: %s/%d", filename, this->songinfo[i].cat_index); this->songinfo[i].songname[0] = '\0'; continue; @@ -157,17 +157,17 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f /* As we possibly add a path to the filename and we compare * on the filename with the path as in the .obm, we need to * keep stripping path elements until we find a match. */ - for (; trimmed_filename != NULL; trimmed_filename = strchr(trimmed_filename, PATHSEPCHAR)) { + for (; trimmed_filename != nullptr; trimmed_filename = strchr(trimmed_filename, PATHSEPCHAR)) { /* Remove possible double path separator characters from * the beginning, so we don't start reading e.g. root. */ while (*trimmed_filename == PATHSEPCHAR) trimmed_filename++; item = names->GetItem(trimmed_filename, false); - if (item != NULL && !StrEmpty(item->value)) break; + if (item != nullptr && !StrEmpty(item->value)) break; } if (this->songinfo[i].filetype == MTT_STANDARDMIDI) { - if (item != NULL && !StrEmpty(item->value)) { + if (item != nullptr && !StrEmpty(item->value)) { strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname)); } else { DEBUG(grf, 0, "Base music set song name missing: %s", filename); @@ -184,9 +184,9 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f } item = timingtrim->GetItem(trimmed_filename, false); - if (item != NULL && !StrEmpty(item->value)) { + if (item != nullptr && !StrEmpty(item->value)) { const char *endpos = strchr(item->value, ':'); - if (endpos != NULL) { + if (endpos != nullptr) { this->songinfo[i].override_start = atoi(item->value); this->songinfo[i].override_end = atoi(endpos + 1); } diff --git a/src/music/allegro_m.cpp b/src/music/allegro_m.cpp index 906aec84fc..959f156118 100644 --- a/src/music/allegro_m.cpp +++ b/src/music/allegro_m.cpp @@ -20,7 +20,7 @@ #include "../safeguards.h" static FMusicDriver_Allegro iFMusicDriver_Allegro; -static MIDI *_midi = NULL; +static MIDI *_midi = nullptr; /** * There are multiple modules that might be using Allegro and @@ -30,14 +30,14 @@ extern int _allegro_instance_count; const char *MusicDriver_Allegro::Start(const char * const *param) { - if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, NULL)) { + if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); return "Failed to set up Allegro"; } _allegro_instance_count++; /* Initialise the sound */ - if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) != 0) { + if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, nullptr) != 0) { DEBUG(driver, 0, "allegro: install_sound failed '%s'", allegro_error); return "Failed to set up Allegro sound"; } @@ -48,13 +48,13 @@ const char *MusicDriver_Allegro::Start(const char * const *param) return "No sound card found"; } - return NULL; + return nullptr; } void MusicDriver_Allegro::Stop() { - if (_midi != NULL) destroy_midi(_midi); - _midi = NULL; + if (_midi != nullptr) destroy_midi(_midi); + _midi = nullptr; if (--_allegro_instance_count == 0) allegro_exit(); } @@ -63,12 +63,12 @@ void MusicDriver_Allegro::PlaySong(const MusicSongInfo &song) { std::string filename = MidiFile::GetSMFFile(song); - if (_midi != NULL) destroy_midi(_midi); + if (_midi != nullptr) destroy_midi(_midi); if (!filename.empty()) { _midi = load_midi(filename.c_str()); play_midi(_midi, false); } else { - _midi = NULL; + _midi = nullptr; } } diff --git a/src/music/allegro_m.h b/src/music/allegro_m.h index 65d8ab811d..9451162a21 100644 --- a/src/music/allegro_m.h +++ b/src/music/allegro_m.h @@ -17,18 +17,18 @@ /** Allegro's music player. */ class MusicDriver_Allegro : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "allegro"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "allegro"; } }; /** Factory for allegro's music player. */ @@ -43,7 +43,7 @@ public: static const int PRIORITY = 2; #endif FMusicDriver_Allegro() : DriverFactoryBase(Driver::DT_MUSIC, PRIORITY, "allegro", "Allegro MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Allegro(); } + Driver *CreateInstance() const override { return new MusicDriver_Allegro(); } }; #endif /* MUSIC_ALLEGRO_H */ diff --git a/src/music/bemidi.cpp b/src/music/bemidi.cpp index ff56d787f1..090ac0f907 100644 --- a/src/music/bemidi.cpp +++ b/src/music/bemidi.cpp @@ -28,7 +28,7 @@ static FMusicDriver_BeMidi iFMusicDriver_BeMidi; const char *MusicDriver_BeMidi::Start(const char * const *parm) { - return NULL; + return nullptr; } void MusicDriver_BeMidi::Stop() diff --git a/src/music/bemidi.h b/src/music/bemidi.h index 7c546525d2..8591ec0159 100644 --- a/src/music/bemidi.h +++ b/src/music/bemidi.h @@ -17,25 +17,25 @@ /** The midi player for BeOS. */ class MusicDriver_BeMidi : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "bemidi"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "bemidi"; } }; /** Factory for the BeOS midi player. */ class FMusicDriver_BeMidi : public DriverFactoryBase { public: FMusicDriver_BeMidi() : DriverFactoryBase(Driver::DT_MUSIC, 10, "bemidi", "BeOS MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_BeMidi(); } + Driver *CreateInstance() const override { return new MusicDriver_BeMidi(); } }; #endif /* MUSIC_BEMIDI_H */ diff --git a/src/music/cocoa_m.cpp b/src/music/cocoa_m.cpp index 2416cade0f..fd3ff295e8 100644 --- a/src/music/cocoa_m.cpp +++ b/src/music/cocoa_m.cpp @@ -35,8 +35,8 @@ static FMusicDriver_Cocoa iFMusicDriver_Cocoa; -static MusicPlayer _player = NULL; -static MusicSequence _sequence = NULL; +static MusicPlayer _player = nullptr; +static MusicSequence _sequence = nullptr; static MusicTimeStamp _seq_length = 0; static bool _playing = false; static byte _volume = 127; @@ -45,12 +45,12 @@ static byte _volume = 127; /** Set the volume of the current sequence. */ static void DoSetVolume() { - if (_sequence == NULL) return; + if (_sequence == nullptr) return; AUGraph graph; MusicSequenceGetAUGraph(_sequence, &graph); - AudioUnit output_unit = NULL; + AudioUnit output_unit = nullptr; /* Get output audio unit */ UInt32 node_count = 0; @@ -82,7 +82,7 @@ static void DoSetVolume() { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) ComponentDescription desc; - AUGraphGetNodeInfo(graph, node, &desc, NULL, NULL, &unit); + AUGraphGetNodeInfo(graph, node, &desc, nullptr, nullptr, &unit); comp_type = desc.componentType; #endif } @@ -92,7 +92,7 @@ static void DoSetVolume() break; } } - if (output_unit == NULL) { + if (output_unit == nullptr) { DEBUG(driver, 1, "cocoa_m: Failed to get output node to set volume"); return; } @@ -109,12 +109,12 @@ const char *MusicDriver_Cocoa::Start(const char * const *parm) { if (NewMusicPlayer(&_player) != noErr) return "failed to create music player"; - return NULL; + return nullptr; } /** - * Checks wether the player is active. + * Checks whether the player is active. */ bool MusicDriver_Cocoa::IsSongPlaying() { @@ -131,8 +131,8 @@ bool MusicDriver_Cocoa::IsSongPlaying() */ void MusicDriver_Cocoa::Stop() { - if (_player != NULL) DisposeMusicPlayer(_player); - if (_sequence != NULL) DisposeMusicSequence(_sequence); + if (_player != nullptr) DisposeMusicPlayer(_player); + if (_sequence != nullptr) DisposeMusicSequence(_sequence); } @@ -148,9 +148,9 @@ void MusicDriver_Cocoa::PlaySong(const MusicSongInfo &song) DEBUG(driver, 2, "cocoa_m: trying to play '%s'", filename.c_str()); this->StopSong(); - if (_sequence != NULL) { + if (_sequence != nullptr) { DisposeMusicSequence(_sequence); - _sequence = NULL; + _sequence = nullptr; } if (filename.empty()) return; @@ -190,7 +190,7 @@ void MusicDriver_Cocoa::PlaySong(const MusicSongInfo &song) CFRelease(url); /* Construct audio graph */ - AUGraph graph = NULL; + AUGraph graph = nullptr; MusicSequenceGetAUGraph(_sequence, &graph); AUGraphOpen(graph); @@ -204,7 +204,7 @@ void MusicDriver_Cocoa::PlaySong(const MusicSongInfo &song) MusicSequenceGetTrackCount(_sequence, &num_tracks); _seq_length = 0; for (UInt32 i = 0; i < num_tracks; i++) { - MusicTrack track = NULL; + MusicTrack track = nullptr; MusicTimeStamp track_length = 0; UInt32 prop_size = sizeof(MusicTimeStamp); MusicSequenceGetIndTrack(_sequence, i, &track); @@ -230,7 +230,7 @@ void MusicDriver_Cocoa::PlaySong(const MusicSongInfo &song) void MusicDriver_Cocoa::StopSong() { MusicPlayerStop(_player); - MusicPlayerSetSequence(_player, NULL); + MusicPlayerSetSequence(_player, nullptr); _playing = false; } diff --git a/src/music/cocoa_m.h b/src/music/cocoa_m.h index fdb10b84e6..7694927993 100644 --- a/src/music/cocoa_m.h +++ b/src/music/cocoa_m.h @@ -16,24 +16,24 @@ class MusicDriver_Cocoa : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "cocoa"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "cocoa"; } }; class FMusicDriver_Cocoa : public DriverFactoryBase { public: FMusicDriver_Cocoa() : DriverFactoryBase(Driver::DT_MUSIC, 10, "cocoa", "Cocoa MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Cocoa(); } + Driver *CreateInstance() const override { return new MusicDriver_Cocoa(); } }; #endif /* MUSIC_MACOSX_COCOA_H */ diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp index 47b3db19ae..c175b0727d 100644 --- a/src/music/dmusic.cpp +++ b/src/music/dmusic.cpp @@ -19,7 +19,7 @@ #include "../debug.h" #include "../os/windows/win32.h" #include "../core/mem_func.hpp" -#include "../thread/thread.h" +#include "../thread.h" #include "../fileio_func.h" #include "../base_media_base.h" #include "dmusic.h" @@ -30,6 +30,7 @@ #include #include #include +#include #include "../safeguards.h" @@ -138,18 +139,18 @@ static struct { } _playback; /** Handle to our worker thread. */ -static ThreadObject *_dmusic_thread = NULL; +static std::thread _dmusic_thread; /** Event to signal the thread that it should look at a state change. */ -static HANDLE _thread_event = NULL; +static HANDLE _thread_event = nullptr; /** Lock access to playback data that is not thread-safe. */ -static ThreadMutex *_thread_mutex = NULL; +static std::mutex _thread_mutex; /** The direct music object manages buffers and ports. */ -static IDirectMusic *_music = NULL; +static IDirectMusic *_music = nullptr; /** The port object lets us send MIDI data to the synthesizer. */ -static IDirectMusicPort *_port = NULL; +static IDirectMusicPort *_port = nullptr; /** The buffer object collects the data to sent. */ -static IDirectMusicBuffer *_buffer = NULL; +static IDirectMusicBuffer *_buffer = nullptr; /** List of downloaded DLS instruments. */ static std::vector _dls_downloads; @@ -233,7 +234,7 @@ bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector & break; default: - DEBUG(driver, 7, "DLS: Ignoring unkown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); fseek(f, chunk.length, SEEK_CUR); break; } @@ -256,7 +257,7 @@ bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instr if (list_type == FOURCC_RGN) { this->ReadDLSRegion(f, chunk.length - sizeof(list_type), instrument.regions); } else { - DEBUG(driver, 7, "DLS: Ignoring unkown list chunk of type %c%c%c%c", (char)(list_type & 0xFF), (char)((list_type >> 8) & 0xFF), (char)((list_type >> 16) & 0xFF), (char)((list_type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown list chunk of type %c%c%c%c", (char)(list_type & 0xFF), (char)((list_type >> 8) & 0xFF), (char)((list_type >> 16) & 0xFF), (char)((list_type >> 24) & 0xFF)); fseek(f, chunk.length - sizeof(list_type), SEEK_CUR); } } else { @@ -303,7 +304,7 @@ bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length) break; default: - DEBUG(driver, 7, "DLS: Ignoring unkown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); fseek(f, chunk.length, SEEK_CUR); break; } @@ -328,7 +329,7 @@ bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length) if (!this->ReadDLSInstrument(f, chunk.length - sizeof(list_type))) return false; } else { - DEBUG(driver, 7, "DLS: Ignoring unkown list chunk of type %c%c%c%c", (char)(list_type & 0xFF), (char)((list_type >> 8) & 0xFF), (char)((list_type >> 16) & 0xFF), (char)((list_type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown list chunk of type %c%c%c%c", (char)(list_type & 0xFF), (char)((list_type >> 8) & 0xFF), (char)((list_type >> 16) & 0xFF), (char)((list_type >> 24) & 0xFF)); fseek(f, chunk.length - sizeof(list_type), SEEK_CUR); } } else { @@ -391,7 +392,7 @@ bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length, long offset) break; default: - DEBUG(driver, 7, "DLS: Ignoring unkown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); fseek(f, chunk.length, SEEK_CUR); break; } @@ -420,7 +421,7 @@ bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length) if (!this->ReadDLSWave(f, chunk.length - sizeof(list_type), chunk_offset - base_offset)) return false; } else { - DEBUG(driver, 7, "DLS: Ignoring unkown list chunk of type %c%c%c%c", (char)(list_type & 0xFF), (char)((list_type >> 8) & 0xFF), (char)((list_type >> 16) & 0xFF), (char)((list_type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown list chunk of type %c%c%c%c", (char)(list_type & 0xFF), (char)((list_type >> 8) & 0xFF), (char)((list_type >> 16) & 0xFF), (char)((list_type >> 24) & 0xFF)); fseek(f, chunk.length - sizeof(list_type), SEEK_CUR); } } else { @@ -437,7 +438,7 @@ bool DLSFile::LoadFile(const TCHAR *file) DEBUG(driver, 2, "DMusic: Try to load DLS file %s", FS2OTTD(file)); FILE *f = _tfopen(file, _T("rb")); - if (f == NULL) return false; + if (f == nullptr) return false; FileCloser f_scope(f); @@ -499,7 +500,7 @@ bool DLSFile::LoadFile(const TCHAR *file) break; default: - DEBUG(driver, 7, "DLS: Ignoring unkown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); + DEBUG(driver, 7, "DLS: Ignoring unknown chunk %c%c%c%c", (char)(chunk.type & 0xFF), (char)((chunk.type >> 8) & 0xFF), (char)((chunk.type >> 16) & 0xFF), (char)((chunk.type >> 24) & 0xFF)); fseek(f, chunk.length, SEEK_CUR); break; } @@ -587,7 +588,7 @@ static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_ti Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000)); } -static void MidiThreadProc(void *) +static void MidiThreadProc() { DEBUG(driver, 2, "DMusic: Entering playback thread"); @@ -639,7 +640,7 @@ static void MidiThreadProc(void *) DEBUG(driver, 2, "DMusic thread: Starting playback"); { /* New scope to limit the time the mutex is locked. */ - ThreadMutexLocker lock(_thread_mutex); + std::lock_guard lock(_thread_mutex); current_file.MoveFrom(_playback.next_file); std::swap(_playback.next_segment, current_segment); @@ -670,7 +671,7 @@ static void MidiThreadProc(void *) size_t preload_bytes = 0; for (size_t bl = 0; bl < current_file.blocks.size(); bl++) { MidiFile::DataBlock &block = current_file.blocks[bl]; - preload_bytes += block.data.Length(); + preload_bytes += block.data.size(); if (block.ticktime >= current_segment.start) { if (current_segment.loop) { DEBUG(driver, 2, "DMusic: timer: loop from block %d (ticktime %d, realtime %.3f, bytes %d)", (int)bl, (int)block.ticktime, ((int)block.realtime) / 1000.0, (int)preload_bytes); @@ -735,8 +736,8 @@ static void MidiThreadProc(void *) block_time = playback_start_time + block.realtime * MIDITIME_TO_REFTIME; DEBUG(driver, 9, "DMusic thread: Streaming block " PRINTF_SIZE " (cur=" OTTD_PRINTF64 ", block=" OTTD_PRINTF64 ")", current_block, (long long)(current_time / MS_TO_REFTIME), (long long)(block_time / MS_TO_REFTIME)); - const byte *data = block.data.Begin(); - size_t remaining = block.data.Length(); + const byte *data = block.data.data(); + size_t remaining = block.data.size(); byte last_status = 0; while (remaining > 0) { /* MidiFile ought to have converted everything out of running status, @@ -862,13 +863,13 @@ static const char *LoadDefaultDLSFile(const char *user_dls) if ((caps.dwFlags & (DMUS_PC_DLS | DMUS_PC_DLS2)) != 0 && (caps.dwFlags & DMUS_PC_GMINHARDWARE) == 0) { DLSFile dls_file; - if (user_dls == NULL) { + if (user_dls == nullptr) { /* Try loading the default GM DLS file stored in the registry. */ HKEY hkDM; if (SUCCEEDED(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\DirectMusic"), 0, KEY_READ, &hkDM))) { TCHAR dls_path[MAX_PATH]; DWORD buf_size = sizeof(dls_path); // Buffer size as to be given in bytes! - if (SUCCEEDED(RegQueryValueEx(hkDM, _T("GMFilePath"), NULL, NULL, (LPBYTE)dls_path, &buf_size))) { + if (SUCCEEDED(RegQueryValueEx(hkDM, _T("GMFilePath"), nullptr, nullptr, (LPBYTE)dls_path, &buf_size))) { TCHAR expand_path[MAX_PATH * 2]; ExpandEnvironmentStrings(dls_path, expand_path, lengthof(expand_path)); if (!dls_file.LoadFile(expand_path)) DEBUG(driver, 1, "Failed to load default GM DLS file from registry"); @@ -889,7 +890,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) } /* Get download port and allocate download IDs. */ - IDirectMusicPortDownload *download_port = NULL; + IDirectMusicPortDownload *download_port = nullptr; if (FAILED(_port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port))) return "Can't get download port"; DWORD dlid_wave = 0, dlid_inst = 0; @@ -903,7 +904,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) /* Download wave data. */ for (DWORD i = 0; i < dls_file.waves.size(); i++) { - IDirectMusicDownload *dl_wave = NULL; + IDirectMusicDownload *dl_wave = nullptr; if (FAILED(download_port->AllocateBuffer((DWORD)(sizeof(WAVE_DOWNLOAD) + dwAppend * dls_file.waves[i].fmt.wf.nBlockAlign + dls_file.waves[i].data.size()), &dl_wave))) { download_port->Release(); return "Can't allocate wave download buffer"; @@ -967,7 +968,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) i_size += offsets * sizeof(ULONG); /* Allocate download buffer. */ - IDirectMusicDownload *dl_inst = NULL; + IDirectMusicDownload *dl_inst = nullptr; if (FAILED(download_port->AllocateBuffer((DWORD)i_size, &dl_inst))) { download_port->Release(); return "Can't allocate instrument download buffer"; @@ -1068,19 +1069,19 @@ static const char *LoadDefaultDLSFile(const char *user_dls) download_port->Release(); } - return NULL; + return nullptr; } const char *MusicDriver_DMusic::Start(const char * const *parm) { /* Initialize COM */ - if (FAILED(CoInitializeEx(NULL, COINITBASE_MULTITHREADED))) return "COM initialization failed"; + if (FAILED(CoInitializeEx(nullptr, COINITBASE_MULTITHREADED))) return "COM initialization failed"; /* Create the DirectMusic object */ if (FAILED(CoCreateInstance( CLSID_DirectMusic, - NULL, + nullptr, CLSCTX_INPROC, IID_IDirectMusic, (LPVOID*)&_music @@ -1089,7 +1090,7 @@ const char *MusicDriver_DMusic::Start(const char * const *parm) } /* Assign sound output device. */ - if (FAILED(_music->SetDirectSound(NULL, NULL))) return "Can't set DirectSound interface"; + if (FAILED(_music->SetDirectSound(nullptr, nullptr))) return "Can't set DirectSound interface"; /* MIDI events need to be send to the synth in time before their playback time * has come. By default, we try send any events at least 50 ms before playback. */ @@ -1132,7 +1133,7 @@ const char *MusicDriver_DMusic::Start(const char * const *parm) params.dwSize = sizeof(DMUS_PORTPARAMS); params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS; params.dwChannelGroups = 1; - if (FAILED(_music->CreatePort(guidPort, ¶ms, &_port, NULL))) return "Failed to create port"; + if (FAILED(_music->CreatePort(guidPort, ¶ms, &_port, nullptr))) return "Failed to create port"; /* Activate port. */ if (FAILED(_port->Activate(TRUE))) return "Failed to activate port"; @@ -1142,21 +1143,19 @@ const char *MusicDriver_DMusic::Start(const char * const *parm) desc.dwSize = sizeof(DMUS_BUFFERDESC); desc.guidBufferFormat = KSDATAFORMAT_SUBTYPE_DIRECTMUSIC; desc.cbBuffer = 1024; - if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer, NULL))) return "Failed to create music buffer"; + if (FAILED(_music->CreateMusicBuffer(&desc, &_buffer, nullptr))) return "Failed to create music buffer"; /* On soft-synths (e.g. the default DirectMusic one), we might need to load a wavetable set to get music. */ const char *dls = LoadDefaultDLSFile(GetDriverParam(parm, "dls")); - if (dls != NULL) return dls; + if (dls != nullptr) return dls; /* Create playback thread and synchronization primitives. */ - _thread_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_thread_event == NULL) return "Can't create thread shutdown event"; - _thread_mutex = ThreadMutex::New(); - if (_thread_mutex == NULL) return "Can't create thread mutex"; + _thread_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (_thread_event == nullptr) return "Can't create thread shutdown event"; - if (!ThreadObject::New(&MidiThreadProc, this, &_dmusic_thread, "ottd:dmusic")) return "Can't create MIDI output thread"; + if (!StartNewThread(&_dmusic_thread, "ottd:dmusic", &MidiThreadProc)) return "Can't create MIDI output thread"; - return NULL; + return nullptr; } @@ -1168,46 +1167,45 @@ MusicDriver_DMusic::~MusicDriver_DMusic() void MusicDriver_DMusic::Stop() { - if (_dmusic_thread != NULL) { + if (_dmusic_thread.joinable()) { _playback.shutdown = true; SetEvent(_thread_event); - _dmusic_thread->Join(); + _dmusic_thread.join(); } /* Unloaded any instruments we loaded. */ if (_dls_downloads.size() > 0) { - IDirectMusicPortDownload *download_port = NULL; + IDirectMusicPortDownload *download_port = nullptr; _port->QueryInterface(IID_IDirectMusicPortDownload, (LPVOID *)&download_port); /* Instruments refer to waves. As the waves are at the beginning of the download list, * do the unload from the back so that references are cleared properly. */ - for (std::vector::reverse_iterator i = _dls_downloads.rbegin(); download_port != NULL && i != _dls_downloads.rend(); i++) { + for (std::vector::reverse_iterator i = _dls_downloads.rbegin(); download_port != nullptr && i != _dls_downloads.rend(); i++) { download_port->Unload(*i); (*i)->Release(); } _dls_downloads.clear(); - if (download_port != NULL) download_port->Release(); + if (download_port != nullptr) download_port->Release(); } - if (_buffer != NULL) { + if (_buffer != nullptr) { _buffer->Release(); - _buffer = NULL; + _buffer = nullptr; } - if (_port != NULL) { + if (_port != nullptr) { _port->Activate(FALSE); _port->Release(); - _port = NULL; + _port = nullptr; } - if (_music != NULL) { + if (_music != nullptr) { _music->Release(); - _music = NULL; + _music = nullptr; } CloseHandle(_thread_event); - delete _thread_mutex; CoUninitialize(); } @@ -1215,7 +1213,7 @@ void MusicDriver_DMusic::Stop() void MusicDriver_DMusic::PlaySong(const MusicSongInfo &song) { - ThreadMutexLocker lock(_thread_mutex); + std::lock_guard lock(_thread_mutex); if (!_playback.next_file.LoadSong(song)) return; diff --git a/src/music/dmusic.h b/src/music/dmusic.h index 527e064e49..5b363b8917 100644 --- a/src/music/dmusic.h +++ b/src/music/dmusic.h @@ -19,25 +19,25 @@ class MusicDriver_DMusic : public MusicDriver { public: virtual ~MusicDriver_DMusic(); - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "dmusic"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "dmusic"; } }; /** Factory for the DirectX music player. */ class FMusicDriver_DMusic : public DriverFactoryBase { public: FMusicDriver_DMusic() : DriverFactoryBase(Driver::DT_MUSIC, 10, "dmusic", "DirectMusic MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_DMusic(); } + Driver *CreateInstance() const override { return new MusicDriver_DMusic(); } }; #endif /* MUSIC_DMUSIC_H */ diff --git a/src/music/extmidi.cpp b/src/music/extmidi.cpp index 9d07761b73..b390c42f55 100644 --- a/src/music/extmidi.cpp +++ b/src/music/extmidi.cpp @@ -18,6 +18,7 @@ #include "../gfx_func.h" #include "extmidi.h" #include "../base_media_base.h" +#include "../thread.h" #include "midifile.hpp" #include #include @@ -51,7 +52,7 @@ const char *MusicDriver_ExtMidi::Start(const char * const * parm) if (StrEmpty(command)) command = EXTERNAL_PLAYER " " MIDI_ARG; #endif - /* Count number of arguments, but include 3 extra slots: 1st for command, 2nd for song title, and 3rd for terminating NULL. */ + /* Count number of arguments, but include 3 extra slots: 1st for command, 2nd for song title, and 3rd for terminating nullptr. */ uint num_args = 3; for (const char *t = command; *t != '\0'; t++) if (*t == ' ') num_args++; @@ -62,7 +63,7 @@ const char *MusicDriver_ExtMidi::Start(const char * const * parm) uint p = 1; while (true) { this->params[p] = strchr(this->params[p - 1], ' '); - if (this->params[p] == NULL) break; + if (this->params[p] == nullptr) break; this->params[p][0] = '\0'; this->params[p]++; @@ -74,7 +75,7 @@ const char *MusicDriver_ExtMidi::Start(const char * const * parm) this->song[0] = '\0'; this->pid = -1; - return NULL; + return nullptr; } void MusicDriver_ExtMidi::Stop() @@ -102,7 +103,7 @@ void MusicDriver_ExtMidi::StopSong() bool MusicDriver_ExtMidi::IsSongPlaying() { - if (this->pid != -1 && waitpid(this->pid, NULL, WNOHANG) == this->pid) { + if (this->pid != -1 && waitpid(this->pid, nullptr, WNOHANG) == this->pid) { this->pid = -1; } if (this->pid == -1 && this->song[0] != '\0') this->DoPlay(); @@ -145,7 +146,7 @@ void MusicDriver_ExtMidi::DoStop() * 5 seconds = 5000 milliseconds, 10 ms per cycle => 500 cycles. */ for (int i = 0; i < 500; i++) { kill(this->pid, SIGTERM); - if (waitpid(this->pid, NULL, WNOHANG) == this->pid) { + if (waitpid(this->pid, nullptr, WNOHANG) == this->pid) { /* It has shut down, so we are done */ this->pid = -1; return; @@ -158,6 +159,6 @@ void MusicDriver_ExtMidi::DoStop() /* Gracefully stopping failed. Do it the hard way * and wait till the process finally died. */ kill(this->pid, SIGKILL); - waitpid(this->pid, NULL, 0); + waitpid(this->pid, nullptr, 0); this->pid = -1; } diff --git a/src/music/extmidi.h b/src/music/extmidi.h index e174dc9b08..55050c0d2b 100644 --- a/src/music/extmidi.h +++ b/src/music/extmidi.h @@ -24,24 +24,24 @@ private: void DoStop(); public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "extmidi"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "extmidi"; } }; class FMusicDriver_ExtMidi : public DriverFactoryBase { public: FMusicDriver_ExtMidi() : DriverFactoryBase(Driver::DT_MUSIC, 3, "extmidi", "External MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_ExtMidi(); } + Driver *CreateInstance() const override { return new MusicDriver_ExtMidi(); } }; #endif /* MUSIC_EXTERNAL_H */ diff --git a/src/music/fluidsynth.cpp b/src/music/fluidsynth.cpp index 6baeb899bc..4623716a46 100644 --- a/src/music/fluidsynth.cpp +++ b/src/music/fluidsynth.cpp @@ -39,7 +39,7 @@ static const char *default_sf[] = { "/usr/share/sounds/sf2/TimGM6mb.sf2", "/usr/share/sounds/sf2/FluidR3_GS.sf2", - NULL + nullptr }; static void RenderMusicStream(int16 *buffer, size_t samples) @@ -58,6 +58,8 @@ const char *MusicDriver_FluidSynth::Start(const char * const *param) /* Create the settings. */ _midi.settings = new_fluid_settings(); if (!_midi.settings) return "Could not create midi settings"; + /* Don't try to lock sample data in memory, OTTD usually does not run with privileges allowing that */ + fluid_settings_setint(_midi.settings, "synth.lock-memory", 0); /* Create the synthesizer. */ _midi.synth = new_fluid_synth(_midi.settings); @@ -79,18 +81,18 @@ const char *MusicDriver_FluidSynth::Start(const char * const *param) if (sfont_id == FLUID_FAILED) return "Could not open sound font"; } - _midi.player = NULL; + _midi.player = nullptr; uint32 samplerate = MxSetMusicSource(RenderMusicStream); fluid_synth_set_sample_rate(_midi.synth, samplerate); DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate); - return NULL; + return nullptr; } void MusicDriver_FluidSynth::Stop() { - MxSetMusicSource(NULL); + MxSetMusicSource(nullptr); this->StopSong(); delete_fluid_synth(_midi.synth); delete_fluid_settings(_midi.settings); @@ -115,13 +117,13 @@ void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song) if (fluid_player_add(_midi.player, filename.c_str()) != FLUID_OK) { DEBUG(driver, 0, "Could not open music file"); delete_fluid_player(_midi.player); - _midi.player = NULL; + _midi.player = nullptr; return; } if (fluid_player_play(_midi.player) != FLUID_OK) { DEBUG(driver, 0, "Could not start midi player"); delete_fluid_player(_midi.player); - _midi.player = NULL; + _midi.player = nullptr; return; } } @@ -136,7 +138,7 @@ void MusicDriver_FluidSynth::StopSong() } delete_fluid_player(_midi.player); fluid_synth_system_reset(_midi.synth); - _midi.player = NULL; + _midi.player = nullptr; } bool MusicDriver_FluidSynth::IsSongPlaying() diff --git a/src/music/fluidsynth.h b/src/music/fluidsynth.h index 171128a8e9..e8a294b77b 100644 --- a/src/music/fluidsynth.h +++ b/src/music/fluidsynth.h @@ -17,25 +17,25 @@ /** Music driver making use of FluidSynth. */ class MusicDriver_FluidSynth : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "fluidsynth"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "fluidsynth"; } }; /** Factory for the fluidsynth driver. */ class FMusicDriver_FluidSynth : public DriverFactoryBase { public: FMusicDriver_FluidSynth() : DriverFactoryBase(Driver::DT_MUSIC, 5, "fluidsynth", "FluidSynth MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_FluidSynth(); } + Driver *CreateInstance() const override { return new MusicDriver_FluidSynth(); } }; #endif /* MUSIC_FLUIDSYNTH_H */ diff --git a/src/music/midifile.cpp b/src/music/midifile.cpp index eb5499426d..6ee1f0e60e 100644 --- a/src/music/midifile.cpp +++ b/src/music/midifile.cpp @@ -21,11 +21,10 @@ #include "../console_func.h" #include "../console_internal.h" - /* SMF reader based on description at: http://www.somascape.org/midi/tech/mfile.html */ -static MidiFile *_midifile_instance = NULL; +static MidiFile *_midifile_instance = nullptr; /** * Retrieve a well-known MIDI system exclusive message. @@ -145,7 +144,7 @@ public: /** * Read bytes into a buffer. - * @param[out] dest buffer to copy info + * @param[out] dest buffer to copy into * @param length number of bytes to read * @return true if the requested number of bytes were available */ @@ -158,6 +157,21 @@ public: return true; } + /** + * Read bytes into a MidiFile::DataBlock. + * @param[out] dest DataBlock to copy into + * @param length number of bytes to read + * @return true if the requested number of bytes were available + */ + bool ReadDataBlock(MidiFile::DataBlock *dest, size_t length) + { + if (this->IsEnd()) return false; + if (this->buflen - this->pos < length) return false; + dest->data.insert(dest->data.end(), this->buf + this->pos, this->buf + this->pos + length); + this->pos += length; + return true; + } + /** * Skip over a number of bytes in the buffer. * @param count number of bytes to skip over @@ -240,7 +254,6 @@ static bool ReadTrackChunk(FILE *file, MidiFile &target) /* Regular channel message */ last_status = status; running_status: - byte *data; switch (status & 0xF0) { case MIDIST_NOTEOFF: case MIDIST_NOTEON: @@ -248,20 +261,19 @@ static bool ReadTrackChunk(FILE *file, MidiFile &target) case MIDIST_CONTROLLER: case MIDIST_PITCHBEND: /* 3 byte messages */ - data = block->data.Append(3); - data[0] = status; - if (!chunk.ReadBuffer(&data[1], 2)) { + block->data.push_back(status); + if (!chunk.ReadDataBlock(block, 2)) { return false; } break; case MIDIST_PROGCHG: case MIDIST_CHANPRESS: /* 2 byte messages */ - data = block->data.Append(2); - data[0] = status; - if (!chunk.ReadByte(data[1])) { + block->data.push_back(status); + if (!chunk.ReadByte(buf[0])) { return false; } + block->data.push_back(buf[0]); break; default: NOT_REACHED(); @@ -298,15 +310,14 @@ static bool ReadTrackChunk(FILE *file, MidiFile &target) if (!chunk.ReadVariableLength(length)) { return false; } - byte *data = block->data.Append(length + 1); - data[0] = 0xF0; - if (!chunk.ReadBuffer(data + 1, length)) { + block->data.push_back(0xF0); + if (!chunk.ReadDataBlock(block, length)) { return false; } - if (data[length] != 0xF7) { + if (block->data.back() != 0xF7) { /* Engage Casio weirdo mode - convert to normal sysex */ running_sysex = true; - *block->data.Append() = 0xF7; + block->data.push_back(0xF7); } else { running_sysex = false; } @@ -316,8 +327,7 @@ static bool ReadTrackChunk(FILE *file, MidiFile &target) if (!chunk.ReadVariableLength(length)) { return false; } - byte *data = block->data.Append(length); - if (!chunk.ReadBuffer(data, length)) { + if (!chunk.ReadDataBlock(block, length)) { return false; } } else { @@ -361,14 +371,13 @@ static bool FixupMidiData(MidiFile &target) uint32 last_ticktime = 0; for (size_t i = 0; i < target.blocks.size(); i++) { MidiFile::DataBlock &block = target.blocks[i]; - if (block.data.Length() == 0) { + if (block.data.size() == 0) { continue; } else if (block.ticktime > last_ticktime || merged_blocks.size() == 0) { merged_blocks.push_back(block); last_ticktime = block.ticktime; } else { - byte *datadest = merged_blocks.back().data.Append(block.data.Length()); - memcpy(datadest, block.data.Begin(), block.data.Length()); + merged_blocks.back().data.insert(merged_blocks.back().data.end(), block.data.begin(), block.data.end()); } } std::swap(merged_blocks, target.blocks); @@ -458,7 +467,7 @@ bool MidiFile::LoadFile(const char *filename) bool success = false; FILE *file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR); - if (file == NULL) return false; + if (file == nullptr) return false; SMFHeader header; if (!ReadSMFHeader(file, header)) goto cleanup; @@ -539,14 +548,14 @@ struct MpsMachine { static void AddMidiData(MidiFile::DataBlock &block, byte b1, byte b2) { - *block.data.Append() = b1; - *block.data.Append() = b2; + block.data.push_back(b1); + block.data.push_back(b2); } static void AddMidiData(MidiFile::DataBlock &block, byte b1, byte b2, byte b3) { - *block.data.Append() = b1; - *block.data.Append() = b2; - *block.data.Append() = b3; + block.data.push_back(b1); + block.data.push_back(b2); + block.data.push_back(b3); } /** @@ -847,7 +856,7 @@ bool MidiFile::LoadSong(const MusicSongInfo &song) { size_t songdatalen = 0; byte *songdata = GetMusicCatEntryData(song.filename, song.cat_index, songdatalen); - if (songdata != NULL) { + if (songdata != nullptr) { bool result = this->LoadMpsData(songdata, songdatalen); free(songdata); return result; @@ -972,8 +981,8 @@ bool MidiFile::WriteSMF(const char *filename) } /* Write each block data command */ - byte *dp = block.data.Begin(); - while (dp < block.data.End()) { + byte *dp = block.data.data(); + while (dp < block.data.data() + block.data.size()) { /* Always zero delta time inside blocks */ if (needtime) { fputc(0, f); @@ -1056,7 +1065,7 @@ std::string MidiFile::GetSMFFile(const MusicSongInfo &song) char basename[MAX_PATH]; { const char *fnstart = strrchr(song.filename, PATHSEPCHAR); - if (fnstart == NULL) { + if (fnstart == nullptr) { fnstart = song.filename; } else { fnstart++; @@ -1086,7 +1095,7 @@ std::string MidiFile::GetSMFFile(const MusicSongInfo &song) byte *data; size_t datalen; data = GetMusicCatEntryData(song.filename, song.cat_index, datalen); - if (data == NULL) return std::string(); + if (data == nullptr) return std::string(); MidiFile midifile; if (!midifile.LoadMpsData(data, datalen)) { @@ -1114,7 +1123,7 @@ static bool CmdDumpSMF(byte argc, char *argv[]) return false; } - if (_midifile_instance == NULL) { + if (_midifile_instance == nullptr) { IConsolePrint(CC_ERROR, "There is no MIDI file loaded currently, make sure music is playing, and you're using a driver that works with raw MIDI."); return false; } @@ -1152,7 +1161,7 @@ MidiFile::MidiFile() MidiFile::~MidiFile() { if (_midifile_instance == this) { - _midifile_instance = NULL; + _midifile_instance = nullptr; } } diff --git a/src/music/midifile.hpp b/src/music/midifile.hpp index 0016be86ca..4d362a1be2 100644 --- a/src/music/midifile.hpp +++ b/src/music/midifile.hpp @@ -22,9 +22,9 @@ struct MusicSongInfo; struct MidiFile { struct DataBlock { - uint32 ticktime; ///< tick number since start of file this block should be triggered at - uint32 realtime; ///< real-time (microseconds) since start of file this block should be triggered at - SmallVector data; ///< raw midi data contained in block + uint32 ticktime; ///< tick number since start of file this block should be triggered at + uint32 realtime; ///< real-time (microseconds) since start of file this block should be triggered at + std::vector data; ///< raw midi data contained in block DataBlock(uint32 _ticktime = 0) : ticktime(_ticktime) { } }; struct TempoChange { diff --git a/src/music/null_m.h b/src/music/null_m.h index 51e1a06656..8eb7d67925 100644 --- a/src/music/null_m.h +++ b/src/music/null_m.h @@ -17,25 +17,25 @@ /** The music player that does nothing. */ class MusicDriver_Null : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param) { return NULL; } + const char *Start(const char * const *param) override { return nullptr; } - /* virtual */ void Stop() { } + void Stop() override { } - /* virtual */ void PlaySong(const MusicSongInfo &song) { } + void PlaySong(const MusicSongInfo &song) override { } - /* virtual */ void StopSong() { } + void StopSong() override { } - /* virtual */ bool IsSongPlaying() { return true; } + bool IsSongPlaying() override { return true; } - /* virtual */ void SetVolume(byte vol) { } - /* virtual */ const char *GetName() const { return "null"; } + void SetVolume(byte vol) override { } + const char *GetName() const override { return "null"; } }; /** Factory for the null music player. */ class FMusicDriver_Null : public DriverFactoryBase { public: FMusicDriver_Null() : DriverFactoryBase(Driver::DT_MUSIC, 1, "null", "Null Music Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Null(); } + Driver *CreateInstance() const override { return new MusicDriver_Null(); } }; #endif /* MUSIC_NULL_H */ diff --git a/src/music/os2_m.cpp b/src/music/os2_m.cpp index 1689f00a64..92e177f840 100644 --- a/src/music/os2_m.cpp +++ b/src/music/os2_m.cpp @@ -45,7 +45,7 @@ static long CDECL MidiSendCommand(const char *cmd, ...) va_start(va, cmd); vseprintf(buf, lastof(buf), cmd, va); va_end(va); - return mciSendString(buf, NULL, 0, NULL, 0); + return mciSendString(buf, nullptr, 0, nullptr, 0); } /** OS/2's music player's factory. */ @@ -78,7 +78,7 @@ void MusicDriver_OS2::SetVolume(byte vol) bool MusicDriver_OS2::IsSongPlaying() { char buf[16]; - mciSendString("status song mode", buf, sizeof(buf), NULL, 0); + mciSendString("status song mode", buf, sizeof(buf), nullptr, 0); return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; } diff --git a/src/music/os2_m.h b/src/music/os2_m.h index ac7cd03197..e320946edb 100644 --- a/src/music/os2_m.h +++ b/src/music/os2_m.h @@ -17,25 +17,25 @@ /** OS/2's music player. */ class MusicDriver_OS2 : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "os2"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "os2"; } }; /** Factory for OS/2's music player. */ class FMusicDriver_OS2 : public DriverFactoryBase { public: FMusicDriver_OS2() : DriverFactoryBase(Driver::DT_MUSIC, 10, "os2", "OS/2 Music Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_OS2(); } + Driver *CreateInstance() const override { return new MusicDriver_OS2(); } }; #endif /* MUSIC_OS2_H */ diff --git a/src/music/qtmidi.cpp b/src/music/qtmidi.cpp index f8ab150e79..e612604edd 100644 --- a/src/music/qtmidi.cpp +++ b/src/music/qtmidi.cpp @@ -34,11 +34,13 @@ #include "../debug.h" #include "../base_media_base.h" -#define Rect OTTDRect -#define Point OTTDPoint +#define Rect OTTD_Rect +#define Point OTTD_Point +#define WindowClass OTTD_WindowClass #include #undef Rect #undef Point +#undef WindowClass #include "../safeguards.h" @@ -60,7 +62,7 @@ static void SetMIDITypeIfNeeded(const FSRef *ref) assert(ref); - if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return; + if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, nullptr, nullptr, nullptr)) return; if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) { FileInfo * const info = (FileInfo *) catalogInfo.finderInfo; if (info->fileType != MIDI_TYPE && !(info->finderFlags & kIsAlias)) { @@ -94,8 +96,8 @@ static bool LoadMovieForMIDIFile(const char *path, Movie *moov) short refnum = 0; short resid = 0; - assert(path != NULL); - assert(moov != NULL); + assert(path != nullptr); + assert(moov != nullptr); DEBUG(driver, 2, "qtmidi: start loading '%s'...", path); @@ -116,15 +118,15 @@ static bool LoadMovieForMIDIFile(const char *path, Movie *moov) return false; } - if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, NULL)) return false; + if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, nullptr)) return false; SetMIDITypeIfNeeded(&fsref); - if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL)) return false; + if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, nullptr, nullptr, &fsspec, nullptr)) return false; if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false; DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path); - if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL, - newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) { + if (noErr != NewMovieFromFile(moov, refnum, &resid, nullptr, + newMovieActive | newMovieDontAskUnresolvedDataRefs, nullptr)) { CloseMovieFile(refnum); return false; } @@ -154,7 +156,7 @@ static void InitQuickTimeIfNeeded() if (_quicktime_started) return; DEBUG(driver, 2, "qtmidi: initializing Quicktime"); - /* Be polite: check wether QuickTime is available and initialize it. */ + /* Be polite: check whether QuickTime is available and initialize it. */ _quicktime_started = (noErr == Gestalt(gestaltQuickTime, &dummy)) && (noErr == EnterMovies()); @@ -191,7 +193,7 @@ static int _quicktime_state = QT_STATE_IDLE; ///< Current player state. const char *MusicDriver_QtMidi::Start(const char * const *parm) { InitQuickTimeIfNeeded(); - return (_quicktime_started) ? NULL : "can't initialize QuickTime"; + return (_quicktime_started) ? nullptr : "can't initialize QuickTime"; } @@ -213,9 +215,9 @@ bool MusicDriver_QtMidi::IsSongPlaying() case QT_STATE_PLAY: MoviesTask(_quicktime_movie, 0); - /* Check wether movie ended. */ + /* Check whether movie ended. */ if (IsMovieDone(_quicktime_movie) || - (GetMovieTime(_quicktime_movie, NULL) >= + (GetMovieTime(_quicktime_movie, nullptr) >= GetMovieDuration(_quicktime_movie))) { _quicktime_state = QT_STATE_STOP; } diff --git a/src/music/qtmidi.h b/src/music/qtmidi.h index 32163db939..631f04d2db 100644 --- a/src/music/qtmidi.h +++ b/src/music/qtmidi.h @@ -16,24 +16,24 @@ class MusicDriver_QtMidi : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "qt"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "qt"; } }; class FMusicDriver_QtMidi : public DriverFactoryBase { public: FMusicDriver_QtMidi() : DriverFactoryBase(Driver::DT_MUSIC, 5, "qt", "QuickTime MIDI Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_QtMidi(); } + Driver *CreateInstance() const override { return new MusicDriver_QtMidi(); } }; #endif /* MUSIC_MACOSX_QUICKTIME_H */ diff --git a/src/music/win32_m.cpp b/src/music/win32_m.cpp index abe2aa31b4..d1ff5375aa 100644 --- a/src/music/win32_m.cpp +++ b/src/music/win32_m.cpp @@ -19,6 +19,7 @@ #include "midifile.hpp" #include "midi.h" #include "../base_media_base.h" +#include #include "../safeguards.h" @@ -29,10 +30,10 @@ struct PlaybackSegment { }; static struct { - UINT time_period; ///< obtained timer precision value - HMIDIOUT midi_out; ///< handle to open midiOut - UINT timer_id; ///< ID of active multimedia timer - CRITICAL_SECTION lock; ///< synchronization for playback status fields + UINT time_period; ///< obtained timer precision value + HMIDIOUT midi_out; ///< handle to open midiOut + UINT timer_id; ///< ID of active multimedia timer + std::mutex lock; ///< synchronization for playback status fields bool playing; ///< flag indicating that playback is active int do_start; ///< flag for starting playback of next_file at next opportunity @@ -82,7 +83,7 @@ static void TransmitSysex(const byte *&msg_start, size_t &remaining) /* prepare header */ MIDIHDR *hdr = CallocT(1); - hdr->lpData = (LPSTR)msg_start; + hdr->lpData = reinterpret_cast(const_cast(msg_start)); hdr->dwBufferLength = msg_end - msg_start; if (midiOutPrepareHeader(_midi.midi_out, hdr, sizeof(*hdr)) == MMSYSERR_NOERROR) { /* transmit - just point directly into the data buffer */ @@ -111,7 +112,8 @@ static void TransmitStandardSysex(MidiSysexMessage msg) void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DWORD_PTR) { /* Ensure only one timer callback is running at once, and prevent races on status flags */ - if (!TryEnterCriticalSection(&_midi.lock)) return; + std::unique_lock mutex_lock(_midi.lock, std::defer_lock); + if (!mutex_lock.try_lock()) return; /* check for stop */ if (_midi.do_stop) { @@ -119,7 +121,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW midiOutReset(_midi.midi_out); _midi.playing = false; _midi.do_stop = false; - LeaveCriticalSection(&_midi.lock); return; } @@ -127,7 +128,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW if (_midi.do_start != 0) { /* Have a delay between playback start steps, prevents jumbled-together notes at the start of song */ if (timeGetTime() - _midi.playback_start_time < 50) { - LeaveCriticalSection(&_midi.lock); return; } DEBUG(driver, 2, "Win32-MIDI: timer: do_start step %d", _midi.do_start); @@ -138,7 +138,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW _midi.playback_start_time = timeGetTime(); _midi.do_start = 2; - LeaveCriticalSection(&_midi.lock); return; } else if (_midi.do_start == 2) { /* Reset the device to General MIDI defaults */ @@ -146,7 +145,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW _midi.playback_start_time = timeGetTime(); _midi.do_start = 3; - LeaveCriticalSection(&_midi.lock); return; } else if (_midi.do_start == 3) { /* Set up device-specific effects */ @@ -154,7 +152,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW _midi.playback_start_time = timeGetTime(); _midi.do_start = 4; - LeaveCriticalSection(&_midi.lock); return; } else if (_midi.do_start == 4) { /* Load the new file */ @@ -173,7 +170,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW DEBUG(driver, 2, "Win32-MIDI: timer: not playing, stopping timer"); timeKillEvent(uTimerID); _midi.timer_id = 0; - LeaveCriticalSection(&_midi.lock); return; } @@ -198,10 +194,10 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW /* find first block after start time and pretend playback started earlier * this is to allow all blocks prior to the actual start to still affect playback, * as they may contain important controller and program changes */ - uint preload_bytes = 0; + size_t preload_bytes = 0; for (size_t bl = 0; bl < _midi.current_file.blocks.size(); bl++) { MidiFile::DataBlock &block = _midi.current_file.blocks[bl]; - preload_bytes += block.data.Length(); + preload_bytes += block.data.size(); if (block.ticktime >= _midi.current_segment.start) { if (_midi.current_segment.loop) { DEBUG(driver, 2, "Win32-MIDI: timer: loop from block %d (ticktime %d, realtime %.3f, bytes %d)", (int)bl, (int)block.ticktime, ((int)block.realtime)/1000.0, (int)preload_bytes); @@ -243,8 +239,8 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW break; } - const byte *data = block.data.Begin(); - size_t remaining = block.data.Length(); + const byte *data = block.data.data(); + size_t remaining = block.data.size(); byte last_status = 0; while (remaining > 0) { /* MidiFile ought to have converted everything out of running status, @@ -322,8 +318,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW _midi.do_stop = true; } } - - LeaveCriticalSection(&_midi.lock); } void MusicDriver_Win32::PlaySong(const MusicSongInfo &song) @@ -334,7 +328,7 @@ void MusicDriver_Win32::PlaySong(const MusicSongInfo &song) if (!new_song.LoadSong(song)) return; DEBUG(driver, 2, "Win32-MIDI: PlaySong: Loaded song"); - EnterCriticalSection(&_midi.lock); + std::lock_guard mutex_lock(_midi.lock); _midi.next_file.MoveFrom(new_song); _midi.next_segment.start = song.override_start; @@ -349,17 +343,14 @@ void MusicDriver_Win32::PlaySong(const MusicSongInfo &song) DEBUG(driver, 2, "Win32-MIDI: PlaySong: starting timer"); _midi.timer_id = timeSetEvent(_midi.time_period, _midi.time_period, TimerCallback, (DWORD_PTR)this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION); } - - LeaveCriticalSection(&_midi.lock); } void MusicDriver_Win32::StopSong() { DEBUG(driver, 2, "Win32-MIDI: StopSong: entry"); - EnterCriticalSection(&_midi.lock); + std::lock_guard mutex_lock(_midi.lock); DEBUG(driver, 2, "Win32-MIDI: StopSong: setting flag"); _midi.do_stop = true; - LeaveCriticalSection(&_midi.lock); } bool MusicDriver_Win32::IsSongPlaying() @@ -369,22 +360,39 @@ bool MusicDriver_Win32::IsSongPlaying() void MusicDriver_Win32::SetVolume(byte vol) { - EnterCriticalSection(&_midi.lock); + std::lock_guard mutex_lock(_midi.lock); _midi.new_volume = vol; - LeaveCriticalSection(&_midi.lock); } const char *MusicDriver_Win32::Start(const char * const *parm) { DEBUG(driver, 2, "Win32-MIDI: Start: initializing"); - InitializeCriticalSection(&_midi.lock); - int resolution = GetDriverParamInt(parm, "resolution", 5); - int port = GetDriverParamInt(parm, "port", -1); + uint port = (uint)GetDriverParamInt(parm, "port", UINT_MAX); + const char *portname = GetDriverParam(parm, "portname"); + + /* Enumerate ports either for selecting port by name, or for debug output */ + if (portname != nullptr || _debug_driver_level > 0) { + uint numports = midiOutGetNumDevs(); + DEBUG(driver, 1, "Win32-MIDI: Found %d output devices:", numports); + for (uint tryport = 0; tryport < numports; tryport++) { + MIDIOUTCAPS moc{}; + if (midiOutGetDevCaps(tryport, &moc, sizeof(moc)) == MMSYSERR_NOERROR) { + char tryportname[128]; + convert_from_fs(moc.szPname, tryportname, lengthof(tryportname)); + + /* Compare requested and detected port name. + * If multiple ports have the same name, this will select the last matching port, and the debug output will be confusing. */ + if (portname != nullptr && strncmp(tryportname, portname, lengthof(tryportname)) == 0) port = tryport; + + DEBUG(driver, 1, "MIDI port %2d: %s%s", tryport, tryportname, (tryport == port) ? " [selected]" : ""); + } + } + } UINT devid; - if (port < 0) { + if (port == UINT_MAX) { devid = MIDI_MAPPER; } else { devid = (UINT)port; @@ -405,7 +413,7 @@ const char *MusicDriver_Win32::Start(const char * const *parm) if (timeBeginPeriod(_midi.time_period) == MMSYSERR_NOERROR) { /* success */ DEBUG(driver, 2, "Win32-MIDI: Start: timer resolution is %d", (int)_midi.time_period); - return NULL; + return nullptr; } } midiOutClose(_midi.midi_out); @@ -414,7 +422,7 @@ const char *MusicDriver_Win32::Start(const char * const *parm) void MusicDriver_Win32::Stop() { - EnterCriticalSection(&_midi.lock); + std::lock_guard mutex_lock(_midi.lock); if (_midi.timer_id) { timeKillEvent(_midi.timer_id); @@ -424,7 +432,4 @@ void MusicDriver_Win32::Stop() timeEndPeriod(_midi.time_period); midiOutReset(_midi.midi_out); midiOutClose(_midi.midi_out); - - LeaveCriticalSection(&_midi.lock); - DeleteCriticalSection(&_midi.lock); } diff --git a/src/music/win32_m.h b/src/music/win32_m.h index 1ac8ae69e4..5366cf5d71 100644 --- a/src/music/win32_m.h +++ b/src/music/win32_m.h @@ -17,25 +17,25 @@ /** The Windows music player. */ class MusicDriver_Win32 : public MusicDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void PlaySong(const MusicSongInfo &song); + void PlaySong(const MusicSongInfo &song) override; - /* virtual */ void StopSong(); + void StopSong() override; - /* virtual */ bool IsSongPlaying(); + bool IsSongPlaying() override; - /* virtual */ void SetVolume(byte vol); - /* virtual */ const char *GetName() const { return "win32"; } + void SetVolume(byte vol) override; + const char *GetName() const override { return "win32"; } }; /** Factory for Windows' music player. */ class FMusicDriver_Win32 : public DriverFactoryBase { public: FMusicDriver_Win32() : DriverFactoryBase(Driver::DT_MUSIC, 5, "win32", "Win32 Music Driver") {} - /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Win32(); } + Driver *CreateInstance() const override { return new MusicDriver_Win32(); } }; #endif /* MUSIC_WIN32_H */ diff --git a/src/music_gui.cpp b/src/music_gui.cpp index 885647427f..90fd476690 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -459,7 +459,7 @@ struct MusicTrackSelectionWindow : public Window { this->LowerWidget(WID_MTS_ALL + _settings_client.music.playlist); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_MTS_PLAYLIST: @@ -476,7 +476,7 @@ struct MusicTrackSelectionWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; for (int i = 0; i < 6; i++) { @@ -486,7 +486,7 @@ struct MusicTrackSelectionWindow : public Window { this->SetDirty(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_MTS_PLAYLIST: { @@ -521,7 +521,7 @@ struct MusicTrackSelectionWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_MTS_LIST_LEFT: { @@ -554,7 +554,7 @@ struct MusicTrackSelectionWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_MTS_LIST_LEFT: { // add to playlist @@ -571,8 +571,7 @@ struct MusicTrackSelectionWindow : public Window { case WID_MTS_MUSICSET: { int selected = 0; - DropDownList *dropdown = BuildMusicSetDropDownList(&selected); - ShowDropDownList(this, dropdown, selected, widget, 0, true, false); + ShowDropDownList(this, BuildMusicSetDropDownList(&selected), selected, widget, 0, true, false); break; } @@ -587,7 +586,7 @@ struct MusicTrackSelectionWindow : public Window { } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_MTS_MUSICSET: @@ -672,7 +671,7 @@ struct MusicWindow : public Window { ); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { /* Make sure that WID_M_SHUFFLE and WID_M_PROGRAMME have the same size. @@ -714,7 +713,7 @@ struct MusicWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_M_TRACK_NR: { @@ -763,7 +762,7 @@ struct MusicWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; for (int i = 0; i < 6; i++) { @@ -775,7 +774,7 @@ struct MusicWindow : public Window { this->SetDirty(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_M_PREV: // skip to prev diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 62af3a40bf..3d5bd5d641 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -11,8 +11,6 @@ #include "../../stdafx.h" -#ifdef ENABLE_NETWORK - #include "address.h" #include "../../debug.h" @@ -27,7 +25,7 @@ const char *NetworkAddress::GetHostname() { if (StrEmpty(this->hostname) && this->address.ss_family != AF_UNSPEC) { assert(this->address_length != 0); - getnameinfo((struct sockaddr *)&this->address, this->address_length, this->hostname, sizeof(this->hostname), NULL, 0, NI_NUMERICHOST); + getnameinfo((struct sockaddr *)&this->address, this->address_length, this->hostname, sizeof(this->hostname), nullptr, 0, NI_NUMERICHOST); } return this->hostname; } @@ -133,7 +131,7 @@ const sockaddr_storage *NetworkAddress::GetAddress() * bothered to implement the specifications and allow '0' as value * that means "don't care whether it is SOCK_STREAM or SOCK_DGRAM". */ - this->Resolve(this->address.ss_family, SOCK_STREAM, AI_ADDRCONFIG, NULL, ResolveLoopProc); + this->Resolve(this->address.ss_family, SOCK_STREAM, AI_ADDRCONFIG, nullptr, ResolveLoopProc); this->resolved = true; } return &this->address; @@ -147,7 +145,7 @@ const sockaddr_storage *NetworkAddress::GetAddress() bool NetworkAddress::IsFamily(int family) { if (!this->IsResolved()) { - this->Resolve(family, SOCK_STREAM, AI_ADDRCONFIG, NULL, ResolveLoopProc); + this->Resolve(family, SOCK_STREAM, AI_ADDRCONFIG, nullptr, ResolveLoopProc); } return this->address.ss_family == family; } @@ -158,7 +156,7 @@ bool NetworkAddress::IsFamily(int family) * @note netmask without /n assumes all bits need to match. * @return true if this IP is within the netmask. */ -bool NetworkAddress::IsInNetmask(char *netmask) +bool NetworkAddress::IsInNetmask(const char *netmask) { /* Resolve it if we didn't do it already */ if (!this->IsResolved()) this->GetAddress(); @@ -168,17 +166,16 @@ bool NetworkAddress::IsInNetmask(char *netmask) NetworkAddress mask_address; /* Check for CIDR separator */ - char *chr_cidr = strchr(netmask, '/'); - if (chr_cidr != NULL) { + const char *chr_cidr = strchr(netmask, '/'); + if (chr_cidr != nullptr) { int tmp_cidr = atoi(chr_cidr + 1); /* Invalid CIDR, treat as single host */ if (tmp_cidr > 0 || tmp_cidr < cidr) cidr = tmp_cidr; - /* Remove and then replace the / so that NetworkAddress works on the IP portion */ - *chr_cidr = '\0'; - mask_address = NetworkAddress(netmask, 0, this->address.ss_family); - *chr_cidr = '/'; + /* Remove the / so that NetworkAddress works on the IP portion */ + std::string ip_str(netmask, chr_cidr - netmask); + mask_address = NetworkAddress(ip_str.c_str(), 0, this->address.ss_family); } else { mask_address = NetworkAddress(netmask, 0, this->address.ss_family); } @@ -235,7 +232,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * seprintf(port_name, lastof(port_name), "%u", this->GetPort()); bool reset_hostname = false; - /* Setting both hostname to NULL and port to 0 is not allowed. + /* Setting both hostname to nullptr and port to 0 is not allowed. * As port 0 means bind to any port, the other must mean that * we want to bind to 'all' IPs. */ if (StrEmpty(this->hostname) && this->address_length == 0 && this->GetPort() == 0) { @@ -245,7 +242,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * strecpy(this->hostname, fam == AF_INET ? "0.0.0.0" : "::", lastof(this->hostname)); } - int e = getaddrinfo(StrEmpty(this->hostname) ? NULL : this->hostname, port_name, &hints, &ai); + int e = getaddrinfo(StrEmpty(this->hostname) ? nullptr : this->hostname, port_name, &hints, &ai); if (reset_hostname) strecpy(this->hostname, "", lastof(this->hostname)); @@ -258,18 +255,18 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * } SOCKET sock = INVALID_SOCKET; - for (struct addrinfo *runp = ai; runp != NULL; runp = runp->ai_next) { + for (struct addrinfo *runp = ai; runp != nullptr; runp = runp->ai_next) { /* When we are binding to multiple sockets, make sure we do not * connect to one with exactly the same address twice. That's * of course totally unneeded ;) */ - if (sockets != NULL) { + if (sockets != nullptr) { NetworkAddress address(runp->ai_addr, (int)runp->ai_addrlen); if (sockets->Contains(address)) continue; } sock = func(runp); if (sock == INVALID_SOCKET) continue; - if (sockets == NULL) { + if (sockets == nullptr) { this->address_length = (int)runp->ai_addrlen; assert(sizeof(this->address) >= runp->ai_addrlen); memcpy(&this->address, runp->ai_addr, runp->ai_addrlen); @@ -326,7 +323,7 @@ SOCKET NetworkAddress::Connect() { DEBUG(net, 1, "Connecting to %s", this->GetAddressAsString()); - return this->Resolve(AF_UNSPEC, SOCK_STREAM, AI_ADDRCONFIG, NULL, ConnectLoopProc); + return this->Resolve(AF_UNSPEC, SOCK_STREAM, AI_ADDRCONFIG, nullptr, ConnectLoopProc); } /** @@ -389,9 +386,9 @@ static SOCKET ListenLoopProc(addrinfo *runp) */ void NetworkAddress::Listen(int socktype, SocketList *sockets) { - assert(sockets != NULL); + assert(sockets != nullptr); - /* Setting both hostname to NULL and port to 0 is not allowed. + /* Setting both hostname to nullptr and port to 0 is not allowed. * As port 0 means bind to any port, the other must mean that * we want to bind to 'all' IPs. */ if (this->address_length == 0 && this->address.ss_family == AF_UNSPEC && @@ -433,5 +430,3 @@ void NetworkAddress::Listen(int socktype, SocketList *sockets) default: return "unsupported"; } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/address.h b/src/network/core/address.h index 9fd40eaeef..2f27a083ac 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -17,11 +17,9 @@ #include "../../string_func.h" #include "../../core/smallmap_type.hpp" -#ifdef ENABLE_NETWORK - class NetworkAddress; -typedef SmallVector NetworkAddressList; ///< Type for a list of addresses. -typedef SmallMap SocketList; ///< Type for a mapping between address and socket. +typedef std::vector NetworkAddressList; ///< Type for a list of addresses. +typedef SmallMap SocketList; ///< Type for a mapping between address and socket. /** * Wrapper for (un)resolved network addresses; there's no reason to transform @@ -86,22 +84,13 @@ public: if (*hostname == '[') hostname++; strecpy(this->hostname, StrEmpty(hostname) ? "" : hostname, lastof(this->hostname)); char *tmp = strrchr(this->hostname, ']'); - if (tmp != NULL) *tmp = '\0'; + if (tmp != nullptr) *tmp = '\0'; memset(&this->address, 0, sizeof(this->address)); this->address.ss_family = family; this->SetPort(port); } - /** - * Make a clone of another address - * @param address the address to clone - */ - NetworkAddress(const NetworkAddress &address) - { - memcpy(this, &address, sizeof(*this)); - } - const char *GetHostname(); void GetAddressAsString(char *buffer, const char *last, bool with_family = true); const char *GetAddressAsString(bool with_family = true); @@ -131,7 +120,7 @@ public: } bool IsFamily(int family); - bool IsInNetmask(char *netmask); + bool IsInNetmask(const char *netmask); /** * Compare the address of this class with the address of another. @@ -192,5 +181,4 @@ public: static const char *AddressFamilyAsString(int family); }; -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_ADDRESS_H */ diff --git a/src/network/core/core.cpp b/src/network/core/core.cpp index c8db860dd5..1726e4176e 100644 --- a/src/network/core/core.cpp +++ b/src/network/core/core.cpp @@ -11,8 +11,6 @@ * @file core.cpp Functions used to initialize/shut down the core network */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../../debug.h" #include "os_abstraction.h" @@ -21,48 +19,12 @@ #include "../../safeguards.h" -#ifdef __MORPHOS__ -/* the library base is required here */ -struct Library *SocketBase = NULL; -#endif - /** * Initializes the network core (as that is needed for some platforms * @return true if the core has been initialized, false otherwise */ bool NetworkCoreInitialize() { -#if defined(__MORPHOS__) || defined(__AMIGA__) - /* - * IMPORTANT NOTE: SocketBase needs to be initialized before we use _any_ - * network related function, else: crash. - */ - DEBUG(net, 3, "[core] loading bsd socket library"); - SocketBase = OpenLibrary("bsdsocket.library", 4); - if (SocketBase == NULL) { - DEBUG(net, 0, "[core] can't open bsdsocket.library version 4, network unavailable"); - return false; - } - -#if defined(__AMIGA__) - /* for usleep() implementation (only required for legacy AmigaOS builds) */ - TimerPort = CreateMsgPort(); - if (TimerPort != NULL) { - TimerRequest = (struct timerequest*)CreateIORequest(TimerPort, sizeof(struct timerequest); - if (TimerRequest != NULL) { - if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)TimerRequest, 0) == 0) { - TimerBase = TimerRequest->tr_node.io_Device; - if (TimerBase == NULL) { - /* free resources... */ - DEBUG(net, 0, "[core] can't initialize timer, network unavailable"); - return false; - } - } - } - } -#endif /* __AMIGA__ */ -#endif /* __MORPHOS__ / __AMIGA__ */ - /* Let's load the network in windows */ #ifdef _WIN32 { @@ -83,17 +45,6 @@ bool NetworkCoreInitialize() */ void NetworkCoreShutdown() { -#if defined(__MORPHOS__) || defined(__AMIGA__) - /* free allocated resources */ -#if defined(__AMIGA__) - if (TimerBase != NULL) CloseDevice((struct IORequest*)TimerRequest); // XXX This smells wrong - if (TimerRequest != NULL) DeleteIORequest(TimerRequest); - if (TimerPort != NULL) DeleteMsgPort(TimerPort); -#endif - - if (SocketBase != NULL) CloseLibrary(SocketBase); -#endif - #if defined(_WIN32) WSACleanup(); #endif @@ -127,5 +78,3 @@ void NetworkSocketHandler::ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf) grf->md5sum[j] = p->Recv_uint8(); } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/core.h b/src/network/core/core.h index a250dbb081..1536c08a7a 100644 --- a/src/network/core/core.h +++ b/src/network/core/core.h @@ -17,8 +17,6 @@ #include "../../newgrf_config.h" #include "config.h" -#ifdef ENABLE_NETWORK - bool NetworkCoreInitialize(); void NetworkCoreShutdown(); @@ -80,6 +78,4 @@ public: void SendCompanyInformation(Packet *p, const struct Company *c, const struct NetworkCompanyStats *stats, uint max_len = NETWORK_COMPANY_NAME_LENGTH); }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_CORE_H */ diff --git a/src/network/core/game.h b/src/network/core/game.h index a9da29118e..57eba5812f 100644 --- a/src/network/core/game.h +++ b/src/network/core/game.h @@ -19,8 +19,6 @@ #include "../../newgrf_config.h" #include "../../date_type.h" -#ifdef ENABLE_NETWORK - /** * The game information that is not generated on-the-fly and has to * be sent to the clients. @@ -58,6 +56,4 @@ struct NetworkGameInfo : NetworkServerGameInfo { const char * GetNetworkRevisionString(); -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_GAME_H */ diff --git a/src/network/core/host.cpp b/src/network/core/host.cpp index 216839032b..04247d99c9 100644 --- a/src/network/core/host.cpp +++ b/src/network/core/host.cpp @@ -9,8 +9,6 @@ /** @file host.cpp Functions related to getting host specific data (IPs). */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../../debug.h" #include "address.h" @@ -24,7 +22,7 @@ */ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast); -#if defined(BEOS_NET_SERVER) || defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */ +#if defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */ /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */ extern "C" int _netstat(int fd, char **output, int verbose); @@ -47,7 +45,7 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BE return; } - char *output_pointer = NULL; + char *output_pointer = nullptr; int output_length = _netstat(sock, &output_pointer, 1); if (output_length < 0) { DEBUG(net, 0, "[core] error running _netstat"); @@ -78,7 +76,7 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BE memset(&address, 0, sizeof(address)); ((sockaddr_in*)&address)->sin_addr.s_addr = htonl(ip | ~netmask); NetworkAddress addr(address, sizeof(sockaddr)); - if (!broadcast->Contains(addr)) *broadcast->Append() = addr; + if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr); } if (read < 0) { break; @@ -96,13 +94,13 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GE if (getifaddrs(&ifap) != 0) return; - for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + for (ifa = ifap; ifa != nullptr; ifa = ifa->ifa_next) { if (!(ifa->ifa_flags & IFF_BROADCAST)) continue; - if (ifa->ifa_broadaddr == NULL) continue; + if (ifa->ifa_broadaddr == nullptr) continue; if (ifa->ifa_broadaddr->sa_family != AF_INET) continue; NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr)); - if (!broadcast->Contains(addr)) *broadcast->Append() = addr; + if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr); } freeifaddrs(ifap); } @@ -118,7 +116,7 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Wi INTERFACE_INFO *ifo = CallocT(num); for (;;) { - if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, ifo, num * sizeof(*ifo), &len, NULL, NULL) == 0) break; + if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, nullptr, 0, ifo, num * sizeof(*ifo), &len, nullptr, nullptr) == 0) break; free(ifo); if (WSAGetLastError() != WSAEFAULT) { closesocket(sock); @@ -138,7 +136,7 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Wi memcpy(&address, &ifo[j].iiAddress.Address, sizeof(sockaddr)); ((sockaddr_in*)&address)->sin_addr.s_addr = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr; NetworkAddress addr(address, sizeof(sockaddr)); - if (!broadcast->Contains(addr)) *broadcast->Append() = addr; + if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr); } free(ifo); @@ -176,7 +174,7 @@ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // !G (r.ifr_flags & IFF_BROADCAST) && ioctl(sock, SIOCGIFBRDADDR, &r) != -1) { NetworkAddress addr(&r.ifr_broadaddr, sizeof(sockaddr)); - if (!broadcast->Contains(addr)) *broadcast->Append() = addr; + if (std::none_of(broadcast->begin(), broadcast->end(), [&addr](NetworkAddress const& elem) -> bool { return elem == addr; })) broadcast->push_back(addr); } } @@ -202,10 +200,8 @@ void NetworkFindBroadcastIPs(NetworkAddressList *broadcast) /* Now display to the debug all the detected ips */ DEBUG(net, 3, "Detected broadcast addresses:"); int i = 0; - for (NetworkAddress *addr = broadcast->Begin(); addr != broadcast->End(); addr++) { - addr->SetPort(NETWORK_DEFAULT_PORT); - DEBUG(net, 3, "%d) %s", i++, addr->GetHostname()); + for (NetworkAddress &addr : *broadcast) { + addr.SetPort(NETWORK_DEFAULT_PORT); + DEBUG(net, 3, "%d) %s", i++, addr.GetHostname()); } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index 32c6cffff2..df4bed425f 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -18,8 +18,6 @@ /* Include standard stuff per OS */ -#ifdef ENABLE_NETWORK - /* Windows stuff */ #if defined(_WIN32) #include @@ -33,6 +31,11 @@ /* Windows has some different names for some types */ typedef unsigned long in_addr_t; +/* Handle cross-compilation with --build=*-*-cygwin --host=*-*-mingw32 */ +#if defined(__MINGW32__) && !defined(AI_ADDRCONFIG) +# define AI_ADDRCONFIG 0x00000400 +#endif + #if !(defined(__MINGW32__) || defined(__CYGWIN__)) /* Windows has some different names for some types */ typedef SSIZE_T ssize_t; @@ -48,50 +51,34 @@ typedef unsigned long in_addr_t; # endif # define SOCKET int # define INVALID_SOCKET -1 -# if !defined(__MORPHOS__) && !defined(__AMIGA__) -# define ioctlsocket ioctl -# if !defined(BEOS_NET_SERVER) -# define closesocket close -# endif -# define GET_LAST_ERROR() (errno) -# endif +# define ioctlsocket ioctl +# define closesocket close +# define GET_LAST_ERROR() (errno) /* Need this for FIONREAD on solaris */ # define BSD_COMP /* Includes needed for UNIX-like systems */ # include # include -# if defined(__BEOS__) && defined(BEOS_NET_SERVER) -# include -# include /* snooze() */ -# include - typedef unsigned long in_addr_t; -# define INADDR_NONE INADDR_BROADCAST -# else -# include -# include -# include -# include -# include +# include +# include +# include +# include +# include /* According to glibc/NEWS, appeared in glibc-2.3. */ -# if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__HAIKU__) && !defined(__INNOTEK_LIBC__) \ - && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX) +# if !defined(__sgi__) && !defined(SUNOS) && !defined(__INNOTEK_LIBC__) \ + && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX) /* If for any reason ifaddrs.h does not exist on your system, comment out * the following two lines and an alternative way will be used to fetch * the list of IPs from the system. */ -# include -# define HAVE_GETIFADDRS -# endif -# if !defined(INADDR_NONE) -# define INADDR_NONE 0xffffffff -# endif -# if defined(__BEOS__) && !defined(BEOS_NET_SERVER) - /* needed on Zeta */ -# include -# endif -# endif /* BEOS_NET_SERVER */ +# include +# define HAVE_GETIFADDRS +# endif +# if !defined(INADDR_NONE) +# define INADDR_NONE 0xffffffff +# endif -# if !defined(__BEOS__) && defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1) +# if defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1) typedef uint32_t in_addr_t; # endif @@ -100,14 +87,6 @@ typedef unsigned long in_addr_t; # include #endif /* UNIX */ -#ifdef __BEOS__ - typedef int socklen_t; -#endif - -#ifdef __HAIKU__ - #define IPV6_V6ONLY 27 -#endif - /* OS/2 stuff */ #if defined(__OS2__) # define SOCKET int @@ -164,39 +143,6 @@ typedef unsigned long in_addr_t; #endif /* OS/2 */ -/* MorphOS and Amiga stuff */ -#if defined(__MORPHOS__) || defined(__AMIGA__) -# include -# include /* required for Open/CloseLibrary() */ - /* MorphOS defines his network functions with UBYTE arrays while we - * use char arrays. This gives tons of unneeded warnings */ -# define UBYTE char -# if defined(__MORPHOS__) -# include /* FIO* defines */ -# include /* SIO* defines */ -# include -# else /* __AMIGA__ */ -# include -# endif - -/* Make the names compatible */ -# define closesocket(s) CloseSocket(s) -# define GET_LAST_ERROR() Errno() -# define ioctlsocket(s, request, status) IoctlSocket((LONG)s, (ULONG)request, (char*)status) -# define ioctl ioctlsocket - - typedef unsigned int in_addr_t; - typedef long socklen_t; - extern struct Library *SocketBase; - -# ifdef __AMIGA__ - /* for usleep() implementation */ - extern struct Device *TimerBase; - extern struct MsgPort *TimerPort; - extern struct timerequest *TimerRequest; -# endif -#endif /* __MORPHOS__ || __AMIGA__ */ - /** * Try to set the socket into non-blocking mode. * @param d The socket to set the non-blocking more for. @@ -209,11 +155,7 @@ static inline bool SetNonBlocking(SOCKET d) #else int nonblocking = 1; #endif -#if (defined(__BEOS__) && defined(BEOS_NET_SERVER)) - return setsockopt(d, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(nonblocking)) == 0; -#else return ioctlsocket(d, FIONBIO, &nonblocking) == 0; -#endif } /** @@ -224,19 +166,13 @@ static inline bool SetNonBlocking(SOCKET d) static inline bool SetNoDelay(SOCKET d) { /* XXX should this be done at all? */ -#if !defined(BEOS_NET_SERVER) /* not implemented on BeOS net_server */ int b = 1; /* The (const char*) cast is needed for windows */ return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; -#else - return true; -#endif } /* Make sure these structures have the size we expect them to be */ assert_compile(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. assert_compile(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes. -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_OS_ABSTRACTION_H */ diff --git a/src/network/core/packet.cpp b/src/network/core/packet.cpp index 7548132e0b..fda8fdfeb7 100644 --- a/src/network/core/packet.cpp +++ b/src/network/core/packet.cpp @@ -11,8 +11,6 @@ * @file packet.cpp Basic functions to create, fill and read packets. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../../string_func.h" @@ -26,10 +24,10 @@ */ Packet::Packet(NetworkSocketHandler *cs) { - assert(cs != NULL); + assert(cs != nullptr); this->cs = cs; - this->next = NULL; + this->next = nullptr; this->pos = 0; // We start reading from here this->size = 0; this->buffer = MallocT(SEND_MTU); @@ -41,8 +39,8 @@ Packet::Packet(NetworkSocketHandler *cs) */ Packet::Packet(PacketType type) { - this->cs = NULL; - this->next = NULL; + this->cs = nullptr; + this->next = nullptr; /* Skip the size so we can write that in before sending the packet */ this->pos = 0; @@ -64,7 +62,7 @@ Packet::~Packet() */ void Packet::PrepareToSend() { - assert(this->cs == NULL && this->next == NULL); + assert(this->cs == nullptr && this->next == nullptr); this->buffer[0] = GB(this->size, 0, 8); this->buffer[1] = GB(this->size, 8, 8); @@ -151,7 +149,7 @@ void Packet::Send_uint64(uint64 data) */ void Packet::Send_string(const char *data) { - assert(data != NULL); + assert(data != nullptr); /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */ assert(this->size + strlen(data) + 1 <= SEND_MTU); while ((this->buffer[this->size++] = *data++) != '\0') {} @@ -189,7 +187,7 @@ bool Packet::CanReadFromPacket(uint bytes_to_read) */ void Packet::ReadRawPacketSize() { - assert(this->cs != NULL && this->next == NULL); + assert(this->cs != nullptr && this->next == nullptr); this->size = (PacketSize)this->buffer[0]; this->size += (PacketSize)this->buffer[1] << 8; } @@ -310,5 +308,3 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set str_validate(bufp, last, settings); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/packet.h b/src/network/core/packet.h index 7f344d0179..7b4bf26f37 100644 --- a/src/network/core/packet.h +++ b/src/network/core/packet.h @@ -18,8 +18,6 @@ #include "core.h" #include "../../string_type.h" -#ifdef ENABLE_NETWORK - typedef uint16 PacketSize; ///< Size of the whole packet. typedef uint8 PacketType; ///< Identifier for the packet @@ -87,6 +85,4 @@ public: void Recv_string(char *buffer, size_t size, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_PACKET_H */ diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index 790941fc01..63d004a8fd 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -11,8 +11,6 @@ * @file tcp.cpp Basic functions to receive and send TCP packets. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../../debug.h" @@ -26,7 +24,7 @@ */ NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) : NetworkSocketHandler(), - packet_queue(NULL), packet_recv(NULL), + packet_queue(nullptr), packet_recv(nullptr), sock(s), writable(false) { } @@ -45,13 +43,13 @@ NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error) NetworkSocketHandler::CloseConnection(error); /* Free all pending and partially received packets */ - while (this->packet_queue != NULL) { + while (this->packet_queue != nullptr) { Packet *p = this->packet_queue->next; delete this->packet_queue; this->packet_queue = p; } delete this->packet_recv; - this->packet_recv = NULL; + this->packet_recv = nullptr; return NETWORK_RECV_STATUS_OKAY; } @@ -65,7 +63,7 @@ NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error) void NetworkTCPSocketHandler::SendPacket(Packet *packet) { Packet *p; - assert(packet != NULL); + assert(packet != nullptr); packet->PrepareToSend(); @@ -76,12 +74,12 @@ void NetworkTCPSocketHandler::SendPacket(Packet *packet) /* Locate last packet buffered for the client */ p = this->packet_queue; - if (p == NULL) { + if (p == nullptr) { /* No packets yet */ this->packet_queue = packet; } else { /* Skip to the last packet */ - while (p->next != NULL) p = p->next; + while (p->next != nullptr) p = p->next; p->next = packet; } } @@ -106,7 +104,7 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) if (!this->IsConnected()) return SPS_CLOSED; p = this->packet_queue; - while (p != NULL) { + while (p != nullptr) { res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0); if (res == -1) { int err = GET_LAST_ERROR(); @@ -144,15 +142,15 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) /** * Receives a packet for the given client - * @return The received packet (or NULL when it didn't receive one) + * @return The received packet (or nullptr when it didn't receive one) */ Packet *NetworkTCPSocketHandler::ReceivePacket() { ssize_t res; - if (!this->IsConnected()) return NULL; + if (!this->IsConnected()) return nullptr; - if (this->packet_recv == NULL) { + if (this->packet_recv == nullptr) { this->packet_recv = new Packet(this); } @@ -169,15 +167,15 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); this->CloseConnection(); - return NULL; + return nullptr; } /* Connection would block, so stop for now */ - return NULL; + return nullptr; } if (res == 0) { /* Client/server has left */ this->CloseConnection(); - return NULL; + return nullptr; } p->pos += res; } @@ -187,7 +185,7 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() if (p->size > SEND_MTU) { this->CloseConnection(); - return NULL; + return nullptr; } } @@ -200,22 +198,22 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); this->CloseConnection(); - return NULL; + return nullptr; } /* Connection would block */ - return NULL; + return nullptr; } if (res == 0) { /* Client/server has left */ this->CloseConnection(); - return NULL; + return nullptr; } p->pos += res; } /* Prepare for receiving a new packet */ - this->packet_recv = NULL; + this->packet_recv = nullptr; p->PrepareToRead(); return p; @@ -238,14 +236,8 @@ bool NetworkTCPSocketHandler::CanSendReceive() FD_SET(this->sock, &write_fd); tv.tv_sec = tv.tv_usec = 0; // don't block at all. -#if !defined(__MORPHOS__) && !defined(__AMIGA__) - if (select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv) < 0) return false; -#else - if (WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL) < 0) return false; -#endif + if (select(FD_SETSIZE, &read_fd, &write_fd, nullptr, &tv) < 0) return false; this->writable = !!FD_ISSET(this->sock, &write_fd); return FD_ISSET(this->sock, &read_fd) != 0; } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index b736189b4e..451b93071c 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -17,8 +17,6 @@ #include "address.h" #include "packet.h" -#ifdef ENABLE_NETWORK - /** The states of sending the packets. */ enum SendPacketsState { SPS_CLOSED, ///< The connection got closed. @@ -42,7 +40,7 @@ public: */ bool IsConnected() const { return this->sock != INVALID_SOCKET; } - virtual NetworkRecvStatus CloseConnection(bool error = true); + NetworkRecvStatus CloseConnection(bool error = true) override; virtual void SendPacket(Packet *packet); SendPacketsState SendPackets(bool closing_down = false); @@ -54,7 +52,7 @@ public: * Whether there is something pending in the send queue. * @return true when something is pending in the send queue. */ - bool HasSendQueue() { return this->packet_queue != NULL; } + bool HasSendQueue() { return this->packet_queue != nullptr; } NetworkTCPSocketHandler(SOCKET s = INVALID_SOCKET); ~NetworkTCPSocketHandler(); @@ -65,7 +63,6 @@ public: */ class TCPConnecter { private: - class ThreadObject *thread; ///< Thread used to create the TCP connection bool connected; ///< Whether we succeeded in making the connection bool aborted; ///< Whether we bailed out (i.e. connection making failed) bool killed; ///< Whether we got killed @@ -73,7 +70,7 @@ private: void Connect(); - static void ThreadEntry(void *param); + static void ThreadEntry(TCPConnecter *param); protected: /** Address we're connecting to */ @@ -99,6 +96,4 @@ public: static void KillAll(); }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_TCP_H */ diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp index 284ceda9b1..98ef0f0a07 100644 --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -11,8 +11,6 @@ * @file tcp_admin.cpp Basic functions to receive and send TCP packets to and from the admin network. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../network_internal.h" @@ -117,7 +115,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) NetworkRecvStatus NetworkAdminSocketHandler::ReceivePackets() { Packet *p; - while ((p = this->ReceivePacket()) != NULL) { + while ((p = this->ReceivePacket()) != nullptr) { NetworkRecvStatus res = this->HandlePacket(p); if (res != NETWORK_RECV_STATUS_OKAY) return res; } @@ -172,5 +170,3 @@ NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_NAMES(Packet *p) NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_LOGGING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_LOGGING); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON_END(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON_END); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PONG(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PONG); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h index e141a191a8..7bcc878403 100644 --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -19,8 +19,6 @@ #include "../network_type.h" #include "../../core/pool_type.hpp" -#ifdef ENABLE_NETWORK - /** * Enum with types of TCP packets specific to the admin network. * This protocol may only be extended to ensure stability. @@ -483,7 +481,7 @@ protected: NetworkRecvStatus HandlePacket(Packet *p); public: - NetworkRecvStatus CloseConnection(bool error = true); + NetworkRecvStatus CloseConnection(bool error = true) override; NetworkAdminSocketHandler(SOCKET s); ~NetworkAdminSocketHandler(); @@ -500,6 +498,4 @@ public: } }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_TCP_ADMIN_H */ diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp index 2dc7898824..13330108aa 100644 --- a/src/network/core/tcp_connect.cpp +++ b/src/network/core/tcp_connect.cpp @@ -11,17 +11,15 @@ * @file tcp_connect.cpp Basic functions to create connections without blocking. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" -#include "../../thread/thread.h" +#include "../../thread.h" #include "tcp.h" #include "../../safeguards.h" /** List of connections that are currently being created */ -static SmallVector _tcp_connecters; +static std::vector _tcp_connecters; /** * Create a new connecter for the given address @@ -34,8 +32,8 @@ TCPConnecter::TCPConnecter(const NetworkAddress &address) : sock(INVALID_SOCKET), address(address) { - *_tcp_connecters.Append() = this; - if (!ThreadObject::New(TCPConnecter::ThreadEntry, this, &this->thread, "ottd:tcp")) { + _tcp_connecters.push_back(this); + if (!StartNewThread(nullptr, "ottd:tcp", &TCPConnecter::ThreadEntry, this)) { this->Connect(); } } @@ -55,9 +53,9 @@ void TCPConnecter::Connect() * Entry point for the new threads. * @param param the TCPConnecter instance to call Connect on. */ -/* static */ void TCPConnecter::ThreadEntry(void *param) +/* static */ void TCPConnecter::ThreadEntry(TCPConnecter *param) { - static_cast(param)->Connect(); + param->Connect(); } /** @@ -68,22 +66,22 @@ void TCPConnecter::Connect() */ /* static */ void TCPConnecter::CheckCallbacks() { - for (TCPConnecter **iter = _tcp_connecters.Begin(); iter < _tcp_connecters.End(); /* nothing */) { + for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) { TCPConnecter *cur = *iter; if ((cur->connected || cur->aborted) && cur->killed) { - _tcp_connecters.Erase(iter); + iter = _tcp_connecters.erase(iter); if (cur->sock != INVALID_SOCKET) closesocket(cur->sock); delete cur; continue; } if (cur->connected) { - _tcp_connecters.Erase(iter); + iter = _tcp_connecters.erase(iter); cur->OnConnect(cur->sock); delete cur; continue; } if (cur->aborted) { - _tcp_connecters.Erase(iter); + iter = _tcp_connecters.erase(iter); cur->OnFailure(); delete cur; continue; @@ -95,7 +93,5 @@ void TCPConnecter::Connect() /** Kill all connection attempts. */ /* static */ void TCPConnecter::KillAll() { - for (TCPConnecter **iter = _tcp_connecters.Begin(); iter != _tcp_connecters.End(); iter++) (*iter)->killed = true; + for (TCPConnecter *conn : _tcp_connecters) conn->killed = true; } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp index fc22c4491f..ee8baf48e0 100644 --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -11,8 +11,6 @@ * @file tcp_content.cpp Basic functions to receive and send Content packets. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #ifndef OPENTTD_MSU #include "../../textfile_gui.h" @@ -49,8 +47,8 @@ void ContentInfo::TransferFrom(ContentInfo *other) free(this->dependencies); free(this->tags); memcpy(this, other, sizeof(ContentInfo)); - other->dependencies = NULL; - other->tags = NULL; + other->dependencies = nullptr; + other->tags = nullptr; } } @@ -100,11 +98,11 @@ bool ContentInfo::IsValid() const /** * Search a textfile file next to this file in the content list. * @param type The type of the textfile to search for. - * @return The filename for the textfile, \c NULL otherwise. + * @return The filename for the textfile, \c nullptr otherwise. */ const char *ContentInfo::GetTextfile(TextfileType type) const { - if (this->state == INVALID) return NULL; + if (this->state == INVALID) return nullptr; const char *tmp; switch (this->type) { default: NOT_REACHED(); @@ -122,7 +120,7 @@ const char *ContentInfo::GetTextfile(TextfileType type) const break; case CONTENT_TYPE_NEWGRF: { const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum); - tmp = gc != NULL ? gc->filename : NULL; + tmp = gc != nullptr ? gc->filename : nullptr; break; } case CONTENT_TYPE_BASE_GRAPHICS: @@ -140,7 +138,7 @@ const char *ContentInfo::GetTextfile(TextfileType type) const tmp = FindScenario(this, true); break; } - if (tmp == NULL) return NULL; + if (tmp == nullptr) return nullptr; return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp); } #endif /* OPENTTD_MSU */ @@ -211,7 +209,7 @@ bool NetworkContentSocketHandler::ReceivePackets() Packet *p; static const int MAX_PACKETS_TO_RECEIVE = 42; int i = MAX_PACKETS_TO_RECEIVE; - while (--i != 0 && (p = this->ReceivePacket()) != NULL) { + while (--i != 0 && (p = this->ReceivePacket()) != nullptr) { bool cont = this->HandlePacket(p); delete p; if (!cont) return true; @@ -266,5 +264,3 @@ Subdirectory GetContentInfoSubDir(ContentType type) } } #endif /* OPENTTD_MSU */ - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h index a506439da9..689de7a018 100644 --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -19,8 +19,6 @@ #include "packet.h" #include "../../debug.h" -#ifdef ENABLE_NETWORK - /** The values in the enum are important; they are used as database 'keys' */ enum ContentType { CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types @@ -100,7 +98,7 @@ struct ContentInfo { class NetworkContentSocketHandler : public NetworkTCPSocketHandler { protected: NetworkAddress client_addr; ///< The address we're connected to. - virtual void Close(); + void Close() override; bool ReceiveInvalidPacket(PacketContentType type); @@ -213,6 +211,4 @@ public: Subdirectory GetContentInfoSubDir(ContentType type); #endif /* OPENTTD_MSU */ -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_TCP_CONTENT_H */ diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index caa378fc4c..6d69d10d25 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -11,8 +11,6 @@ * @file tcp_game.cpp Basic functions to receive and send TCP packets for game purposes. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../network.h" @@ -28,7 +26,7 @@ * Create a new socket for the game connection. * @param s The socket to connect with. */ -NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(NULL), client_id(INVALID_CLIENT_ID), +NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(nullptr), client_id(INVALID_CLIENT_ID), last_frame(_frame_counter), last_frame_server(_frame_counter), last_packet(_realtime_tick) { this->sock = s; @@ -136,7 +134,7 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p) NetworkRecvStatus NetworkGameSocketHandler::ReceivePackets() { Packet *p; - while ((p = this->ReceivePacket()) != NULL) { + while ((p = this->ReceivePacket()) != nullptr) { NetworkRecvStatus res = HandlePacket(p); delete p; if (res != NETWORK_RECV_STATUS_OKAY) return res; @@ -199,5 +197,3 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p) { ret NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MOVE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_UPDATE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CONFIG_UPDATE); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index 5c6cb5c34d..eb8881adc0 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -19,8 +19,6 @@ #include "../network_type.h" #include "../../core/pool_type.hpp" -#ifdef ENABLE_NETWORK - /** * Enum with all types of TCP packets. * For the exact meaning, look at #NetworkGameSocketHandler. @@ -132,12 +130,12 @@ struct CommandPacket; /** A queue of CommandPackets. */ class CommandQueue { CommandPacket *first; ///< The first packet in the queue. - CommandPacket *last; ///< The last packet in the queue; only valid when first != NULL. + CommandPacket *last; ///< The last packet in the queue; only valid when first != nullptr. uint count; ///< The number of items in the queue. public: /** Initialise the command queue. */ - CommandQueue() : first(NULL), last(NULL), count(0) {} + CommandQueue() : first(nullptr), last(nullptr), count(0) {} /** Clear the command queue. */ ~CommandQueue() { this->Free(); } void Append(CommandPacket *p); @@ -524,7 +522,7 @@ public: CommandQueue incoming_queue; ///< The command-queue awaiting handling uint last_packet; ///< Time we received the last frame. - NetworkRecvStatus CloseConnection(bool error = true); + NetworkRecvStatus CloseConnection(bool error = true) override; /** * Close the network connection due to the given status. @@ -539,7 +537,7 @@ public: */ inline void SetInfo(NetworkClientInfo *info) { - assert(info != NULL && this->info == NULL); + assert(info != nullptr && this->info == nullptr); this->info = info; } @@ -558,6 +556,4 @@ public: void SendCommand(Packet *p, const CommandPacket *cp); }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_TCP_GAME_H */ diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index aec198bf55..1162324028 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -11,8 +11,6 @@ * @file tcp_http.cpp Basic functions to receive and send HTTP TCP packets. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../../debug.h" #include "../../rev.h" @@ -23,7 +21,7 @@ #include "../../safeguards.h" /** List of open HTTP connections. */ -static SmallVector _http_connections; +static std::vector _http_connections; /** * Start the querying @@ -45,11 +43,11 @@ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s, redirect_depth(depth), sock(s) { - size_t bufferSize = strlen(url) + strlen(host) + strlen(GetNetworkRevisionString()) + (data == NULL ? 0 : strlen(data)) + 128; + size_t bufferSize = strlen(url) + strlen(host) + strlen(GetNetworkRevisionString()) + (data == nullptr ? 0 : strlen(data)) + 128; char *buffer = AllocaM(char, bufferSize); DEBUG(net, 7, "[tcp/http] requesting %s%s", host, url); - if (data != NULL) { + if (data != nullptr) { seprintf(buffer, buffer + bufferSize - 1, "POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s\r\n", url, host, GetNetworkRevisionString(), (int)strlen(data), data); } else { seprintf(buffer, buffer + bufferSize - 1, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\n\r\n", url, host, GetNetworkRevisionString()); @@ -65,7 +63,7 @@ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s, return; } - *_http_connections.Append() = this; + _http_connections.push_back(this); } /** Free whatever needs to be freed. */ @@ -110,7 +108,7 @@ static const char * const LOCATION = "Location: "; ///< Header for l int NetworkHTTPSocketHandler::HandleHeader() { assert(strlen(HTTP_1_0) == strlen(HTTP_1_1)); - assert(strstr(this->recv_buffer, END_OF_HEADER) != NULL); + assert(strstr(this->recv_buffer, END_OF_HEADER) != nullptr); /* We expect a HTTP/1.[01] reply */ if (strncmp(this->recv_buffer, HTTP_1_0, strlen(HTTP_1_0)) != 0 && @@ -124,7 +122,7 @@ int NetworkHTTPSocketHandler::HandleHeader() /* Get the length of the document to receive */ char *length = strcasestr(this->recv_buffer, CONTENT_LENGTH); - if (length == NULL) return_error("[tcp/http] missing 'content-length' header"); + if (length == nullptr) return_error("[tcp/http] missing 'content-length' header"); /* Skip the header */ length += strlen(CONTENT_LENGTH); @@ -165,7 +163,7 @@ int NetworkHTTPSocketHandler::HandleHeader() /* Redirect to other URL */ char *uri = strcasestr(this->recv_buffer, LOCATION); - if (uri == NULL) return_error("[tcp/http] missing 'location' header for redirect"); + if (uri == nullptr) return_error("[tcp/http] missing 'location' header for redirect"); uri += strlen(LOCATION); @@ -180,7 +178,7 @@ int NetworkHTTPSocketHandler::HandleHeader() if (ret != 0) return ret; /* We've relinquished control of data now. */ - this->data = NULL; + this->data = nullptr; /* Restore the header. */ *end_of_line = '\r'; @@ -197,22 +195,22 @@ int NetworkHTTPSocketHandler::HandleHeader() /* static */ int NetworkHTTPSocketHandler::Connect(char *uri, HTTPCallback *callback, const char *data, int depth) { char *hname = strstr(uri, "://"); - if (hname == NULL) return_error("[tcp/http] invalid location"); + if (hname == nullptr) return_error("[tcp/http] invalid location"); hname += 3; char *url = strchr(hname, '/'); - if (url == NULL) return_error("[tcp/http] invalid location"); + if (url == nullptr) return_error("[tcp/http] invalid location"); *url = '\0'; /* Fetch the hostname, and possible port number. */ - const char *company = NULL; - const char *port = NULL; + const char *company = nullptr; + const char *port = nullptr; ParseConnectionString(&company, &port, hname); - if (company != NULL) return_error("[tcp/http] invalid hostname"); + if (company != nullptr) return_error("[tcp/http] invalid hostname"); - NetworkAddress address(hname, port == NULL ? 80 : atoi(port)); + NetworkAddress address(hname, port == nullptr ? 80 : atoi(port)); /* Restore the URL. */ *url = '/'; @@ -248,7 +246,7 @@ int NetworkHTTPSocketHandler::Receive() if (res == 0) { if (this->recv_length != 0) return -1; - this->callback->OnReceiveData(NULL, 0); + this->callback->OnReceiveData(nullptr, 0); return 0; } @@ -263,7 +261,7 @@ int NetworkHTTPSocketHandler::Receive() char *end_of_header = strstr(this->recv_buffer, END_OF_HEADER); this->recv_buffer[end] = prev; - if (end_of_header == NULL) { + if (end_of_header == nullptr) { if (read == lengthof(this->recv_buffer)) { DEBUG(net, 0, "[tcp/http] header too big"); return -1; @@ -299,25 +297,21 @@ int NetworkHTTPSocketHandler::Receive() /* static */ void NetworkHTTPSocketHandler::HTTPReceive() { /* No connections, just bail out. */ - if (_http_connections.Length() == 0) return; + if (_http_connections.size() == 0) return; fd_set read_fd; struct timeval tv; FD_ZERO(&read_fd); - for (NetworkHTTPSocketHandler **iter = _http_connections.Begin(); iter < _http_connections.End(); iter++) { - FD_SET((*iter)->sock, &read_fd); + for (NetworkHTTPSocketHandler *handler : _http_connections) { + FD_SET(handler->sock, &read_fd); } tv.tv_sec = tv.tv_usec = 0; // don't block at all. -#if !defined(__MORPHOS__) && !defined(__AMIGA__) - int n = select(FD_SETSIZE, &read_fd, NULL, NULL, &tv); -#else - int n = WaitSelect(FD_SETSIZE, &read_fd, NULL, NULL, &tv, NULL); -#endif + int n = select(FD_SETSIZE, &read_fd, nullptr, nullptr, &tv); if (n == -1) return; - for (NetworkHTTPSocketHandler **iter = _http_connections.Begin(); iter < _http_connections.End(); /* nothing */) { + for (auto iter = _http_connections.begin(); iter < _http_connections.end(); /* nothing */) { NetworkHTTPSocketHandler *cur = *iter; if (FD_ISSET(cur->sock, &read_fd)) { @@ -327,7 +321,7 @@ int NetworkHTTPSocketHandler::Receive() if (ret <= 0) { /* Then... the connection can be closed */ cur->CloseConnection(); - _http_connections.Erase(iter); + iter = _http_connections.erase(iter); delete cur; continue; } @@ -335,5 +329,3 @@ int NetworkHTTPSocketHandler::Receive() iter++; } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_http.h b/src/network/core/tcp_http.h index 36520f1364..001942ffb7 100644 --- a/src/network/core/tcp_http.h +++ b/src/network/core/tcp_http.h @@ -16,8 +16,6 @@ #include "tcp.h" -#ifdef ENABLE_NETWORK - /** Callback for when the HTTP handler has something to tell us. */ struct HTTPCallback { /** @@ -28,9 +26,9 @@ struct HTTPCallback { /** * We're receiving data. - * @param data the received data, NULL when all data has been received. + * @param data the received data, nullptr when all data has been received. * @param length the amount of received data, 0 when all data has been received. - * @note When NULL is sent the HTTP socket handler is closed/freed. + * @note When nullptr is sent the HTTP socket handler is closed/freed. */ virtual void OnReceiveData(const char *data, size_t length) = 0; @@ -62,7 +60,7 @@ public: return this->sock != INVALID_SOCKET; } - virtual NetworkRecvStatus CloseConnection(bool error = true); + NetworkRecvStatus CloseConnection(bool error = true) override; NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback, const char *host, const char *url, const char *data, int depth); @@ -70,7 +68,7 @@ public: ~NetworkHTTPSocketHandler(); static int Connect(char *uri, HTTPCallback *callback, - const char *data = NULL, int depth = 0); + const char *data = nullptr, int depth = 0); static void HTTPReceive(); }; @@ -93,7 +91,7 @@ public: */ NetworkHTTPContentConnecter(const NetworkAddress &address, HTTPCallback *callback, const char *url, - const char *data = NULL, int depth = 0) : + const char *data = nullptr, int depth = 0) : TCPConnecter(address), callback(callback), url(stredup(url)), @@ -108,20 +106,18 @@ public: free(this->url); } - virtual void OnFailure() + void OnFailure() override { this->callback->OnFailure(); free(this->data); } - virtual void OnConnect(SOCKET s) + void OnConnect(SOCKET s) override { new NetworkHTTPSocketHandler(s, this->callback, this->address.GetHostname(), this->url, this->data, this->depth); /* We've relinquished control of data now. */ - this->data = NULL; + this->data = nullptr; } }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_TCP_HTTP_H */ diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index e6b5893324..28b6de8ace 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -20,8 +20,6 @@ #include "../../debug.h" #include "table/strings.h" -#ifdef ENABLE_NETWORK - /** * Template for TCP listeners. * @param Tsocket The class we create sockets for. @@ -56,13 +54,13 @@ public: /* Check if the client is banned */ bool banned = false; - for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) { - banned = address.IsInNetmask(*iter); + for (const auto &entry : _network_ban_list) { + banned = address.IsInNetmask(entry.c_str()); if (banned) { Packet p(Tban_packet); p.PrepareToSend(); - DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), *iter); + DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str()); if (send(s, (const char*)p.buffer, p.size, 0) < 0) { DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); @@ -113,20 +111,16 @@ public: } /* take care of listener port */ - for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) { - FD_SET(s->second, &read_fd); + for (auto &s : sockets) { + FD_SET(s.second, &read_fd); } tv.tv_sec = tv.tv_usec = 0; // don't block at all. -#if !defined(__MORPHOS__) && !defined(__AMIGA__) - if (select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv) < 0) return false; -#else - if (WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL) < 0) return false; -#endif + if (select(FD_SETSIZE, &read_fd, &write_fd, nullptr, &tv) < 0) return false; /* accept clients.. */ - for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) { - if (FD_ISSET(s->second, &read_fd)) AcceptClient(s->second); + for (auto &s : sockets) { + if (FD_ISSET(s.second, &read_fd)) AcceptClient(s.second); } /* read stuff from clients */ @@ -146,16 +140,16 @@ public: */ static bool Listen(uint16 port) { - assert(sockets.Length() == 0); + assert(sockets.size() == 0); NetworkAddressList addresses; GetBindAddresses(&addresses, port); - for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) { - address->Listen(SOCK_STREAM, &sockets); + for (NetworkAddress &address : addresses) { + address.Listen(SOCK_STREAM, &sockets); } - if (sockets.Length() == 0) { + if (sockets.size() == 0) { DEBUG(net, 0, "[server] could not start network: could not create listening socket"); NetworkError(STR_NETWORK_ERROR_SERVER_START); return false; @@ -167,16 +161,14 @@ public: /** Close the sockets we're listening on. */ static void CloseListeners() { - for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) { - closesocket(s->second); + for (auto &s : sockets) { + closesocket(s.second); } - sockets.Clear(); + sockets.clear(); DEBUG(net, 1, "[%s] closed listeners", Tsocket::GetName()); } }; template SocketList TCPListenHandler::sockets; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_TCP_LISTEN_H */ diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index d2dc15d427..853b19e1ac 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -11,8 +11,6 @@ * @file core/udp.cpp Basic functions to receive and send UDP packets. */ -#ifdef ENABLE_NETWORK - #include "../../stdafx.h" #include "../../date_func.h" #include "../../debug.h" @@ -26,16 +24,16 @@ */ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind) { - if (bind != NULL) { - for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) { - *this->bind.Append() = *addr; + if (bind != nullptr) { + for (NetworkAddress &addr : *bind) { + this->bind.push_back(addr); } } else { - /* As hostname NULL and port 0/NULL don't go well when + /* As hostname nullptr and port 0/nullptr don't go well when * resolving it we need to add an address for each of * the address families we support. */ - *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET); - *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6); + this->bind.emplace_back(nullptr, 0, AF_INET); + this->bind.emplace_back(nullptr, 0, AF_INET6); } } @@ -49,11 +47,11 @@ bool NetworkUDPSocketHandler::Listen() /* Make sure socket is closed */ this->Close(); - for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) { - addr->Listen(SOCK_DGRAM, &this->sockets); + for (NetworkAddress &addr : this->bind) { + addr.Listen(SOCK_DGRAM, &this->sockets); } - return this->sockets.Length() != 0; + return this->sockets.size() != 0; } /** @@ -61,10 +59,10 @@ bool NetworkUDPSocketHandler::Listen() */ void NetworkUDPSocketHandler::Close() { - for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { - closesocket(s->second); + for (auto &s : this->sockets) { + closesocket(s.second); } - this->sockets.Clear(); + this->sockets.clear(); } NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection(bool error) @@ -82,30 +80,28 @@ NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection(bool error) */ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast) { - if (this->sockets.Length() == 0) this->Listen(); + if (this->sockets.size() == 0) this->Listen(); - for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { + for (auto &s : this->sockets) { /* Make a local copy because if we resolve it we cannot * easily unresolve it so we can resolve it later again. */ NetworkAddress send(*recv); /* Not the same type */ - if (!send.IsFamily(s->first.GetAddress()->ss_family)) continue; + if (!send.IsFamily(s.first.GetAddress()->ss_family)) continue; p->PrepareToSend(); -#ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */ if (broadcast) { /* Enable broadcast */ unsigned long val = 1; - if (setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { + if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR()); } } -#endif /* Send the buffer */ - int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); + int res = sendto(s.second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString()); /* Check for any errors, but ignore it otherwise */ @@ -120,7 +116,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a */ void NetworkUDPSocketHandler::ReceivePackets() { - for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { + for (auto &s : this->sockets) { for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP struct sockaddr_storage client_addr; memset(&client_addr, 0, sizeof(client_addr)); @@ -129,8 +125,8 @@ void NetworkUDPSocketHandler::ReceivePackets() socklen_t client_len = sizeof(client_addr); /* Try to receive anything */ - SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket - int nbytes = recvfrom(s->second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len); + SetNonBlocking(s.second); // Some OSes seem to lose the non-blocking status of the socket + int nbytes = recvfrom(s.second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len); /* Did we get the bytes for the base header of the packet? */ if (nbytes <= 0) break; // No data, i.e. no packet @@ -180,13 +176,13 @@ void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameIn uint count = 0; /* Count number of GRFs to send information about */ - for (c = info->grfconfig; c != NULL; c = c->next) { + for (c = info->grfconfig; c != nullptr; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) count++; } p->Send_uint8 (count); // Send number of GRFs /* Send actual GRF Identifications */ - for (c = info->grfconfig; c != NULL; c = c->next) { + for (c = info->grfconfig; c != nullptr; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); } } @@ -349,5 +345,3 @@ void NetworkUDPSocketHandler::Receive_SERVER_UNREGISTER(Packet *p, NetworkAddres void NetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_NEWGRFS, client_addr); } void NetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_NEWGRFS, client_addr); } void NetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_SESSION_KEY, client_addr); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/core/udp.h b/src/network/core/udp.h index 9aa0c9dc49..9ed2705ef9 100644 --- a/src/network/core/udp.h +++ b/src/network/core/udp.h @@ -18,8 +18,6 @@ #include "game.h" #include "packet.h" -#ifdef ENABLE_NETWORK - /** Enum with all types of UDP packets. The order MUST not be changed **/ enum PacketUDPType { PACKET_UDP_CLIENT_FIND_SERVER, ///< Queries a game server for game information @@ -54,7 +52,7 @@ protected: /** The opened sockets. */ SocketList sockets; - NetworkRecvStatus CloseConnection(bool error = true); + NetworkRecvStatus CloseConnection(bool error = true) override; void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr); @@ -231,13 +229,13 @@ protected: */ virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); } public: - NetworkUDPSocketHandler(NetworkAddressList *bind = NULL); + NetworkUDPSocketHandler(NetworkAddressList *bind = nullptr); /** On destructing of this class, the socket needs to be closed */ virtual ~NetworkUDPSocketHandler() { this->Close(); } bool Listen(); - void Close(); + void Close() override; void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false); void ReceivePackets(); @@ -246,6 +244,4 @@ public: void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info); }; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CORE_UDP_H */ diff --git a/src/network/network.cpp b/src/network/network.cpp index 931d664251..e2ccee8cf4 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -11,8 +11,6 @@ #include "../stdafx.h" -#ifdef ENABLE_NETWORK - #include "../strings_func.h" #include "../command_func.h" #include "../date_func.h" @@ -59,7 +57,7 @@ bool _network_available; ///< is network mode available? bool _network_dedicated; ///< are we a dedicated server? bool _is_network_server; ///< Does this client wants to be a network-server? NetworkServerGameInfo _network_game_info; ///< Information about our game. -NetworkCompanyState *_network_company_states = NULL; ///< Statistics about some companies. +NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies. ClientID _network_own_client_id; ///< Our client identifier. ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client. bool _network_need_advertise; ///< Whether we need to advertise. @@ -122,7 +120,7 @@ NetworkClientInfo::~NetworkClientInfo() /** * Return the CI given it's client-identifier * @param client_id the ClientID to search for - * @return return a pointer to the corresponding NetworkClientInfo struct or NULL when not found + * @return return a pointer to the corresponding NetworkClientInfo struct or nullptr when not found */ /* static */ NetworkClientInfo *NetworkClientInfo::GetByClientID(ClientID client_id) { @@ -132,13 +130,13 @@ NetworkClientInfo::~NetworkClientInfo() if (ci->client_id == client_id) return ci; } - return NULL; + return nullptr; } /** * Return the client state given it's client-identifier * @param client_id the ClientID to search for - * @return return a pointer to the corresponding NetworkClientSocket struct or NULL when not found + * @return return a pointer to the corresponding NetworkClientSocket struct or nullptr when not found */ /* static */ ServerNetworkGameSocketHandler *ServerNetworkGameSocketHandler::GetByClientID(ClientID client_id) { @@ -148,7 +146,7 @@ NetworkClientInfo::~NetworkClientInfo() if (cs->client_id == client_id) return cs; } - return NULL; + return nullptr; } byte NetworkSpectatorCount() @@ -381,7 +379,7 @@ void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode) char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); - NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, NULL, buffer); + NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, nullptr, buffer); break; } @@ -544,7 +542,7 @@ void NetworkClose(bool close_admins) } ServerNetworkGameSocketHandler::CloseListeners(); ServerNetworkAdminSocketHandler::CloseListeners(); - } else if (MyClient::my_client != NULL) { + } else if (MyClient::my_client != nullptr) { MyClient::SendQuit(); MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } @@ -557,7 +555,7 @@ void NetworkClose(bool close_admins) NetworkFreeLocalCommandQueue(); free(_network_company_states); - _network_company_states = NULL; + _network_company_states = nullptr; InitializeNetworkPools(close_admins); } @@ -579,12 +577,12 @@ class TCPQueryConnecter : TCPConnecter { public: TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {} - virtual void OnFailure() + void OnFailure() override { NetworkDisconnect(); } - virtual void OnConnect(SOCKET s) + void OnConnect(SOCKET s) override { _networking = true; new ClientNetworkGameSocketHandler(s); @@ -611,8 +609,8 @@ void NetworkTCPQueryServer(NetworkAddress address) void NetworkAddServer(const char *b) { if (*b != '\0') { - const char *port = NULL; - const char *company = NULL; + const char *port = nullptr; + const char *company = nullptr; char host[NETWORK_HOSTNAME_LENGTH]; uint16 rport; @@ -622,7 +620,7 @@ void NetworkAddServer(const char *b) rport = NETWORK_DEFAULT_PORT; ParseConnectionString(&company, &port, host); - if (port != NULL) rport = atoi(port); + if (port != nullptr) rport = atoi(port); NetworkUDPQueryServer(NetworkAddress(host, rport), true); } @@ -635,13 +633,13 @@ void NetworkAddServer(const char *b) */ void GetBindAddresses(NetworkAddressList *addresses, uint16 port) { - for (char **iter = _network_bind_list.Begin(); iter != _network_bind_list.End(); iter++) { - *addresses->Append() = NetworkAddress(*iter, port); + for (const auto &iter : _network_bind_list) { + addresses->emplace_back(iter.c_str(), port); } /* No address, so bind to everything. */ - if (addresses->Length() == 0) { - *addresses->Append() = NetworkAddress("", port); + if (addresses->size() == 0) { + addresses->emplace_back("", port); } } @@ -650,10 +648,10 @@ void GetBindAddresses(NetworkAddressList *addresses, uint16 port) * by the function that generates the config file. */ void NetworkRebuildHostList() { - _network_host_list.Clear(); + _network_host_list.clear(); - for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { - if (item->manually) *_network_host_list.Append() = stredup(item->address.GetAddressAsString(false)); + for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) { + if (item->manually) _network_host_list.emplace_back(item->address.GetAddressAsString(false)); } } @@ -662,12 +660,12 @@ class TCPClientConnecter : TCPConnecter { public: TCPClientConnecter(const NetworkAddress &address) : TCPConnecter(address) {} - virtual void OnFailure() + void OnFailure() override { NetworkError(STR_NETWORK_ERROR_NOCONNECTION); } - virtual void OnConnect(SOCKET s) + void OnConnect(SOCKET s) override { _networking = true; new ClientNetworkGameSocketHandler(s); @@ -887,21 +885,21 @@ void NetworkGameLoop() static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR); static Date next_date = 0; static uint32 next_date_fract; - static CommandPacket *cp = NULL; + static CommandPacket *cp = nullptr; static bool check_sync_state = false; static uint32 sync_state[2]; - if (f == NULL && next_date == 0) { + if (f == nullptr && next_date == 0) { DEBUG(net, 0, "Cannot open commands.log"); next_date = 1; } - while (f != NULL && !feof(f)) { + while (f != nullptr && !feof(f)) { if (_date == next_date && _date_fract == next_date_fract) { - if (cp != NULL) { - NetworkSendCommand(cp->tile, cp->p1, cp->p2, cp->cmd & ~CMD_FLAGS_MASK, NULL, cp->text, cp->company); + if (cp != nullptr) { + NetworkSendCommand(cp->tile, cp->p1, cp->p2, cp->cmd & ~CMD_FLAGS_MASK, nullptr, cp->text, cp->company); DEBUG(net, 0, "injecting: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->cmd, cp->text, GetCommandName(cp->cmd)); free(cp); - cp = NULL; + cp = nullptr; } if (check_sync_state) { if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) { @@ -915,16 +913,16 @@ void NetworkGameLoop() } } - if (cp != NULL || check_sync_state) break; + if (cp != nullptr || check_sync_state) break; char buff[4096]; - if (fgets(buff, lengthof(buff), f) == NULL) break; + if (fgets(buff, lengthof(buff), f) == nullptr) break; char *p = buff; /* Ignore the "[date time] " part of the message */ if (*p == '[') { p = strchr(p, ']'); - if (p == NULL) break; + if (p == nullptr) break; p += 2; } @@ -971,10 +969,10 @@ void NetworkGameLoop() NOT_REACHED(); } } - if (f != NULL && feof(f)) { + if (f != nullptr && feof(f)) { DEBUG(net, 0, "End of commands.log"); fclose(f); - f = NULL; + f = nullptr; } #endif /* DEBUG_DUMP_COMMANDS */ if (_frame_counter >= _frame_counter_max) { @@ -1173,5 +1171,3 @@ bool IsNetworkCompatibleVersion(const char *other) const char *hash2 = ExtractNetworkRevisionHash(other); return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network.h b/src/network/network.h index 26f94482ec..9f8e3b790b 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -12,9 +12,6 @@ #ifndef NETWORK_H #define NETWORK_H - -#ifdef ENABLE_NETWORK - void NetworkStartUp(); void NetworkShutDown(); void NetworkDrawChatMessage(); @@ -26,19 +23,4 @@ extern bool _network_available; ///< is network mode available? extern bool _network_dedicated; ///< are we a dedicated server? extern bool _is_network_server; ///< Does this client wants to be a network-server? -#else /* ENABLE_NETWORK */ -/* Network function stubs when networking is disabled */ - -static inline void NetworkStartUp() {} -static inline void NetworkShutDown() {} -static inline void NetworkDrawChatMessage() {} -static inline bool HasClients() { return false; } - -#define _networking 0 -#define _network_server 0 -#define _network_available 0 -#define _network_dedicated 0 -#define _is_network_server 0 - -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_H */ diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index f70f3d1a51..9c5c43ab5c 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -9,8 +9,6 @@ /** @file network_admin.cpp Server part of the admin network protocol. */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" @@ -236,12 +234,12 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID clien NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientSocket *cs, const NetworkClientInfo *ci) { /* Only send data when we're a proper client, not just someone trying to query the server. */ - if (ci == NULL) return NETWORK_RECV_STATUS_OKAY; + if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO); p->Send_uint32(ci->client_id); - p->Send_string(cs == NULL ? "" : const_cast(cs->client_address).GetHostname()); + p->Send_string(cs == nullptr ? "" : const_cast(cs->client_address).GetHostname()); p->Send_string(ci->client_name); p->Send_uint8 (ci->client_lang); p->Send_uint32(ci->join_date); @@ -736,16 +734,16 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p) /* The admin is requesting client info. */ const NetworkClientSocket *cs; if (d1 == UINT32_MAX) { - this->SendClientInfo(NULL, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); + this->SendClientInfo(nullptr, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); FOR_ALL_CLIENT_SOCKETS(cs) { this->SendClientInfo(cs, cs->GetInfo()); } } else { if (d1 == CLIENT_ID_SERVER) { - this->SendClientInfo(NULL, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); + this->SendClientInfo(nullptr, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); } else { cs = NetworkClientSocket::GetByClientID((ClientID)d1); - if (cs != NULL) this->SendClientInfo(cs, cs->GetInfo()); + if (cs != nullptr) this->SendClientInfo(cs, cs->GetInfo()); } } break; @@ -759,7 +757,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p) } } else { company = Company::GetIfValid(d1); - if (company != NULL) this->SendCompanyInfo(company); + if (company != nullptr) this->SendCompanyInfo(company); } break; @@ -886,7 +884,7 @@ void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code) */ void NetworkAdminCompanyInfo(const Company *company, bool new_company) { - if (company == NULL) { + if (company == nullptr) { DEBUG(net, 1, "[admin] Empty company given for update"); return; } @@ -908,7 +906,7 @@ void NetworkAdminCompanyInfo(const Company *company, bool new_company) */ void NetworkAdminCompanyUpdate(const Company *company) { - if (company == NULL) return; + if (company == nullptr) return; ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { @@ -994,7 +992,7 @@ void NetworkAdminGameScript(const char *json) */ void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp) { - ClientID client_id = owner == NULL ? _network_own_client_id : owner->client_id; + ClientID client_id = owner == nullptr ? _network_own_client_id : owner->client_id; ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { @@ -1045,5 +1043,3 @@ void NetworkAdminUpdate(AdminUpdateFrequency freq) } } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_admin.h b/src/network/network_admin.h index cb478fc7e7..6ea373e8eb 100644 --- a/src/network/network_admin.h +++ b/src/network/network_admin.h @@ -12,8 +12,6 @@ #ifndef NETWORK_ADMIN_H #define NETWORK_ADMIN_H -#ifdef ENABLE_NETWORK - #include "network_internal.h" #include "core/tcp_listen.h" #include "core/tcp_admin.h" @@ -28,14 +26,14 @@ extern NetworkAdminSocketPool _networkadminsocket_pool; /** Class for handling the server side of the game connection. */ class ServerNetworkAdminSocketHandler : public NetworkAdminSocketPool::PoolItem<&_networkadminsocket_pool>, public NetworkAdminSocketHandler, public TCPListenHandler { protected: - virtual NetworkRecvStatus Receive_ADMIN_JOIN(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_QUIT(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_POLL(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_RCON(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p); - virtual NetworkRecvStatus Receive_ADMIN_PING(Packet *p); + NetworkRecvStatus Receive_ADMIN_JOIN(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_QUIT(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_POLL(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_RCON(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p) override; + NetworkRecvStatus Receive_ADMIN_PING(Packet *p) override; NetworkRecvStatus SendProtocol(); NetworkRecvStatus SendPong(uint32 d1); @@ -124,5 +122,4 @@ void NetworkAdminConsole(const char *origin, const char *string); void NetworkAdminGameScript(const char *json); void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp); -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_ADMIN_H */ diff --git a/src/network/network_base.h b/src/network/network_base.h index 1644b3558a..817d0e4c89 100644 --- a/src/network/network_base.h +++ b/src/network/network_base.h @@ -12,8 +12,6 @@ #ifndef NETWORK_BASE_H #define NETWORK_BASE_H -#ifdef ENABLE_NETWORK - #include "network_type.h" #include "core/address.h" #include "../core/pool_type.hpp" @@ -54,5 +52,4 @@ struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_p */ #define FOR_ALL_CLIENT_INFOS(var) FOR_ALL_CLIENT_INFOS_FROM(var, 0) -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_BASE_H */ diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 68e1489874..e7e22db99b 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -11,8 +11,6 @@ #include /* va_list */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "../strings_func.h" #include "../blitter/factory.hpp" @@ -48,7 +46,7 @@ struct ChatMessage { }; /* used for chat window */ -static ChatMessage *_chatmsg_list = NULL; ///< The actual chat message list. +static ChatMessage *_chatmsg_list = nullptr; ///< The actual chat message list. static bool _chatmessage_dirty = false; ///< Does the chat message need repainting? static bool _chatmessage_visible = false; ///< Is a chat message visible. static bool _chat_tab_completion_active; ///< Whether tab completion is active. @@ -59,7 +57,7 @@ static uint MAX_CHAT_MESSAGES = 0; ///< The limit of chat messages to sho * the left and pixels from the bottom. The height is the maximum height. */ static PointDimension _chatmsg_box; -static uint8 *_chatmessage_backup = NULL; ///< Backup in case text is moved. +static uint8 *_chatmessage_backup = nullptr; ///< Backup in case text is moved. /** * Count the chat messages. @@ -322,7 +320,7 @@ struct NetworkChatWindow : public Window { InvalidateWindowData(WC_NEWS_WINDOW, 0, 0); } - virtual void FindWindowPlacementAndResize(int def_width, int def_height) + void FindWindowPlacementAndResize(int def_width, int def_height) override { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } @@ -362,7 +360,7 @@ struct NetworkChatWindow : public Window { } } - return NULL; + return nullptr; } /** @@ -373,7 +371,7 @@ struct NetworkChatWindow : public Window { static char *ChatTabCompletionFindText(char *buf) { char *p = strrchr(buf, ' '); - if (p == NULL) return buf; + if (p == nullptr) return buf; *p = '\0'; return p + 1; @@ -402,7 +400,7 @@ struct NetworkChatWindow : public Window { tb_buf = ChatTabCompletionFindText(pre_buf); tb_len = strlen(tb_buf); - while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) { + while ((cur_name = ChatTabCompletionNextItem(&item)) != nullptr) { item++; if (_chat_tab_completion_active) { @@ -460,13 +458,13 @@ struct NetworkChatWindow : public Window { free(pre_buf); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt = { 0, _screen.height - sm_height - FindWindowById(WC_STATUS_BAR, 0)->height }; return pt; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_NC_DESTINATION) return; @@ -479,7 +477,7 @@ struct NetworkChatWindow : public Window { *size = maxdim(*size, d); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_NC_DESTINATION) return; @@ -489,7 +487,7 @@ struct NetworkChatWindow : public Window { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, this->dest_string, TC_BLACK, SA_RIGHT); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NC_SENDBUTTON: /* Send */ @@ -502,7 +500,7 @@ struct NetworkChatWindow : public Window { } } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { EventState state = ES_NOT_HANDLED; if (keycode == WKC_TAB) { @@ -512,7 +510,7 @@ struct NetworkChatWindow : public Window { return state; } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { _chat_tab_completion_active = false; } @@ -522,7 +520,7 @@ struct NetworkChatWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == this->dest) delete this; } @@ -545,7 +543,7 @@ static const NWidgetPart _nested_chat_window_widgets[] = { /** The description of the chat window. */ static WindowDesc _chat_window_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_SEND_NETWORK_MSG, WC_NONE, 0, _nested_chat_window_widgets, lengthof(_nested_chat_window_widgets) @@ -562,5 +560,3 @@ void ShowNetworkChatQueryWindow(DestType type, int dest) DeleteWindowByClass(WC_SEND_NETWORK_MSG); new NetworkChatWindow(&_chat_window_desc, type, dest); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index cd4572a061..d000487805 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -9,8 +9,6 @@ /** @file network_client.cpp Client part of the network protocol. */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "network_gui.h" #include "../saveload/saveload.h" @@ -31,12 +29,12 @@ #include "network_base.h" #include "network_client.h" #include "../core/backup_type.hpp" -#include "../newgrf_revisions.hpp" - +#include "../thread.h" #include "table/strings.h" #include "../town.h" #include "network_func.h" +#include "../newgrf_revisions.hpp" #include "../safeguards.h" /* This file handles all the client-commands */ @@ -50,7 +48,7 @@ static const uint32 OPENTTD_NEWGRF_REVISION_MASK = (1 << 19) - 1; struct PacketReader : LoadFilter { static const size_t CHUNK = 32 * 1024; ///< 32 KiB chunks of memory. - AutoFreeSmallVector blocks; ///< Buffer with blocks of allocated memory. + std::vector blocks; ///< Buffer with blocks of allocated memory. byte *buf; ///< Buffer we're going to write to/read from. byte *bufe; ///< End of the buffer we write to/read from. byte **block; ///< The block we're reading from/writing to. @@ -58,10 +56,17 @@ struct PacketReader : LoadFilter { size_t read_bytes; ///< The total number of read bytes. /** Initialise everything. */ - PacketReader() : LoadFilter(NULL), buf(NULL), bufe(NULL), block(NULL), written_bytes(0), read_bytes(0) + PacketReader() : LoadFilter(nullptr), buf(nullptr), bufe(nullptr), block(nullptr), written_bytes(0), read_bytes(0) { } + ~PacketReader() override + { + for (auto p : this->blocks) { + free(p); + } + } + /** * Add a packet to this buffer. * @param p The packet to add. @@ -86,14 +91,14 @@ struct PacketReader : LoadFilter { /* Allocate a new chunk and add the remaining data. */ pbuf += to_write; to_write = in_packet - to_write; - this->buf = *this->blocks.Append() = CallocT(CHUNK); + this->blocks.push_back(this->buf = CallocT(CHUNK)); this->bufe = this->buf + CHUNK; memcpy(this->buf, pbuf, to_write); this->buf += to_write; } - /* virtual */ size_t Read(byte *rbuf, size_t size) + size_t Read(byte *rbuf, size_t size) override { /* Limit the amount to read to whatever we still have. */ size_t ret_size = size = min(this->written_bytes - this->read_bytes, size); @@ -115,11 +120,11 @@ struct PacketReader : LoadFilter { return ret_size; } - /* virtual */ void Reset() + void Reset() override { this->read_bytes = 0; - this->block = this->blocks.Begin(); + this->block = this->blocks.data(); this->buf = *this->block++; this->bufe = this->buf + CHUNK; } @@ -144,9 +149,9 @@ void ClientNetworkEmergencySave() * Create a new socket for the client side of the game connection. * @param s The socket to connect with. */ -ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), savegame(NULL), status(STATUS_INACTIVE) +ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), savegame(nullptr), status(STATUS_INACTIVE) { - assert(ClientNetworkGameSocketHandler::my_client == NULL); + assert(ClientNetworkGameSocketHandler::my_client == nullptr); ClientNetworkGameSocketHandler::my_client = this; } @@ -154,7 +159,7 @@ ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : Netwo ClientNetworkGameSocketHandler::~ClientNetworkGameSocketHandler() { assert(ClientNetworkGameSocketHandler::my_client == this); - ClientNetworkGameSocketHandler::my_client = NULL; + ClientNetworkGameSocketHandler::my_client = nullptr; delete this->savegame; } @@ -302,7 +307,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) /** Our client's connection. */ -ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = NULL; +ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = nullptr; /** Last frame we performed an ack. */ static uint32 last_ack_frame; @@ -321,9 +326,9 @@ static uint8 _network_server_max_spectators; CompanyID _network_join_as; /** Login password from -p argument */ -const char *_network_join_server_password = NULL; +const char *_network_join_server_password = nullptr; /** Company password from -P argument */ -const char *_network_join_company_password = NULL; +const char *_network_join_company_password = nullptr; /** Server revision to use when fooling revision check */ const char *_network_join_server_revision = NULL; @@ -558,7 +563,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, co */ bool ClientNetworkGameSocketHandler::IsConnected() { - return my_client != NULL && my_client->status == STATUS_ACTIVE; + return my_client != nullptr && my_client->status == STATUS_ACTIVE; } @@ -567,7 +572,7 @@ bool ClientNetworkGameSocketHandler::IsConnected() * DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p ************/ -extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL); +extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr); NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p) { @@ -601,7 +606,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_INFO(Pa if (current >= MAX_COMPANIES) return NETWORK_RECV_STATUS_CLOSE_QUERY; NetworkCompanyInfo *company_info = GetLobbyCompanyInfo(current); - if (company_info == NULL) return NETWORK_RECV_STATUS_CLOSE_QUERY; + if (company_info == nullptr) return NETWORK_RECV_STATUS_CLOSE_QUERY; p->Recv_string(company_info->company_name, sizeof(company_info->company_name)); company_info->inaugurated_year = p->Recv_uint32(); @@ -644,7 +649,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; ci = NetworkClientInfo::GetByClientID(client_id); - if (ci != NULL) { + if (ci != nullptr) { if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) { /* Client name changed, display the change */ NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, name); @@ -747,7 +752,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P /* Check whether we know this GRF */ const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); - if (f == NULL) { + if (f == nullptr) { /* We do not know this GRF, bail out of initialization */ char buf[sizeof(c.md5sum) * 2 + 1]; md5sumToString(buf, lastof(buf), c.md5sum); @@ -833,7 +838,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packe if (this->status < STATUS_AUTHORIZED || this->status >= STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_MAP; - if (this->savegame != NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + if (this->savegame != nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->savegame = new PacketReader(); @@ -851,7 +856,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packe NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet *p) { if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - if (this->savegame == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _network_join_bytes_total = p->Recv_uint32(); SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); @@ -862,7 +867,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet *p) { if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - if (this->savegame == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* We are still receiving data, put it to the file */ this->savegame->AddPacket(p); @@ -876,7 +881,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet *p) { if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - if (this->savegame == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + if (this->savegame == nullptr) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _network_join_status = NETWORK_JOIN_STATUS_PROCESSING; SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); @@ -889,12 +894,12 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet * game, which would cause us to free this->savegame twice. */ LoadFilter *lf = this->savegame; - this->savegame = NULL; + this->savegame = nullptr; lf->Reset(); /* The map is done downloading, load it */ ClearErrorMessages(); - bool load_success = SafeLoad(NULL, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf); + bool load_success = SafeLoad(nullptr, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf); /* Long savegame loads shouldn't affect the lag calculation! */ this->last_packet = _realtime_tick; @@ -920,7 +925,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet * the server will give us a client-id and let us in */ _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; ShowJoinStatusWindow(); - NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company); + NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company); } } else { /* take control over an existing company */ @@ -985,7 +990,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet cp.frame = p->Recv_uint32(); cp.my_cmd = p->Recv_bool(); - if (err != NULL) { + if (err != nullptr) { IConsolePrintF(CC_ERROR, "WARNING: %s from server, dropping...", err); return NETWORK_RECV_STATUS_MALFORMED_PACKET; } @@ -1000,7 +1005,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH]; - const NetworkClientInfo *ci = NULL, *ci_to; + const NetworkClientInfo *ci = nullptr, *ci_to; NetworkAction action = (NetworkAction)p->Recv_uint8(); ClientID client_id = (ClientID)p->Recv_uint32(); @@ -1009,7 +1014,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) int64 data = p->Recv_uint64(); ci_to = NetworkClientInfo::GetByClientID(client_id); - if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY; + if (ci_to == nullptr) return NETWORK_RECV_STATUS_OKAY; /* Did we initiate the action locally? */ if (self_send) { @@ -1042,7 +1047,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) ci = ci_to; } - if (ci != NULL) { + if (ci != nullptr) { if (strncmp(msg, "synccmuser", 10) == 0) SyncCMUser(msg); else NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data); } @@ -1056,8 +1061,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); - if (ci != NULL) { - NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, GetNetworkErrorMsg((NetworkErrorCode)p->Recv_uint8())); + if (ci != nullptr) { + NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, nullptr, GetNetworkErrorMsg((NetworkErrorCode)p->Recv_uint8())); delete ci; } @@ -1073,8 +1078,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); - if (ci != NULL) { - NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING); + if (ci != nullptr) { + NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, nullptr, STR_NETWORK_MESSAGE_CLIENT_LEAVING); delete ci; } else { DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id); @@ -1095,7 +1100,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p) ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); - if (ci != NULL) { + if (ci != nullptr) { NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name); } @@ -1165,7 +1170,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p) const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); /* Just make sure we do not try to use a client_index that does not exist */ - if (ci == NULL) return NETWORK_RECV_STATUS_OKAY; + if (ci == nullptr) return NETWORK_RECV_STATUS_OKAY; /* if not valid player, force spectator, else check player exists */ if (!Company::IsValidID(company_id)) company_id = COMPANY_SPECTATOR; @@ -1270,7 +1275,7 @@ void NetworkClientRequestMove(CompanyID company_id, const char *pass) */ void NetworkClientsToSpectators(CompanyID cid) { - Backup cur_company(_current_company, FILE_LINE); + Backup cur_company(_current_company, FILE_LINE); /* If our company is changing owner, go to spectators */ if (cid == _local_company) SetLocalCompany(COMPANY_SPECTATOR); @@ -1291,7 +1296,7 @@ void NetworkUpdateClientName() { NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(_network_own_client_id); - if (ci == NULL) return; + if (ci == nullptr) return; /* Don't change the name if it is the same as the old name */ if (strcmp(ci->client_name, _settings_client.network.client_name) != 0) { @@ -1375,4 +1380,4 @@ void SyncCMUser(const char *msg) { _novarole = (role >= 50); DEBUG(net, 1, "CityMania user synchronized: %u %u", user_id, role); } -#endif /* ENABLE_NETWORK */ + diff --git a/src/network/network_client.h b/src/network/network_client.h index eb4790305a..d3ac27ddd2 100644 --- a/src/network/network_client.h +++ b/src/network/network_client.h @@ -12,8 +12,6 @@ #ifndef NETWORK_CLIENT_H #define NETWORK_CLIENT_H -#ifdef ENABLE_NETWORK - #include "network_internal.h" /** Class for handling the client side of the game connection. */ @@ -44,33 +42,33 @@ protected: friend void NetworkClose(bool close_admins); static ClientNetworkGameSocketHandler *my_client; ///< This is us! - virtual NetworkRecvStatus Receive_SERVER_FULL(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_WAIT(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_JOIN(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_FRAME(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_SYNC(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_COMMAND(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_QUIT(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_RCON(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_MOVE(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p); - virtual NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet *p); + NetworkRecvStatus Receive_SERVER_FULL(Packet *p) override; + NetworkRecvStatus Receive_SERVER_BANNED(Packet *p) override; + NetworkRecvStatus Receive_SERVER_ERROR(Packet *p) override; + NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p) override; + NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p) override; + NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) override; + NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) override; + NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p) override; + NetworkRecvStatus Receive_SERVER_WAIT(Packet *p) override; + NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p) override; + NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet *p) override; + NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet *p) override; + NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet *p) override; + NetworkRecvStatus Receive_SERVER_JOIN(Packet *p) override; + NetworkRecvStatus Receive_SERVER_FRAME(Packet *p) override; + NetworkRecvStatus Receive_SERVER_SYNC(Packet *p) override; + NetworkRecvStatus Receive_SERVER_COMMAND(Packet *p) override; + NetworkRecvStatus Receive_SERVER_CHAT(Packet *p) override; + NetworkRecvStatus Receive_SERVER_QUIT(Packet *p) override; + NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p) override; + NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p) override; + NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p) override; + NetworkRecvStatus Receive_SERVER_RCON(Packet *p) override; + NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet *p) override; + NetworkRecvStatus Receive_SERVER_MOVE(Packet *p) override; + NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p) override; + NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet *p) override; static NetworkRecvStatus SendNewGRFsOk(); static NetworkRecvStatus SendGetMap(); @@ -80,7 +78,7 @@ public: ClientNetworkGameSocketHandler(SOCKET s); ~ClientNetworkGameSocketHandler(); - NetworkRecvStatus CloseConnection(NetworkRecvStatus status); + NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; void ClientError(NetworkRecvStatus res); static NetworkRecvStatus SendCompanyInformationQuery(); @@ -119,6 +117,4 @@ extern const char *_network_join_server_password; extern const char *_network_join_company_password; extern const char *_network_join_server_revision; -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CLIENT_H */ diff --git a/src/network/network_command.cpp b/src/network/network_command.cpp index bc08bc5f14..472215a63e 100644 --- a/src/network/network_command.cpp +++ b/src/network/network_command.cpp @@ -9,8 +9,6 @@ /** @file network_command.cpp Command handling over network connections. */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "network_admin.h" #include "network_client.h" @@ -23,7 +21,7 @@ /** Table with all the callbacks we'll use for conversion*/ static CommandCallback * const _callback_table[] = { - /* 0x00 */ NULL, + /* 0x00 */ nullptr, /* 0x01 */ CcBuildPrimaryVehicle, /* 0x02 */ CcBuildAirport, /* 0x03 */ CcBuildBridge, @@ -62,8 +60,8 @@ void CommandQueue::Append(CommandPacket *p) { CommandPacket *add = MallocT(1); *add = *p; - add->next = NULL; - if (this->first == NULL) { + add->next = nullptr; + if (this->first == nullptr) { this->first = add; } else { this->last->next = add; @@ -81,15 +79,15 @@ CommandPacket *CommandQueue::Pop(bool ignore_paused) { CommandPacket **prev = &this->first; CommandPacket *ret = this->first; - CommandPacket *prev_item = NULL; + CommandPacket *prev_item = nullptr; if (ignore_paused && _pause_mode != PM_UNPAUSED) { - while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) { + while (ret != nullptr && !IsCommandAllowedWhilePaused(ret->cmd)) { prev_item = ret; prev = &ret->next; ret = ret->next; } } - if (ret != NULL) { + if (ret != nullptr) { if (ret == this->last) this->last = prev_item; *prev = ret->next; this->count--; @@ -106,17 +104,17 @@ CommandPacket *CommandQueue::Peek(bool ignore_paused) { if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first; - for (CommandPacket *p = this->first; p != NULL; p = p->next) { + for (CommandPacket *p = this->first; p != nullptr; p = p->next) { if (IsCommandAllowedWhilePaused(p->cmd)) return p; } - return NULL; + return nullptr; } /** Free everything that is in the queue. */ void CommandQueue::Free() { CommandPacket *cp; - while ((cp = this->Pop()) != NULL) { + while ((cp = this->Pop()) != nullptr) { free(cp); } assert(this->count == 0); @@ -149,7 +147,7 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman c.cmd = cmd; c.callback = callback; - strecpy(c.text, (text != NULL) ? text : "", lastof(c.text)); + strecpy(c.text, (text != nullptr) ? text : "", lastof(c.text)); if (_network_server) { /* If we are the server, we queue the command in our 'special' queue. @@ -182,7 +180,7 @@ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, Comman */ void NetworkSyncCommandQueue(NetworkClientSocket *cs) { - for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) { + for (CommandPacket *p = _local_execution_queue.Peek(); p != nullptr; p = p->next) { CommandPacket c = *p; c.callback = 0; cs->outgoing_queue.Append(&c); @@ -199,7 +197,7 @@ void NetworkExecuteLocalCommandQueue() CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue); CommandPacket *cp; - while ((cp = queue.Peek()) != NULL) { + while ((cp = queue.Peek()) != nullptr) { /* The queue is always in order, which means * that the first element will be executed first. */ if (_frame_counter < cp->frame) break; @@ -247,13 +245,13 @@ static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket if (cs->status >= NetworkClientSocket::STATUS_MAP) { /* Callbacks are only send back to the client who sent them in the * first place. This filters that out. */ - cp.callback = (cs != owner) ? NULL : callback; + cp.callback = (cs != owner) ? nullptr : callback; cp.my_cmd = (cs == owner); cs->outgoing_queue.Append(&cp); } } - cp.callback = (cs != owner) ? NULL : callback; + cp.callback = (cs != owner) ? nullptr : callback; cp.my_cmd = (cs == owner); _local_execution_queue.Append(&cp); } @@ -273,7 +271,7 @@ static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owne #endif CommandPacket *cp; - while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) { + while (--to_go >= 0 && (cp = queue->Pop(true)) != nullptr) { DistributeCommandPacket(*cp, owner); NetworkAdminCmdLogging(owner, cp); free(cp); @@ -284,7 +282,7 @@ static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owne void NetworkDistributeCommands() { /* First send the server's commands. */ - DistributeQueue(&_local_wait_queue, NULL); + DistributeQueue(&_local_wait_queue, nullptr); /* Then send the queues of the others. */ NetworkClientSocket *cs; @@ -297,7 +295,7 @@ void NetworkDistributeCommands() * Receives a command from the network. * @param p the packet to read from. * @param cp the struct to write the data to. - * @return an error message. When NULL there has been no error. + * @return an error message. When nullptr there has been no error. */ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp) { @@ -316,7 +314,7 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c if (callback >= lengthof(_callback_table)) return "invalid callback"; cp->callback = _callback_table[callback]; - return NULL; + return nullptr; } /** @@ -340,9 +338,7 @@ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp) if (callback == lengthof(_callback_table)) { DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback); - callback = 0; // _callback_table[0] == NULL + callback = 0; // _callback_table[0] == nullptr } p->Send_uint8 (callback); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 551abb4420..b6d32620bd 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -9,8 +9,6 @@ /** @file network_content.cpp Content sending/receiving part of the network protocol. */ -#if defined(ENABLE_NETWORK) - #include "../stdafx.h" #include "../rev.h" #include "../ai/ai.hpp" @@ -37,7 +35,7 @@ ClientNetworkContentSocketHandler _network_content_client; /** Wrapper function for the HasProc */ static bool HasGRFConfig(const ContentInfo *ci, bool md5sum) { - return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : NULL) != NULL; + return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : nullptr) != nullptr; } /** @@ -81,7 +79,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) } /* Find the appropriate check function */ - HasProc proc = NULL; + HasProc proc = nullptr; switch (ci->type) { case CONTENT_TYPE_NEWGRF: proc = HasGRFConfig; @@ -124,7 +122,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) break; } - if (proc != NULL) { + if (proc != nullptr) { if (proc(ci, true)) { ci->state = ContentInfo::ALREADY_HERE; } else { @@ -135,12 +133,11 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) ci->state = ContentInfo::UNSELECTED; } - /* Something we don't have and has filesize 0 does not exist in te system */ + /* Something we don't have and has filesize 0 does not exist in the system */ if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST; /* Do we already have a stub for this? */ - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - ContentInfo *ici = *iter; + for (ContentInfo *ici : this->infos) { if (ici->type == ci->type && ici->unique_id == ci->unique_id && memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) { /* Preserve the name if possible */ @@ -167,11 +164,11 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) return true; } - *this->infos.Append() = ci; + this->infos.push_back(ci); /* Incoming data means that we might need to reconsider dependencies */ - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - this->CheckDependencyState(*iter); + for (ContentInfo *ici : this->infos) { + this->CheckDependencyState(ici); } this->OnReceiveContentInfo(ci); @@ -244,19 +241,18 @@ void ClientNetworkContentSocketHandler::RequestContentList(uint count, const Con */ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bool send_md5sum) { - if (cv == NULL) return; + if (cv == nullptr) return; this->Connect(); - assert(cv->Length() < 255); - assert(cv->Length() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / + assert(cv->size() < 255); + assert(cv->size() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / (sizeof(uint8) + sizeof(uint32) + (send_md5sum ? /*sizeof(ContentInfo::md5sum)*/16 : 0))); Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID); - p->Send_uint8(cv->Length()); + p->Send_uint8((uint8)cv->size()); - for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) { - const ContentInfo *ci = *iter; + for (const ContentInfo *ci : *cv) { p->Send_uint8((byte)ci->type); p->Send_uint32(ci->unique_id); if (!send_md5sum) continue; @@ -268,11 +264,9 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo this->SendPacket(p); - for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) { - ContentInfo *ci = *iter; + for (ContentInfo *ci : *cv) { bool found = false; - for (ContentIterator iter2 = this->infos.Begin(); iter2 != this->infos.End(); iter2++) { - ContentInfo *ci2 = *iter2; + for (ContentInfo *ci2 : this->infos) { if (ci->type == ci2->type && ci->unique_id == ci2->unique_id && (!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) { found = true; @@ -280,7 +274,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo } } if (!found) { - *this->infos.Append() = ci; + this->infos.push_back(ci); } else { delete ci; } @@ -298,15 +292,14 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin bytes = 0; ContentIDList content; - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - const ContentInfo *ci = *iter; + for (const ContentInfo *ci : this->infos) { if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue; - *content.Append() = ci->id; + content.push_back(ci->id); bytes += ci->filesize; } - files = content.Length(); + files = (uint)content.size(); /* If there's nothing to download, do nothing. */ if (files == 0) return; @@ -324,7 +317,7 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin */ void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const ContentIDList &content) { - uint count = content.Length(); + uint count = (uint)content.size(); /* Allocate memory for the whole request. * Requests are "id\nid\n..." (as strings), so assume the maximum ID, @@ -335,8 +328,8 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const Conten const char *lastof = content_request + bytes - 1; char *p = content_request; - for (const ContentID *id = content.Begin(); id != content.End(); id++) { - p += seprintf(p, lastof, "%d\n", *id); + for (const ContentID &id : content) { + p += seprintf(p, lastof, "%d\n", id); } this->http_response_index = -1; @@ -352,8 +345,8 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const Conten */ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const ContentIDList &content) { - uint count = content.Length(); - const ContentID *content_ids = content.Begin(); + uint count = (uint)content.size(); + const ContentID *content_ids = content.data(); this->Connect(); while (count > 0) { @@ -381,12 +374,12 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co * @param ci the information to get the filename from * @param compressed should the filename end with .gz? * @return a statically allocated buffer with the filename or - * NULL when no filename could be made. + * nullptr when no filename could be made. */ static char *GetFullFilename(const ContentInfo *ci, bool compressed) { Subdirectory dir = GetContentInfoSubDir(ci->type); - if (dir == NO_DIRECTORY) return NULL; + if (dir == NO_DIRECTORY) return nullptr; static char buf[MAX_PATH]; FioGetFullPath(buf, lastof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename); @@ -407,14 +400,14 @@ static bool GunzipFile(const ContentInfo *ci) /* Need to open the file with fopen() to support non-ASCII on Windows. */ FILE *ftmp = fopen(GetFullFilename(ci, true), "rb"); - if (ftmp == NULL) return false; + if (ftmp == nullptr) return false; /* Duplicate the handle, and close the FILE*, to avoid double-closing the handle later. */ gzFile fin = gzdopen(dup(fileno(ftmp)), "rb"); fclose(ftmp); FILE *fout = fopen(GetFullFilename(ci, false), "wb"); - if (fin == NULL || fout == NULL) { + if (fin == nullptr || fout == nullptr) { ret = false; } else { byte buff[8192]; @@ -448,8 +441,8 @@ static bool GunzipFile(const ContentInfo *ci) } } - if (fin != NULL) gzclose(fin); - if (fout != NULL) fclose(fout); + if (fin != nullptr) gzclose(fin); + if (fout != nullptr) fclose(fout); return ret; #else @@ -459,7 +452,7 @@ static bool GunzipFile(const ContentInfo *ci) bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { - if (this->curFile == NULL) { + if (this->curFile == nullptr) { delete this->curInfo; /* When we haven't opened a file this must be our first packet with metadata. */ this->curInfo = new ContentInfo; @@ -480,7 +473,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR); this->Close(); fclose(this->curFile); - this->curFile = NULL; + this->curFile = nullptr; return false; } @@ -501,14 +494,14 @@ bool ClientNetworkContentSocketHandler::BeforeDownload() { if (!this->curInfo->IsValid()) { delete this->curInfo; - this->curInfo = NULL; + this->curInfo = nullptr; return false; } if (this->curInfo->filesize != 0) { /* The filesize is > 0, so we are going to download it */ const char *filename = GetFullFilename(this->curInfo, true); - if (filename == NULL || (this->curFile = fopen(filename, "wb")) == NULL) { + if (filename == nullptr || (this->curFile = fopen(filename, "wb")) == nullptr) { /* Unless that fails of course... */ DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR); @@ -527,7 +520,7 @@ void ClientNetworkContentSocketHandler::AfterDownload() /* We read nothing; that's our marker for end-of-stream. * Now gunzip the tar and make it known. */ fclose(this->curFile); - this->curFile = NULL; + this->curFile = nullptr; if (GunzipFile(this->curInfo)) { unlink(GetFullFilename(this->curInfo, true)); @@ -557,41 +550,42 @@ void ClientNetworkContentSocketHandler::OnFailure() uint files, bytes; this->DownloadSelectedContent(files, bytes, true); - this->http_response.Reset(); + this->http_response.clear(); + this->http_response.shrink_to_fit(); this->http_response_index = -2; - if (this->curFile != NULL) { + if (this->curFile != nullptr) { /* Revert the download progress when we are going for the old system. */ long size = ftell(this->curFile); if (size > 0) this->OnDownloadProgress(this->curInfo, (int)-size); fclose(this->curFile); - this->curFile = NULL; + this->curFile = nullptr; } } void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length) { - assert(data == NULL || length != 0); + assert(data == nullptr || length != 0); /* Ignore any latent data coming from a connection we closed. */ if (this->http_response_index == -2) return; if (this->http_response_index == -1) { - if (data != NULL) { + if (data != nullptr) { /* Append the rest of the response. */ - memcpy(this->http_response.Append((uint)length), data, length); + this->http_response.insert(this->http_response.end(), data, data + length); return; } else { /* Make sure the response is properly terminated. */ - *this->http_response.Append() = '\0'; + this->http_response.push_back('\0'); /* And prepare for receiving the rest of the data. */ this->http_response_index = 0; } } - if (data != NULL) { + if (data != nullptr) { /* We have data, so write it to the file. */ if (fwrite(data, 1, length, this->curFile) != length) { /* Writing failed somehow, let try via the old method. */ @@ -604,12 +598,12 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l return; } - if (this->curFile != NULL) { + if (this->curFile != nullptr) { /* We've finished downloading a file. */ this->AfterDownload(); } - if ((uint)this->http_response_index >= this->http_response.Length()) { + if ((uint)this->http_response_index >= this->http_response.size()) { /* It's not a real failure, but if there's * nothing more to download it helps with * cleaning up the stuff we allocated. */ @@ -622,12 +616,12 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l this->curInfo = new ContentInfo; /** Check p for not being null and return calling OnFailure if that's not the case. */ -#define check_not_null(p) { if ((p) == NULL) { this->OnFailure(); return; } } +#define check_not_null(p) { if ((p) == nullptr) { this->OnFailure(); return; } } /** Check p for not being null and then terminate, or return calling OnFailure. */ #define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; } for (;;) { - char *str = this->http_response.Begin() + this->http_response_index; + char *str = this->http_response.data() + this->http_response_index; char *p = strchr(str, '\n'); check_and_terminate(p); @@ -655,7 +649,7 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l str = p + 1; /* Is it a fallback URL? If so, just continue with the next one. */ if (strncmp(str, "ottd", 4) == 0) { - if ((uint)this->http_response_index >= this->http_response.Length()) { + if ((uint)this->http_response_index >= this->http_response.size()) { /* Have we gone through all lines? */ this->OnFailure(); return; @@ -701,8 +695,8 @@ void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t l ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() : NetworkContentSocketHandler(), http_response_index(-2), - curFile(NULL), - curInfo(NULL), + curFile(nullptr), + curInfo(nullptr), isConnecting(false), lastActivity(_realtime_tick) { @@ -712,9 +706,9 @@ ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() : ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler() { delete this->curInfo; - if (this->curFile != NULL) fclose(this->curFile); + if (this->curFile != nullptr) fclose(this->curFile); - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter; + for (ContentInfo *ci : this->infos) delete ci; } /** Connect to the content server. */ @@ -726,13 +720,13 @@ public: */ NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {} - virtual void OnFailure() + void OnFailure() override { _network_content_client.isConnecting = false; _network_content_client.OnConnect(false); } - virtual void OnConnect(SOCKET s) + void OnConnect(SOCKET s) override { assert(_network_content_client.sock == INVALID_SOCKET); _network_content_client.isConnecting = false; @@ -780,7 +774,7 @@ void ClientNetworkContentSocketHandler::SendReceive() if (this->CanSendReceive()) { if (this->ReceivePackets()) { - /* Only update activity once a packet is received, instead of everytime we try it. */ + /* Only update activity once a packet is received, instead of every time we try it. */ this->lastActivity = _realtime_tick; } } @@ -795,25 +789,23 @@ void ClientNetworkContentSocketHandler::SendReceive() void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid) { /* When we tried to download it already, don't try again */ - if (this->requested.Contains(cid)) return; + if (std::find(this->requested.begin(), this->requested.end(), cid) != this->requested.end()) return; - *this->requested.Append() = cid; - assert(this->requested.Contains(cid)); + this->requested.push_back(cid); this->RequestContentList(1, &cid); } /** * Get the content info based on a ContentID * @param cid the ContentID to search for - * @return the ContentInfo or NULL if not found + * @return the ContentInfo or nullptr if not found */ ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid) { - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - ContentInfo *ci = *iter; + for (ContentInfo *ci : this->infos) { if (ci->id == cid) return ci; } - return NULL; + return nullptr; } @@ -824,7 +816,7 @@ ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid) void ClientNetworkContentSocketHandler::Select(ContentID cid) { ContentInfo *ci = this->GetContent(cid); - if (ci == NULL || ci->state != ContentInfo::UNSELECTED) return; + if (ci == nullptr || ci->state != ContentInfo::UNSELECTED) return; ci->state = ContentInfo::SELECTED; this->CheckDependencyState(ci); @@ -837,7 +829,7 @@ void ClientNetworkContentSocketHandler::Select(ContentID cid) void ClientNetworkContentSocketHandler::Unselect(ContentID cid) { ContentInfo *ci = this->GetContent(cid); - if (ci == NULL || !ci->IsSelected()) return; + if (ci == nullptr || !ci->IsSelected()) return; ci->state = ContentInfo::UNSELECTED; this->CheckDependencyState(ci); @@ -846,8 +838,7 @@ void ClientNetworkContentSocketHandler::Unselect(ContentID cid) /** Select everything we can select */ void ClientNetworkContentSocketHandler::SelectAll() { - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - ContentInfo *ci = *iter; + for (ContentInfo *ci : this->infos) { if (ci->state == ContentInfo::UNSELECTED) { ci->state = ContentInfo::SELECTED; this->CheckDependencyState(ci); @@ -858,8 +849,7 @@ void ClientNetworkContentSocketHandler::SelectAll() /** Select everything that's an update for something we've got */ void ClientNetworkContentSocketHandler::SelectUpgrade() { - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - ContentInfo *ci = *iter; + for (ContentInfo *ci : this->infos) { if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) { ci->state = ContentInfo::SELECTED; this->CheckDependencyState(ci); @@ -870,8 +860,7 @@ void ClientNetworkContentSocketHandler::SelectUpgrade() /** Unselect everything that we've not downloaded so far. */ void ClientNetworkContentSocketHandler::UnselectAll() { - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - ContentInfo *ci = *iter; + for (ContentInfo *ci : this->infos) { if (ci->IsSelected() && ci->state != ContentInfo::ALREADY_HERE) ci->state = ContentInfo::UNSELECTED; } } @@ -901,13 +890,12 @@ void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *c */ void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const { - for (ConstContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { - const ContentInfo *ci = *iter; + for (const ContentInfo * const &ci : this->infos) { if (ci == child) continue; for (uint i = 0; i < ci->dependency_count; i++) { if (ci->dependencies[i] == child->id) { - *parents.Append() = ci; + parents.push_back(ci); break; } } @@ -921,18 +909,18 @@ void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVect */ void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const { - *tree.Append() = child; + tree.push_back(child); /* First find all direct parents. We can't use the "normal" iterator as * we are including stuff into the vector and as such the vector's data * store can be reallocated (and thus move), which means out iterating * pointer gets invalid. So fall back to the indices. */ - for (uint i = 0; i < tree.Length(); i++) { + for (uint i = 0; i < tree.size(); i++) { ConstContentVector parents; this->ReverseLookupDependency(parents, tree[i]); - for (ConstContentIterator piter = parents.Begin(); piter != parents.End(); piter++) { - tree.Include(*piter); + for (const ContentInfo *ci : parents) { + include(tree, ci); } } } @@ -949,7 +937,7 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) * selected and thus can unselect when a dependency is removed. */ for (uint i = 0; i < ci->dependency_count; i++) { ContentInfo *c = this->GetContent(ci->dependencies[i]); - if (c == NULL) { + if (c == nullptr) { this->DownloadContentInfo(ci->dependencies[i]); } else if (c->state == ContentInfo::UNSELECTED) { c->state = ContentInfo::AUTOSELECTED; @@ -967,8 +955,7 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) * we automatically selected them. */ ConstContentVector parents; this->ReverseLookupDependency(parents, ci); - for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { - const ContentInfo *c = *iter; + for (const ContentInfo *c : parents) { if (!c->IsSelected()) continue; this->Unselect(c->id); @@ -976,22 +963,22 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) for (uint i = 0; i < ci->dependency_count; i++) { const ContentInfo *c = this->GetContent(ci->dependencies[i]); - if (c == NULL) { + if (c == nullptr) { DownloadContentInfo(ci->dependencies[i]); continue; } if (c->state != ContentInfo::AUTOSELECTED) continue; /* Only unselect when WE are the only parent. */ - parents.Clear(); + parents.clear(); this->ReverseLookupDependency(parents, c); /* First check whether anything depends on us */ int sel_count = 0; bool force_selection = false; - for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { - if ((*iter)->IsSelected()) sel_count++; - if ((*iter)->state == ContentInfo::SELECTED) force_selection = true; + for (const ContentInfo *ci : parents) { + if (ci->IsSelected()) sel_count++; + if (ci->state == ContentInfo::SELECTED) force_selection = true; } if (sel_count == 0) { /* Nothing depends on us */ @@ -1002,12 +989,12 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) if (force_selection) continue; /* "Flood" search to find all items in the dependency graph*/ - parents.Clear(); + parents.clear(); this->ReverseLookupTreeDependency(parents, c); /* Is there anything that is "force" selected?, if so... we're done. */ - for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { - if ((*iter)->state != ContentInfo::SELECTED) continue; + for (const ContentInfo *ci : parents) { + if (ci->state != ContentInfo::SELECTED) continue; force_selection = true; break; @@ -1020,12 +1007,11 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) * After that's done run over them once again to test their children * to unselect. Don't do it immediately because it'll do exactly what * we're doing now. */ - for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { - const ContentInfo *c = *iter; + for (const ContentInfo *c : parents) { if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id); } - for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { - this->CheckDependencyState(this->GetContent((*iter)->id)); + for (const ContentInfo *c : parents) { + this->CheckDependencyState(this->GetContent(c->id)); } } } @@ -1033,62 +1019,63 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) /** Clear all downloaded content information. */ void ClientNetworkContentSocketHandler::Clear() { - for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter; + for (ContentInfo *c : this->infos) delete c; - this->infos.Clear(); - this->requested.Clear(); + this->infos.clear(); + this->requested.clear(); } /*** CALLBACK ***/ void ClientNetworkContentSocketHandler::OnConnect(bool success) { - for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { - ContentCallback *cb = *iter; + for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { + ContentCallback *cb = this->callbacks[i]; + /* the callback may remove itself from this->callbacks */ cb->OnConnect(success); - if (iter != this->callbacks.End() && *iter == cb) iter++; + if (i != this->callbacks.size() && this->callbacks[i] == cb) i++; } } void ClientNetworkContentSocketHandler::OnDisconnect() { - for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { - ContentCallback *cb = *iter; + for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { + ContentCallback *cb = this->callbacks[i]; cb->OnDisconnect(); - if (iter != this->callbacks.End() && *iter == cb) iter++; + if (i != this->callbacks.size() && this->callbacks[i] == cb) i++; } } void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci) { - for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { - ContentCallback *cb = *iter; + for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { + ContentCallback *cb = this->callbacks[i]; + /* the callback may add items and/or remove itself from this->callbacks */ cb->OnReceiveContentInfo(ci); - if (iter != this->callbacks.End() && *iter == cb) iter++; + if (i != this->callbacks.size() && this->callbacks[i] == cb) i++; } } void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, int bytes) { - for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { - ContentCallback *cb = *iter; + for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { + ContentCallback *cb = this->callbacks[i]; cb->OnDownloadProgress(ci, bytes); - if (iter != this->callbacks.End() && *iter == cb) iter++; + if (i != this->callbacks.size() && this->callbacks[i] == cb) i++; } } void ClientNetworkContentSocketHandler::OnDownloadComplete(ContentID cid) { ContentInfo *ci = this->GetContent(cid); - if (ci != NULL) { + if (ci != nullptr) { ci->state = ContentInfo::ALREADY_HERE; } - for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { - ContentCallback *cb = *iter; + for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { + ContentCallback *cb = this->callbacks[i]; + /* the callback may remove itself from this->callbacks */ cb->OnDownloadComplete(cid); - if (iter != this->callbacks.End() && *iter == cb) iter++; + if (i != this->callbacks.size() && this->callbacks[i] == cb) i++; } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_content.h b/src/network/network_content.h index 25788065fd..b65321e0f0 100644 --- a/src/network/network_content.h +++ b/src/network/network_content.h @@ -15,12 +15,10 @@ #include "core/tcp_content.h" #include "core/tcp_http.h" -#if defined(ENABLE_NETWORK) - /** Vector with content info */ -typedef SmallVector ContentVector; +typedef std::vector ContentVector; /** Vector with constant content info */ -typedef SmallVector ConstContentVector; +typedef std::vector ConstContentVector; /** Iterator for the content vector */ typedef ContentInfo **ContentIterator; @@ -68,12 +66,12 @@ struct ContentCallback { */ class ClientNetworkContentSocketHandler : public NetworkContentSocketHandler, ContentCallback, HTTPCallback { protected: - typedef SmallVector ContentIDList; ///< List of content IDs to (possibly) select. - SmallVector callbacks; ///< Callbacks to notify "the world" - ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) - ContentVector infos; ///< All content info we received - SmallVector http_response; ///< The HTTP response to the requests we've been doing - int http_response_index; ///< Where we are, in the response, with handling it + typedef std::vector ContentIDList; ///< List of content IDs to (possibly) select. + std::vector callbacks; ///< Callbacks to notify "the world" + ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) + ContentVector infos; ///< All content info we received + std::vector http_response; ///< The HTTP response to the requests we've been doing + int http_response_index; ///< Where we are, in the response, with handling it FILE *curFile; ///< Currently downloaded file ContentInfo *curInfo; ///< Information about the currently downloaded file @@ -82,20 +80,20 @@ protected: friend class NetworkContentConnecter; - virtual bool Receive_SERVER_INFO(Packet *p); - virtual bool Receive_SERVER_CONTENT(Packet *p); + bool Receive_SERVER_INFO(Packet *p) override; + bool Receive_SERVER_CONTENT(Packet *p) override; ContentInfo *GetContent(ContentID cid); void DownloadContentInfo(ContentID cid); - void OnConnect(bool success); - void OnDisconnect(); - void OnReceiveContentInfo(const ContentInfo *ci); - void OnDownloadProgress(const ContentInfo *ci, int bytes); - void OnDownloadComplete(ContentID cid); + void OnConnect(bool success) override; + void OnDisconnect() override; + void OnReceiveContentInfo(const ContentInfo *ci) override; + void OnDownloadProgress(const ContentInfo *ci, int bytes) override; + void OnDownloadComplete(ContentID cid) override; - void OnFailure(); - void OnReceiveData(const char *data, size_t length); + void OnFailure() override; + void OnReceiveData(const char *data, size_t length) override; bool BeforeDownload(); void AfterDownload(); @@ -111,7 +109,7 @@ public: void Connect(); void SendReceive(); - void Close(); + void Close() override; void RequestContentList(ContentType type); void RequestContentList(uint count, const ContentID *content_ids); @@ -131,30 +129,26 @@ public: void CheckDependencyState(ContentInfo *ci); /** Get the number of content items we know locally. */ - uint Length() const { return this->infos.Length(); } + uint Length() const { return (uint)this->infos.size(); } /** Get the begin of the content inf iterator. */ - ConstContentIterator Begin() const { return this->infos.Begin(); } + ConstContentIterator Begin() const { return this->infos.data(); } /** Get the nth position of the content inf iterator. */ - ConstContentIterator Get(uint32 index) const { return this->infos.Get(index); } + ConstContentIterator Get(uint32 index) const { return this->infos.data() + index; } /** Get the end of the content inf iterator. */ - ConstContentIterator End() const { return this->infos.End(); } + ConstContentIterator End() const { return this->Begin() + this->Length(); } void Clear(); /** Add a callback to this class */ - void AddCallback(ContentCallback *cb) { this->callbacks.Include(cb); } + void AddCallback(ContentCallback *cb) { include(this->callbacks, cb); } /** Remove a callback */ - void RemoveCallback(ContentCallback *cb) { this->callbacks.Erase(this->callbacks.Find(cb)); } + void RemoveCallback(ContentCallback *cb) { this->callbacks.erase(std::find(this->callbacks.begin(), this->callbacks.end(), cb)); } }; extern ClientNetworkContentSocketHandler _network_content_client; -void ShowNetworkContentListWindow(ContentVector *cv = NULL, ContentType type1 = CONTENT_TYPE_END, ContentType type2 = CONTENT_TYPE_END); +void ShowNetworkContentListWindow(ContentVector *cv = nullptr, ContentType type1 = CONTENT_TYPE_END, ContentType type2 = CONTENT_TYPE_END); void ShowMissingContentWindow(const struct GRFConfig *list); -#else -static inline void ShowNetworkContentListWindow() {} -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_CONTENT_H */ diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 877dea9786..9c58564e7b 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -9,7 +9,6 @@ /** @file network_content_gui.cpp Implementation of the Network Content related GUIs. */ -#if defined(ENABLE_NETWORK) #include "../stdafx.h" #include "../strings_func.h" #include "../gfx_func.h" @@ -65,7 +64,7 @@ struct ContentTextfileWindow : public TextfileWindow { } } - /* virtual */ void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_TF_CAPTION) { SetDParam(0, this->GetTypeString()); @@ -96,7 +95,7 @@ static const NWidgetPart _nested_network_content_download_status_window_widgets[ /** Window description for the download window */ static WindowDesc _network_content_download_status_window_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_network_content_download_status_window_widgets, lengthof(_nested_network_content_download_status_window_widgets) @@ -116,7 +115,7 @@ BaseNetworkContentDownloadStatusWindow::~BaseNetworkContentDownloadStatusWindow( _network_content_client.RemoveCallback(this); } -/* virtual */ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widget) const +void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widget) const { if (widget != WID_NCDS_BACKGROUND) return; @@ -145,7 +144,7 @@ BaseNetworkContentDownloadStatusWindow::~BaseNetworkContentDownloadStatusWindow( DrawStringMultiLine(r.left + 2, r.right - 2, y, y + FONT_HEIGHT_NORMAL * 2, str, TC_FROMSTRING, SA_CENTER); } -/* virtual */ void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes) +void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes) { if (ci->id != this->cur_id) { strecpy(this->name, ci->filename, lastof(this->name)); @@ -161,7 +160,7 @@ BaseNetworkContentDownloadStatusWindow::~BaseNetworkContentDownloadStatusWindow( /** Window for showing the download status of content */ struct NetworkContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow { private: - SmallVector receivedTypes; ///< Types we received so we can update their cache + std::vector receivedTypes; ///< Types we received so we can update their cache public: /** @@ -177,8 +176,8 @@ public: ~NetworkContentDownloadStatusWindow() { TarScanner::Mode mode = TarScanner::NONE; - for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) { - switch (*iter) { + for (auto ctype : this->receivedTypes) { + switch (ctype) { case CONTENT_TYPE_AI: case CONTENT_TYPE_AI_LIBRARY: /* AI::Rescan calls the scanner. */ @@ -211,8 +210,8 @@ public: TarScanner::DoScan(mode); /* Tell all the backends about what we've downloaded */ - for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) { - switch (*iter) { + for (auto ctype : this->receivedTypes) { + switch (ctype) { case CONTENT_TYPE_AI: case CONTENT_TYPE_AI_LIBRARY: AI::Rescan(); @@ -239,7 +238,7 @@ public: break; case CONTENT_TYPE_NEWGRF: - ScanNewGRFFiles(NULL); + ScanNewGRFFiles(nullptr); break; case CONTENT_TYPE_SCENARIO: @@ -258,7 +257,7 @@ public: InvalidateWindowData(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST, 2); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget == WID_NCDS_CANCELOK) { if (this->downloaded_bytes != this->total_bytes) { @@ -272,10 +271,10 @@ public: } } - virtual void OnDownloadProgress(const ContentInfo *ci, int bytes) + void OnDownloadProgress(const ContentInfo *ci, int bytes) override { BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ci, bytes); - this->receivedTypes.Include(ci->type); + include(this->receivedTypes, ci->type); /* When downloading is finished change cancel in ok */ if (this->downloaded_bytes == this->total_bytes) { @@ -290,7 +289,7 @@ struct ContentListFilterData { std::bitset types; ///< Content types displayed }; -/** Filter criterias for NetworkContentListWindow. */ +/** Filter criteria for NetworkContentListWindow. */ enum ContentListFilterCriteria { CONTENT_FILTER_TEXT = 0, ///< Filter by query sting CONTENT_FILTER_TYPE_OR_SELECTED,///< Filter by being of displayed type or selected for download @@ -334,8 +333,7 @@ class NetworkContentListWindow : public Window, ContentCallback { pos = strecpy(pos, "do=searchgrfid&q=", last); bool first = true; - for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { - const ContentInfo *ci = *iter; + for (const ContentInfo *ci : this->content) { if (ci->state != ContentInfo::DOES_NOT_EXIST) continue; if (!first) pos = strecpy(pos, ",", last); @@ -386,49 +384,49 @@ class NetworkContentListWindow : public Window, ContentCallback { if (!this->content.NeedRebuild()) return; /* Create temporary array of games to use for listing */ - this->content.Clear(); + this->content.clear(); bool all_available = true; for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { if ((*iter)->state == ContentInfo::DOES_NOT_EXIST) all_available = false; - *this->content.Append() = *iter; + this->content.push_back(*iter); } this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select && all_available); this->FilterContentList(); - this->content.Compact(); + this->content.shrink_to_fit(); this->content.RebuildDone(); this->SortContentList(); - this->vscroll->SetCount(this->content.Length()); // Update the scrollbar + this->vscroll->SetCount((int)this->content.size()); // Update the scrollbar this->ScrollToSelected(); } /** Sort content by name. */ - static int CDECL NameSorter(const ContentInfo * const *a, const ContentInfo * const *b) + static bool NameSorter(const ContentInfo * const &a, const ContentInfo * const &b) { - return strnatcmp((*a)->name, (*b)->name, true); // Sort by name (natural sorting). + return strnatcmp(a->name, b->name, true) < 0; // Sort by name (natural sorting). } /** Sort content by type. */ - static int CDECL TypeSorter(const ContentInfo * const *a, const ContentInfo * const *b) + static bool TypeSorter(const ContentInfo * const &a, const ContentInfo * const &b) { int r = 0; - if ((*a)->type != (*b)->type) { - r = strnatcmp(content_type_strs[(*a)->type], content_type_strs[(*b)->type]); + if (a->type != b->type) { + r = strnatcmp(content_type_strs[a->type], content_type_strs[b->type]); } - if (r == 0) r = NameSorter(a, b); - return r; + if (r == 0) return NameSorter(a, b); + return r < 0; } /** Sort content by state. */ - static int CDECL StateSorter(const ContentInfo * const *a, const ContentInfo * const *b) + static bool StateSorter(const ContentInfo * const &a, const ContentInfo * const &b) { - int r = (*a)->state - (*b)->state; - if (r == 0) r = TypeSorter(a, b); - return r; + int r = a->state - b->state; + if (r == 0) return TypeSorter(a, b); + return r < 0; } /** Sort the content list */ @@ -436,12 +434,8 @@ class NetworkContentListWindow : public Window, ContentCallback { { if (!this->content.Sort()) return; - for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { - if (*iter == this->selected) { - this->list_pos = iter - this->content.Begin(); - break; - } - } + int idx = find_index(this->content, this->selected); + if (idx >= 0) this->list_pos = idx; } /** Filter content by tags/name */ @@ -479,15 +473,14 @@ class NetworkContentListWindow : public Window, ContentCallback { if (!changed) return; /* update list position */ - for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { - if (*iter == this->selected) { - this->list_pos = iter - this->content.Begin(); - return; - } + int idx = find_index(this->content, this->selected); + if (idx >= 0) { + this->list_pos = idx; + return; } /* previously selected item not in list anymore */ - this->selected = NULL; + this->selected = nullptr; this->list_pos = 0; } @@ -508,7 +501,7 @@ class NetworkContentListWindow : public Window, ContentCallback { /** Make sure that the currently selected content info is within the visible part of the matrix */ void ScrollToSelected() { - if (this->selected == NULL) return; + if (this->selected == nullptr) return; this->vscroll->ScrollTowards(this->list_pos); } @@ -528,7 +521,7 @@ public: Window(desc), auto_select(select_all), filter_editbox(EDITBOX_MAX_SIZE), - selected(NULL), + selected(nullptr), list_pos(0) { this->checkbox_size = maxdim(maxdim(GetSpriteSize(SPR_BOX_EMPTY), GetSpriteSize(SPR_BOX_CHECKED)), GetSpriteSize(SPR_BLOT)); @@ -563,7 +556,7 @@ public: _network_content_client.RemoveCallback(this); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NCL_FILTER_CAPT: @@ -591,7 +584,7 @@ public: } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_NCL_FILTER_CAPT: @@ -608,7 +601,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP; @@ -641,8 +634,12 @@ public: int sprite_y_offset = WD_MATRIX_TOP + (line_height - this->checkbox_size.height) / 2 - 1; int text_y_offset = WD_MATRIX_TOP + (line_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top; - int cnt = 0; - for (ConstContentIterator iter = this->content.Get(this->vscroll->GetPosition()); iter != this->content.End() && cnt < this->vscroll->GetCapacity(); iter++, cnt++) { + + auto iter = this->content.begin() + this->vscroll->GetPosition(); + size_t last = this->vscroll->GetPosition() + this->vscroll->GetCapacity(); + auto end = (last < this->content.size()) ? this->content.begin() + last : this->content.end(); + + for (/**/; iter != end; iter++) { const ContentInfo *ci = *iter; if (ci == this->selected) GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, PC_GREY); @@ -688,7 +685,7 @@ public: SetDParam(0, this->filesize_sum); DrawString(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_NORMAL, STR_CONTENT_TOTAL_DOWNLOAD_SIZE); - if (this->selected == NULL) return; + if (this->selected == nullptr) return; /* And fill the rest of the details when there's information to place there */ DrawStringMultiLine(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + DETAIL_TITLE_HEIGHT / 2, r.top + DETAIL_TITLE_HEIGHT, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER); @@ -767,8 +764,7 @@ public: char buf[DRAW_STRING_BUFFER] = ""; char *p = buf; - for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) { - const ContentInfo *ci = *iter; + for (const ContentInfo *ci : tree) { if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue; p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name); @@ -780,10 +776,10 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) { - if (this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE) return; + if (this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE) return; ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected); return; @@ -792,9 +788,9 @@ public: switch (widget) { case WID_NCL_MATRIX: { uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX); - if (id_v >= this->content.Length()) return; // click out of bounds + if (id_v >= this->content.size()) return; // click out of bounds - this->selected = *this->content.Get(id_v); + this->selected = this->content[id_v]; this->list_pos = id_v; const NWidgetBase *checkbox = this->GetWidget(WID_NCL_CHECKBOX); @@ -816,7 +812,7 @@ public: case WID_NCL_NAME: if (this->content.SortType() == widget - WID_NCL_CHECKBOX) { this->content.ToggleSortOrder(); - if (this->content.Length() > 0) this->list_pos = this->content.Length() - this->list_pos - 1; + if (this->content.size() > 0) this->list_pos = (int)this->content.size() - this->list_pos - 1; } else { this->content.SetSortType(widget - WID_NCL_CHECKBOX); this->content.ForceResort(); @@ -846,14 +842,14 @@ public: break; case WID_NCL_OPEN_URL: - if (this->selected != NULL) { + if (this->selected != nullptr) { extern void OpenBrowser(const char *url); OpenBrowser(this->selected->url); } break; case WID_NCL_DOWNLOAD: - if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == NULL) new NetworkContentDownloadStatusWindow(); + if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == nullptr) new NetworkContentDownloadStatusWindow(); break; case WID_NCL_SEARCH_EXTERNAL: @@ -866,7 +862,7 @@ public: } } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { switch (keycode) { case WKC_UP: @@ -875,7 +871,7 @@ public: break; case WKC_DOWN: /* scroll down by one */ - if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++; + if (this->list_pos < (int)this->content.size() - 1) this->list_pos++; break; case WKC_PAGEUP: /* scroll up a page */ @@ -883,7 +879,7 @@ public: break; case WKC_PAGEDOWN: /* scroll down a page */ - this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.Length() - 1); + this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.size() - 1); break; case WKC_HOME: /* jump to beginning */ @@ -891,13 +887,13 @@ public: break; case WKC_END: /* jump to end */ - this->list_pos = this->content.Length() - 1; + this->list_pos = (int)this->content.size() - 1; break; case WKC_SPACE: case WKC_RETURN: if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { - if (this->selected != NULL) { + if (this->selected != nullptr) { _network_content_client.ToggleSelectedState(this->selected); this->content.ForceResort(); this->InvalidateData(); @@ -915,7 +911,7 @@ public: return ES_NOT_HANDLED; } - if (this->content.Length() == 0) { + if (this->content.size() == 0) { this->list_pos = 0; // above stuff may result in "-1". if (this->UpdateFilterState()) { this->content.ForceRebuild(); @@ -924,7 +920,7 @@ public: return ES_HANDLED; } - this->selected = *this->content.Get(this->list_pos); + this->selected = this->content[this->list_pos]; if (this->UpdateFilterState()) { this->content.ForceRebuild(); @@ -938,7 +934,7 @@ public: return ES_HANDLED; } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { if (wid == WID_NCL_FILTER) { this->filter_data.string_filter.SetFilterTerm(this->filter_editbox.text.buf); @@ -948,25 +944,25 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX); } - virtual void OnReceiveContentInfo(const ContentInfo *rci) + void OnReceiveContentInfo(const ContentInfo *rci) override { if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci); this->content.ForceRebuild(); this->InvalidateData(); } - virtual void OnDownloadComplete(ContentID cid) + void OnDownloadComplete(ContentID cid) override { this->content.ForceResort(); this->InvalidateData(); } - virtual void OnConnect(bool success) + void OnConnect(bool success) override { if (!success) { ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, WL_ERROR); @@ -982,7 +978,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (this->content.NeedRebuild()) this->BuildContentList(); @@ -991,8 +987,7 @@ public: this->filesize_sum = 0; bool show_select_all = false; bool show_select_upgrade = false; - for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { - const ContentInfo *ci = *iter; + for (const ContentInfo *ci : this->content) { switch (ci->state) { case ContentInfo::SELECTED: case ContentInfo::AUTOSELECTED: @@ -1010,13 +1005,13 @@ public: } /* If data == 2 then the status window caused this OnInvalidate */ - this->SetWidgetDisabledState(WID_NCL_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) != NULL && data != 2)); + this->SetWidgetDisabledState(WID_NCL_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) != nullptr && data != 2)); this->SetWidgetDisabledState(WID_NCL_UNSELECT, this->filesize_sum == 0); this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all); this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade); - this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == NULL || StrEmpty(this->selected->url)); + this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == nullptr || StrEmpty(this->selected->url)); for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { - this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == NULL); + this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == nullptr || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == nullptr); } this->GetWidget(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL; @@ -1136,7 +1131,7 @@ static WindowDesc _network_content_list_desc( /** * Show the content list window with a given set of content - * @param cv the content to show, or NULL when it has to search for itself + * @param cv the content to show, or nullptr when it has to search for itself * @param type1 the first type to (only) show or #CONTENT_TYPE_END to show all. * @param type2 the second type to (only) show in addition to type1. If type2 is != #CONTENT_TYPE_END, then also type1 should be != #CONTENT_TYPE_END. * If type2 != #CONTENT_TYPE_END, then type1 != type2 must be true. @@ -1146,7 +1141,7 @@ void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentT #if defined(WITH_ZLIB) std::bitset types; _network_content_client.Clear(); - if (cv == NULL) { + if (cv == nullptr) { assert(type1 != CONTENT_TYPE_END || type2 == CONTENT_TYPE_END); assert(type1 == CONTENT_TYPE_END || type1 != type2); _network_content_client.RequestContentList(type1); @@ -1159,14 +1154,12 @@ void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentT } DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST); - new NetworkContentListWindow(&_network_content_list_desc, cv != NULL, types); + new NetworkContentListWindow(&_network_content_list_desc, cv != nullptr, types); #else ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR); /* Connection failed... clean up the mess */ - if (cv != NULL) { - for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter; + if (cv != nullptr) { + for (ContentInfo *ci : *cv) delete ci; } #endif /* WITH_ZLIB */ } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_content_gui.h b/src/network/network_content_gui.h index 1397010019..8afd245d7c 100644 --- a/src/network/network_content_gui.h +++ b/src/network/network_content_gui.h @@ -39,8 +39,8 @@ public: */ ~BaseNetworkContentDownloadStatusWindow(); - virtual void DrawWidget(const Rect &r, int widget) const; - virtual void OnDownloadProgress(const ContentInfo *ci, int bytes); + void DrawWidget(const Rect &r, int widget) const override; + void OnDownloadProgress(const ContentInfo *ci, int bytes) override; }; void BuildContentTypeStringList(); diff --git a/src/network/network_func.h b/src/network/network_func.h index d3145ea0c7..9d2705ac6c 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -26,8 +26,6 @@ #include "../openttd.h" #include "../company_type.h" -#ifdef ENABLE_NETWORK - extern NetworkServerGameInfo _network_game_info; extern NetworkCompanyState *_network_company_states; @@ -53,7 +51,7 @@ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); void NetworkClientsToSpectators(CompanyID cid); -void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = NULL, const char *join_company_password = NULL); +void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0); @@ -91,5 +89,4 @@ void NetworkChatMessageLoop(); void NetworkAfterNewGRFScan(); -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_FUNC_H */ diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index e5d80630e1..3b3afcb80e 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -12,24 +12,20 @@ * Also, it handles the request to a server for data about the server */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "../debug.h" #include "../window_func.h" -#include "../thread/thread.h" #include "network_internal.h" #include "network_udp.h" #include "network_gamelist.h" +#include #include "../safeguards.h" -NetworkGameList *_network_game_list = NULL; +NetworkGameList *_network_game_list = nullptr; -/** Mutex for handling delayed insertion/querying of servers. */ -static ThreadMutex *_network_game_list_mutex = ThreadMutex::New(); /** The games to insert when the GUI thread has time for us. */ -static NetworkGameList *_network_game_delayed_insertion_list = NULL; +static std::atomic _network_game_delayed_insertion_list(nullptr); /** * Add a new item to the linked gamelist, but do it delayed in the next tick @@ -38,23 +34,21 @@ static NetworkGameList *_network_game_delayed_insertion_list = NULL; */ void NetworkGameListAddItemDelayed(NetworkGameList *item) { - _network_game_list_mutex->BeginCritical(); - item->next = _network_game_delayed_insertion_list; - _network_game_delayed_insertion_list = item; - _network_game_list_mutex->EndCritical(); + item->next = _network_game_delayed_insertion_list.load(std::memory_order_relaxed); + while (!_network_game_delayed_insertion_list.compare_exchange_weak(item->next, item, std::memory_order_acq_rel)) {} } /** Perform the delayed (thread safe) insertion into the game list */ static void NetworkGameListHandleDelayedInsert() { - _network_game_list_mutex->BeginCritical(); - while (_network_game_delayed_insertion_list != NULL) { - NetworkGameList *ins_item = _network_game_delayed_insertion_list; - _network_game_delayed_insertion_list = ins_item->next; + while (true) { + NetworkGameList *ins_item = _network_game_delayed_insertion_list.load(std::memory_order_relaxed); + while (ins_item != nullptr && !_network_game_delayed_insertion_list.compare_exchange_weak(ins_item, ins_item->next, std::memory_order_acq_rel)) {} + if (ins_item == nullptr) break; // No item left. NetworkGameList *item = NetworkGameListAddItem(ins_item->address); - if (item != NULL) { + if (item != nullptr) { if (StrEmpty(item->info.server_name)) { ClearGRFConfigList(&item->info.grfconfig); memset(&item->info, 0, sizeof(item->info)); @@ -68,7 +62,6 @@ static void NetworkGameListHandleDelayedInsert() } free(ins_item); } - _network_game_list_mutex->EndCritical(); } /** @@ -85,22 +78,22 @@ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) if (StrEmpty(hostname) || strcmp(hostname, "0.0.0.0") == 0 || strcmp(hostname, "::") == 0) { - return NULL; + return nullptr; } NetworkGameList *item, *prev_item; - prev_item = NULL; - for (item = _network_game_list; item != NULL; item = item->next) { + prev_item = nullptr; + for (item = _network_game_list; item != nullptr; item = item->next) { if (item->address == address) return item; prev_item = item; } item = CallocT(1); - item->next = NULL; + item->next = nullptr; item->address = address; - if (prev_item == NULL) { + if (prev_item == nullptr) { _network_game_list = item; } else { prev_item->next = item; @@ -118,10 +111,10 @@ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) */ void NetworkGameListRemoveItem(NetworkGameList *remove) { - NetworkGameList *prev_item = NULL; - for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { + NetworkGameList *prev_item = nullptr; + for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) { if (remove == item) { - if (prev_item == NULL) { + if (prev_item == nullptr) { _network_game_list = remove->next; } else { prev_item->next = remove->next; @@ -130,7 +123,7 @@ void NetworkGameListRemoveItem(NetworkGameList *remove) /* Remove GRFConfig information */ ClearGRFConfigList(&remove->info.grfconfig); free(remove); - remove = NULL; + remove = nullptr; DEBUG(net, 4, "[gamelist] removed server from list"); NetworkRebuildHostList(); @@ -155,7 +148,7 @@ void NetworkGameListRequery() if (++requery_cnt < REQUERY_EVERY_X_GAMELOOPS) return; requery_cnt = 0; - for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { + for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) { item->retries++; if (item->retries < REFRESH_GAMEINFO_X_REQUERIES && (item->online || item->retries >= MAX_GAME_LIST_REQUERY_COUNT)) continue; @@ -172,15 +165,15 @@ void NetworkGameListRequery() */ void NetworkAfterNewGRFScan() { - for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { + for (NetworkGameList *item = _network_game_list; item != nullptr; item = item->next) { /* Reset compatibility state */ item->info.compatible = item->info.version_compatible; - for (GRFConfig *c = item->info.grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = item->info.grfconfig; c != nullptr; c = c->next) { assert(HasBit(c->flags, GCF_COPY)); const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum); - if (f == NULL) { + if (f == nullptr) { /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already. */ @@ -206,5 +199,3 @@ void NetworkAfterNewGRFScan() InvalidateWindowClassesData(WC_NETWORK_WINDOW); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 356888a5a2..1f5b5bd4a8 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -9,7 +9,6 @@ /** @file network_gui.cpp Implementation of the Network related GUIs. */ -#ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" @@ -68,18 +67,18 @@ static const StringID _lan_internet_types_dropdown[] = { INVALID_STRING_ID }; -static StringID _language_dropdown[NETLANG_COUNT + 1] = {STR_NULL}; +static std::vector _language_dropdown; void SortNetworkLanguages() { /* Init the strings */ - if (_language_dropdown[0] == STR_NULL) { - for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown[i] = STR_NETWORK_LANG_ANY + i; - _language_dropdown[NETLANG_COUNT] = INVALID_STRING_ID; + if (_language_dropdown.empty()) { + for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown.emplace_back(STR_NETWORK_LANG_ANY + i); + _language_dropdown.emplace_back(INVALID_STRING_ID); } /* Sort the strings (we don't move 'any' and the 'invalid' one) */ - QSortT(_language_dropdown + 1, NETLANG_COUNT - 1, &StringIDSorter); + std::sort(_language_dropdown.begin() + 1, _language_dropdown.end() - 1, StringIDSorter); } /** @@ -122,7 +121,7 @@ public: *lastof(this->visible) = true; } - void SetupSmallestSize(Window *w, bool init_array) + void SetupSmallestSize(Window *w, bool init_array) override { /* Oh yeah, we ought to be findable! */ w->nested_array[WID_NG_HEADER] = this; @@ -134,13 +133,13 @@ public: this->resize_y = 0; // We never resize in this direction /* First initialise some variables... */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); } /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->current_x = child_wid->smallest_x; child_wid->current_y = this->smallest_y; } @@ -148,7 +147,7 @@ public: this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not } - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); @@ -177,7 +176,7 @@ public: uint position = 0; // Place to put next child relative to origin of the container. uint i = rtl ? lengthof(this->visible) - 1 : 0; child_wid = rtl ? this->tail : this->head; - while (child_wid != NULL) { + while (child_wid != nullptr) { if (this->visible[i]) { child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); position += child_wid->current_x; @@ -188,27 +187,27 @@ public: } } - /* virtual */ void Draw(const Window *w) + void Draw(const Window *w) override { int i = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (!this->visible[i++]) continue; child_wid->Draw(w); } } - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y) + NWidgetCore *GetWidgetFromPos(int x, int y) override { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; int i = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (!this->visible[i++]) continue; NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); - if (nwid != NULL) return nwid; + if (nwid != nullptr) return nwid; } - return NULL; + return nullptr; } /** @@ -244,7 +243,7 @@ protected: int lock_offset; ///< Left offset for lock icon. int blot_offset; ///< Left offset for green/yellow/red compatibility icon. - int flag_offset; ///< Left offset for langauge flag icon. + int flag_offset; ///< Left offset for language flag icon. /** * (Re)build the GUI network game list (a.k.a. this->servers) as some @@ -256,10 +255,10 @@ protected: if (!this->servers.NeedRebuild()) return; /* Create temporary array of games to use for listing */ - this->servers.Clear(); + this->servers.clear(); - for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) { - *this->servers.Append() = ngl; + for (NetworkGameList *ngl = _network_game_list; ngl != nullptr; ngl = ngl->next) { + this->servers.push_back(ngl); } /* Apply the filter condition immediately, if a search string has been provided. */ @@ -273,9 +272,9 @@ protected: this->servers.SetFilterState(false); } - this->servers.Compact(); + this->servers.shrink_to_fit(); this->servers.RebuildDone(); - this->vscroll->SetCount(this->servers.Length()); + this->vscroll->SetCount((int)this->servers.size()); /* Sort the list of network games as requested. */ this->servers.Sort(); @@ -283,10 +282,10 @@ protected: } /** Sort servers by name. */ - static int CDECL NGameNameSorter(NetworkGameList * const *a, NetworkGameList * const *b) + static bool NGameNameSorter(NetworkGameList * const &a, NetworkGameList * const &b) { - int r = strnatcmp((*a)->info.server_name, (*b)->info.server_name, true); // Sort by name (natural sorting). - return r == 0 ? (*a)->address.CompareTo((*b)->address) : r; + int r = strnatcmp(a->info.server_name, b->info.server_name, true); // Sort by name (natural sorting). + return r == 0 ? a->address.CompareTo(b->address) < 0: r < 0; } /** @@ -294,60 +293,60 @@ protected: * server. If the two servers have the same amount, the one with the * higher maximum is preferred. */ - static int CDECL NGameClientSorter(NetworkGameList * const *a, NetworkGameList * const *b) + static bool NGameClientSorter(NetworkGameList * const &a, NetworkGameList * const &b) { /* Reverse as per default we are interested in most-clients first */ - int r = (*a)->info.clients_on - (*b)->info.clients_on; + int r = a->info.clients_on - b->info.clients_on; - if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max; - if (r == 0) r = NGameNameSorter(a, b); + if (r == 0) r = a->info.clients_max - b->info.clients_max; + if (r == 0) return NGameNameSorter(a, b); - return r; + return r < 0; } /** Sort servers by map size */ - static int CDECL NGameMapSizeSorter(NetworkGameList * const *a, NetworkGameList * const *b) + static bool NGameMapSizeSorter(NetworkGameList * const &a, NetworkGameList * const &b) { /* Sort by the area of the map. */ - int r = ((*a)->info.map_height) * ((*a)->info.map_width) - ((*b)->info.map_height) * ((*b)->info.map_width); + int r = (a->info.map_height) * (a->info.map_width) - (b->info.map_height) * (b->info.map_width); - if (r == 0) r = (*a)->info.map_width - (*b)->info.map_width; - return (r != 0) ? r : NGameClientSorter(a, b); + if (r == 0) r = a->info.map_width - b->info.map_width; + return (r != 0) ? r < 0 : NGameClientSorter(a, b); } /** Sort servers by current date */ - static int CDECL NGameDateSorter(NetworkGameList * const *a, NetworkGameList * const *b) + static bool NGameDateSorter(NetworkGameList * const &a, NetworkGameList * const &b) { - int r = (*a)->info.game_date - (*b)->info.game_date; - return (r != 0) ? r : NGameClientSorter(a, b); + int r = a->info.game_date - b->info.game_date; + return (r != 0) ? r < 0 : NGameClientSorter(a, b); } /** Sort servers by the number of days the game is running */ - static int CDECL NGameYearsSorter(NetworkGameList * const *a, NetworkGameList * const *b) + static bool NGameYearsSorter(NetworkGameList * const &a, NetworkGameList * const &b) { - int r = (*a)->info.game_date - (*a)->info.start_date - (*b)->info.game_date + (*b)->info.start_date; - return (r != 0) ? r : NGameDateSorter(a, b); + int r = a->info.game_date - a->info.start_date - b->info.game_date + b->info.start_date; + return (r != 0) ? r < 0: NGameDateSorter(a, b); } /** * Sort servers by joinability. If both servers are the * same, prefer the non-passworded server first. */ - static int CDECL NGameAllowedSorter(NetworkGameList * const *a, NetworkGameList * const *b) + static bool NGameAllowedSorter(NetworkGameList * const &a, NetworkGameList * const &b) { /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */ - int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision); + int r = StrEmpty(a->info.server_revision) - StrEmpty(b->info.server_revision); /* Reverse default as we are interested in version-compatible clients first */ - if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible; + if (r == 0) r = b->info.version_compatible - a->info.version_compatible; /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */ - if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible; + if (r == 0) r = b->info.compatible - a->info.compatible; /* Passworded servers should be below unpassworded servers */ - if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password; + if (r == 0) r = a->info.use_password - b->info.use_password; /* Finally sort on the number of clients of the server */ - if (r == 0) r = -NGameClientSorter(a, b); + if (r == 0) return NGameClientSorter(a, b); - return r; + return r < 0; } /** Sort the server list */ @@ -360,7 +359,7 @@ protected: void UpdateListPos() { this->list_pos = SLP_INVALID; - for (uint i = 0; i != this->servers.Length(); i++) { + for (uint i = 0; i != this->servers.size(); i++) { if (this->servers[i] == this->server) { this->list_pos = i; break; @@ -370,8 +369,8 @@ protected: static bool CDECL NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf) { - assert(item != NULL); - assert((*item) != NULL); + assert(item != nullptr); + assert((*item) != nullptr); sf.ResetState(); sf.AddLine((*item)->info.server_name); @@ -467,7 +466,7 @@ public: NetworkGameWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_CLIENT_NAME_LENGTH), filter_editbox(120) { this->list_pos = SLP_INVALID; - this->server = NULL; + this->server = nullptr; this->lock_offset = 5; this->blot_offset = this->lock_offset + 3 + GetSpriteSize(SPR_LOCK).width; @@ -487,7 +486,7 @@ public: this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); this->server = this->last_joined; - if (this->last_joined != NULL) NetworkUDPQueryServer(this->last_joined->address); + if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address); this->requery_timer.SetInterval(MILLISECONDS_PER_TICK); @@ -502,7 +501,7 @@ public: this->last_sorting = this->servers.GetListing(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_NG_CONN_BTN: @@ -511,7 +510,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NG_CONN_BTN: @@ -566,13 +565,13 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_NG_MATRIX: { uint16 y = r.top; - const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.Length()); + const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.size()); for (int i = this->vscroll->GetPosition(); i < max; ++i) { const NetworkGameList *ngl = this->servers[i]; @@ -584,7 +583,7 @@ public: case WID_NG_LASTJOINED: /* Draw the last joined server, if any */ - if (this->last_joined != NULL) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server); + if (this->last_joined != nullptr) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server); break; case WID_NG_DETAILS: @@ -603,7 +602,7 @@ public: } - virtual void OnPaint() + void OnPaint() override { if (this->servers.NeedRebuild()) { this->BuildGUINetworkGameList(); @@ -614,16 +613,16 @@ public: NetworkGameList *sel = this->server; /* 'Refresh' button invisible if no server selected */ - this->SetWidgetDisabledState(WID_NG_REFRESH, sel == NULL); + this->SetWidgetDisabledState(WID_NG_REFRESH, sel == nullptr); /* 'Join' button disabling conditions */ - this->SetWidgetDisabledState(WID_NG_JOIN, sel == NULL || // no Selected Server + this->SetWidgetDisabledState(WID_NG_JOIN, sel == nullptr || // no Selected Server !sel->online || // Server offline sel->info.clients_on >= sel->info.clients_max || // Server full (!sel->info.compatible && !_ctrl_pressed)); // Revision mismatch /* 'NewGRF Settings' button invisible if no NewGRF is used */ - this->GetWidget(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL); - this->GetWidget(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL || !sel->info.version_compatible || sel->info.compatible); + this->GetWidget(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr); + this->GetWidget(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible); this->DrawWidgets(); } @@ -636,7 +635,7 @@ public: /* Draw the right menu */ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE); - if (sel == NULL) { + if (sel == nullptr) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER); } else if (!sel->online) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name @@ -699,7 +698,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NG_CANCEL: // Cancel button @@ -718,7 +717,7 @@ public: case WID_NG_INFO: // Connectivity (green dot) if (this->servers.SortType() == widget - WID_NG_NAME) { this->servers.ToggleSortOrder(); - if (this->list_pos != SLP_INVALID) this->list_pos = this->servers.Length() - this->list_pos - 1; + if (this->list_pos != SLP_INVALID) this->list_pos = (ServerListPosition)this->servers.size() - this->list_pos - 1; } else { this->servers.SetSortType(widget - WID_NG_NAME); this->servers.ForceResort(); @@ -730,8 +729,8 @@ public: case WID_NG_MATRIX: { // Show available network games uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX); - this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL; - this->list_pos = (server == NULL) ? SLP_INVALID : id_v; + this->server = (id_v < this->servers.size()) ? this->servers[id_v] : nullptr; + this->list_pos = (server == nullptr) ? SLP_INVALID : id_v; this->SetDirty(); /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */ @@ -740,7 +739,7 @@ public: } case WID_NG_LASTJOINED: { - if (this->last_joined != NULL) { + if (this->last_joined != nullptr) { this->server = this->last_joined; /* search the position of the newly selected server */ @@ -775,7 +774,7 @@ public: break; case WID_NG_JOIN: // Join Game - if (this->server != NULL) { + if (this->server != nullptr) { seprintf(_settings_client.network.last_host, lastof(_settings_client.network.last_host), "%s", this->server->address.GetHostname()); _settings_client.network.last_port = this->server->address.GetPort(); if (this->server->info.compatible) { @@ -794,15 +793,15 @@ public: break; case WID_NG_REFRESH: // Refresh - if (this->server != NULL) NetworkUDPQueryServer(this->server->address); + if (this->server != nullptr) NetworkUDPQueryServer(this->server->address); break; case WID_NG_NEWGRF: // NewGRF Settings - if (this->server != NULL) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig); + if (this->server != nullptr) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig); break; case WID_NG_NEWGRF_MISSING: // Find missing content online - if (this->server != NULL) ShowMissingContentWindow(this->server->info.grfconfig); + if (this->server != nullptr) ShowMissingContentWindow(this->server->info.grfconfig); break; case WID_NG_NICE: case WID_NG_BTPRO: @@ -824,7 +823,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_NG_CONN_BTN: @@ -843,19 +842,19 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { this->servers.ForceRebuild(); this->SetDirty(); } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { EventState state = ES_NOT_HANDLED; /* handle up, down, pageup, pagedown, home and end */ if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) { - if (this->servers.Length() == 0) return ES_HANDLED; + if (this->servers.size() == 0) return ES_HANDLED; switch (keycode) { case WKC_UP: /* scroll up by one */ @@ -865,7 +864,7 @@ public: case WKC_DOWN: /* scroll down by one */ if (this->list_pos == SLP_INVALID) return ES_HANDLED; - if (this->list_pos < this->servers.Length() - 1) this->list_pos++; + if (this->list_pos < this->servers.size() - 1) this->list_pos++; break; case WKC_PAGEUP: /* scroll up a page */ @@ -875,7 +874,7 @@ public: case WKC_PAGEDOWN: /* scroll down a page */ if (this->list_pos == SLP_INVALID) return ES_HANDLED; - this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.Length() - 1); + this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1); break; case WKC_HOME: /* jump to beginning */ @@ -883,7 +882,7 @@ public: break; case WKC_END: /* jump to end */ - this->list_pos = this->servers.Length() - 1; + this->list_pos = (ServerListPosition)this->servers.size() - 1; break; default: NOT_REACHED(); } @@ -898,11 +897,11 @@ public: return ES_HANDLED; } - if (this->server != NULL) { + if (this->server != nullptr) { if (keycode == WKC_DELETE) { // Press 'delete' to remove servers NetworkGameListRemoveItem(this->server); - if (this->server == this->last_joined) this->last_joined = NULL; - this->server = NULL; + if (this->server == this->last_joined) this->last_joined = nullptr; + this->server = nullptr; this->list_pos = SLP_INVALID; } } @@ -910,7 +909,7 @@ public: return state; } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { switch (wid) { case WID_NG_FILTER: { @@ -932,17 +931,17 @@ public: } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (!StrEmpty(str)) NetworkAddServer(str); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (!this->requery_timer.Elapsed(delta_ms)) return; this->requery_timer.SetInterval(MILLISECONDS_PER_TICK); @@ -1085,8 +1084,8 @@ void ShowNetworkGameWindow() if (first) { first = false; /* Add all servers from the config file to our list. */ - for (char **iter = _network_host_list.Begin(); iter != _network_host_list.End(); iter++) { - NetworkAddServer(*iter); + for (const auto &iter : _network_host_list) { + NetworkAddServer(iter.c_str()); } } @@ -1107,7 +1106,7 @@ struct NetworkStartServerWindow : public Window { this->SetFocusedWidget(WID_NSS_GAMENAME); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_NSS_CONNTYPE_BTN: @@ -1132,7 +1131,7 @@ struct NetworkStartServerWindow : public Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NSS_CONNTYPE_BTN: @@ -1143,7 +1142,7 @@ struct NetworkStartServerWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_NSS_SETPWD: @@ -1152,7 +1151,7 @@ struct NetworkStartServerWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NSS_CANCEL: // Cancel button @@ -1212,13 +1211,13 @@ struct NetworkStartServerWindow : public Window { case WID_NSS_LANGUAGE_BTN: { // Language uint sel = 0; - for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) { + for (uint i = 0; i < _language_dropdown.size() - 1; i++) { if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) { sel = i; break; } } - ShowDropDownMenu(this, _language_dropdown, sel, WID_NSS_LANGUAGE_BTN, 0, 0); + ShowDropDownMenu(this, _language_dropdown.data(), sel, WID_NSS_LANGUAGE_BTN, 0, 0); break; } @@ -1248,7 +1247,7 @@ struct NetworkStartServerWindow : public Window { } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_NSS_CONNTYPE_BTN: @@ -1264,14 +1263,14 @@ struct NetworkStartServerWindow : public Window { this->SetDirty(); } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { if (wid == WID_NSS_GAMENAME) { strecpy(_settings_client.network.server_name, this->name_editbox.text.buf, lastof(_settings_client.network.server_name)); } } - virtual void OnTimeout() + void OnTimeout() override { static const int raise_widgets[] = {WID_NSS_CLIENTS_BTND, WID_NSS_CLIENTS_BTNU, WID_NSS_COMPANIES_BTND, WID_NSS_COMPANIES_BTNU, WID_NSS_SPECTATORS_BTND, WID_NSS_SPECTATORS_BTNU, WIDGET_LIST_END}; for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) { @@ -1282,9 +1281,9 @@ struct NetworkStartServerWindow : public Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; if (this->widget_id == WID_NSS_SETPWD) { strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password)); @@ -1384,7 +1383,7 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = { }; static WindowDesc _network_start_server_window_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets) @@ -1424,7 +1423,7 @@ struct NetworkLobbyWindow : public Window { return COMPANY_FIRST; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NL_HEADER: @@ -1443,7 +1442,7 @@ struct NetworkLobbyWindow : public Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_NL_TEXT: @@ -1452,7 +1451,7 @@ struct NetworkLobbyWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_NL_DETAILS: @@ -1465,7 +1464,7 @@ struct NetworkLobbyWindow : public Window { } } - virtual void OnPaint() + void OnPaint() override { const NetworkGameInfo *gi = &this->server->info; @@ -1588,7 +1587,7 @@ struct NetworkLobbyWindow : public Window { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NL_CANCEL: // Cancel button @@ -1627,7 +1626,7 @@ struct NetworkLobbyWindow : public Window { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX); } @@ -1673,7 +1672,7 @@ static const NWidgetPart _nested_network_lobby_window_widgets[] = { }; static WindowDesc _network_lobby_window_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets) @@ -1702,7 +1701,7 @@ static void ShowNetworkLobbyWindow(NetworkGameList *ngl) NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company) { NetworkLobbyWindow *lobby = dynamic_cast(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY)); - return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL; + return (lobby != nullptr && company < MAX_COMPANIES) ? &lobby->company_info[company] : nullptr; } /* The window below gives information about the connected clients @@ -1722,7 +1721,7 @@ static const NWidgetPart _nested_client_list_popup_widgets[] = { }; static WindowDesc _client_list_popup_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_CLIENT_LIST_POPUP, WC_CLIENT_LIST, 0, _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets) @@ -1778,7 +1777,7 @@ struct NetworkClientListPopupWindow : Window { uint sel_index; ClientID client_id; Point desired_location; - SmallVector actions; ///< Actions to execute + std::vector actions; ///< Actions to execute /** * Add an action to the list of actions to execute. @@ -1787,9 +1786,7 @@ struct NetworkClientListPopupWindow : Window { */ inline void AddAction(StringID name, ClientList_Action_Proc *proc) { - ClientListAction *action = this->actions.Append(); - action->name = name; - action->proc = proc; + this->actions.push_back({name, proc}); } NetworkClientListPopupWindow(WindowDesc *desc, int x, int y, ClientID client_id) : @@ -1830,30 +1827,30 @@ struct NetworkClientListPopupWindow : Window { CLRBITS(this->flags, WF_WHITE_BORDER); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { return this->desired_location; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { Dimension d = *size; - for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++) { - d = maxdim(GetStringBoundingBox(action->name), d); + for (const ClientListAction &action : this->actions) { + d = maxdim(GetStringBoundingBox(action.name), d); } - d.height *= this->actions.Length(); + d.height *= (uint)this->actions.size(); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { /* Draw the actions */ int sel = this->sel_index; int y = r.top + WD_FRAMERECT_TOP; - for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++, y += FONT_HEIGHT_NORMAL) { + for (const ClientListAction &action : this->actions) { TextColour colour; if (sel-- == 0) { // Selected item, highlight it GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK); @@ -1862,24 +1859,25 @@ struct NetworkClientListPopupWindow : Window { colour = TC_BLACK; } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action->name, colour); + DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action.name, colour); + y += FONT_HEIGHT_NORMAL; } } - virtual void OnMouseLoop() + void OnMouseLoop() override { /* We selected an action */ uint index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL; if (_left_button_down) { - if (index == this->sel_index || index >= this->actions.Length()) return; + if (index == this->sel_index || index >= this->actions.size()) return; this->sel_index = index; this->SetDirty(); } else { - if (index < this->actions.Length() && _cursor.pos.y >= this->top) { + if (index < this->actions.size() && _cursor.pos.y >= this->top) { const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id); - if (ci != NULL) this->actions[index].proc(ci); + if (ci != nullptr) this->actions[index].proc(ci); } DeleteWindowByClass(WC_CLIENT_LIST_POPUP); @@ -1894,7 +1892,7 @@ static void PopupClientList(ClientID client_id, int x, int y) { DeleteWindowByClass(WC_CLIENT_LIST_POPUP); - if (NetworkClientInfo::GetByClientID(client_id) == NULL) return; + if (NetworkClientInfo::GetByClientID(client_id) == nullptr) return; new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id); } @@ -1957,7 +1955,7 @@ struct NetworkClientListWindow : Window { return true; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_CL_PANEL) return; @@ -1976,7 +1974,7 @@ struct NetworkClientListWindow : Window { size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT + width2; } - virtual void OnPaint() + void OnPaint() override { /* Check if we need to reset the height */ if (!this->CheckClientListHeight()) return; @@ -1984,7 +1982,7 @@ struct NetworkClientListWindow : Window { this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_CL_PANEL) return; @@ -2035,7 +2033,7 @@ struct NetworkClientListWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { /* Show the popup with option */ if (this->selected_item != -1) { @@ -2047,11 +2045,11 @@ struct NetworkClientListWindow : Window { client_no--; } - if (ci != NULL) PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top); + if (ci != nullptr) PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top); } } - virtual void OnMouseOver(Point pt, int widget) + void OnMouseOver(Point pt, int widget) override { /* -1 means we left the current window */ if (pt.y == -1) { @@ -2095,7 +2093,7 @@ struct NetworkJoinStatusWindow : Window { this->InitNested(WN_NETWORK_STATUS_WINDOW_JOIN); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_NJS_BACKGROUND) return; @@ -2129,7 +2127,7 @@ struct NetworkJoinStatusWindow : Window { DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_NJS_BACKGROUND) return; @@ -2155,7 +2153,7 @@ struct NetworkJoinStatusWindow : Window { size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget == WID_NJS_CANCELOK) { // Disconnect button NetworkDisconnect(); @@ -2164,7 +2162,7 @@ struct NetworkJoinStatusWindow : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (StrEmpty(str)) { NetworkDisconnect(); @@ -2194,7 +2192,7 @@ static const NWidgetPart _nested_network_join_status_window_widgets[] = { }; static WindowDesc _network_join_status_window_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets) @@ -2209,7 +2207,7 @@ void ShowJoinStatusWindow() void ShowNetworkNeedPassword(NetworkPasswordType npt) { NetworkJoinStatusWindow *w = (NetworkJoinStatusWindow *)FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); - if (w == NULL) return; + if (w == nullptr) return; w->password_type = npt; StringID caption; @@ -2218,15 +2216,17 @@ void ShowNetworkNeedPassword(NetworkPasswordType npt) case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break; case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break; } - ShowQueryString(STR_EMPTY, caption, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_NONE); + ShowQueryString(STR_EMPTY, caption, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_PASSWORD); } struct NetworkCompanyPasswordWindow : public Window { QueryString password_editbox; ///< Password editbox. + Dimension warning_size; ///< How much space to use for the warning text NetworkCompanyPasswordWindow(WindowDesc *desc, Window *parent) : Window(desc), password_editbox(lengthof(_settings_client.network.default_company_pass)) { this->InitNested(0); + this->UpdateWarningStringSize(); this->parent = parent; this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox; @@ -2235,6 +2235,32 @@ struct NetworkCompanyPasswordWindow : public Window { this->SetFocusedWidget(WID_NCP_PASSWORD); } + void UpdateWarningStringSize() + { + assert(this->nested_root->smallest_x > 0); + this->warning_size.width = this->nested_root->current_x - (WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT); + this->warning_size.height = GetStringHeight(STR_WARNING_PASSWORD_SECURITY, this->warning_size.width); + this->warning_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + + this->ReInit(); + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + { + if (widget == WID_NCP_WARNING) { + *size = this->warning_size; + } + } + + void DrawWidget(const Rect &r, int widget) const override + { + if (widget != WID_NCP_WARNING) return; + + DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, + r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, + STR_WARNING_PASSWORD_SECURITY, TC_FROMSTRING, SA_CENTER); + } + void OnOk() { if (this->IsWidgetLowered(WID_NCP_SAVE_AS_DEFAULT_PASSWORD)) { @@ -2244,7 +2270,7 @@ struct NetworkCompanyPasswordWindow : public Window { NetworkChangeCompanyPassword(_local_company, this->password_editbox.text.buf); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NCP_OK: @@ -2281,6 +2307,7 @@ static const NWidgetPart _nested_network_company_password_window_widgets[] = { EndContainer(), EndContainer(), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_WARNING), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK), @@ -2288,7 +2315,7 @@ static const NWidgetPart _nested_network_company_password_window_widgets[] = { }; static WindowDesc _network_company_password_window_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_COMPANY_PASSWORD_WINDOW, WC_NONE, 0, _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets) @@ -2300,5 +2327,3 @@ void ShowNetworkCompanyPasswordWindow(Window *parent) new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_gui.h b/src/network/network_gui.h index a196c75e9f..d9dfb57dd6 100644 --- a/src/network/network_gui.h +++ b/src/network/network_gui.h @@ -17,8 +17,6 @@ #include "../window_type.h" #include "network_type.h" -#ifdef ENABLE_NETWORK - void ShowNetworkNeedPassword(NetworkPasswordType npt); void ShowNetworkGiveMoneyWindow(CompanyID company); void ShowNetworkChatQueryWindow(DestType type, int dest); @@ -42,14 +40,4 @@ struct NetworkCompanyInfo : NetworkCompanyStats { NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company); -#else /* ENABLE_NETWORK */ -/* Network function stubs when networking is disabled */ - -static inline void ShowNetworkChatQueryWindow(byte desttype, int dest) {} -static inline void ShowClientList() {} -static inline void ShowNetworkGameWindow() {} -static inline void ShowNetworkCompanyPasswordWindow(Window *parent) {} - -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_GUI_H */ diff --git a/src/network/network_internal.h b/src/network/network_internal.h index ed9a8de6f6..06dca992f7 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -17,8 +17,6 @@ #include "../command_type.h" -#ifdef ENABLE_NETWORK - #ifdef RANDOM_DEBUG /** * If this line is enable, every frame will have a sync test @@ -151,8 +149,8 @@ bool IsNetworkCompatibleVersion(const char *version); * Everything we need to know about a command to be able to execute it. */ struct CommandPacket : CommandContainer { - /** Make sure the pointer is NULL. */ - CommandPacket() : next(NULL), company(INVALID_COMPANY), frame(0), my_cmd(false) {} + /** Make sure the pointer is nullptr. */ + CommandPacket() : next(nullptr), company(INVALID_COMPANY), frame(0), my_cmd(false) {} CommandPacket *next; ///< the next command packet (if in queue) CompanyID company; ///< company that is executing the command uint32 frame; ///< the frame in which this packet is executed @@ -171,5 +169,4 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err); bool NetworkFindName(char *new_name, const char *last); const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed); -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_INTERNAL_H */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 148a455062..6d9dcc3d8c 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -9,8 +9,6 @@ /** @file network_server.cpp Server part of the network protocol. */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" @@ -32,6 +30,8 @@ #include "../core/pool_func.hpp" #include "../core/random_func.hpp" #include "../rev.h" +#include +#include #include "../safeguards.h" @@ -60,47 +60,40 @@ struct PacketWriter : SaveFilter { Packet *current; ///< The packet we're currently writing to. size_t total_size; ///< Total size of the compressed savegame. Packet *packets; ///< Packet queue of the savegame; send these "slowly" to the client. - ThreadMutex *mutex; ///< Mutex for making threaded saving safe. + std::mutex mutex; ///< Mutex for making threaded saving safe. + std::condition_variable exit_sig; ///< Signal for threaded destruction of this packet writer. /** * Create the packet writer. * @param cs The socket handler we're making the packets for. */ - PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0), packets(NULL) + PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(nullptr), cs(cs), current(nullptr), total_size(0), packets(nullptr) { - this->mutex = ThreadMutex::New(); } /** Make sure everything is cleaned up. */ ~PacketWriter() { - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::unique_lock lock(this->mutex); - if (this->cs != NULL && this->mutex != NULL) { - this->mutex->WaitForSignal(); - } + if (this->cs != nullptr) this->exit_sig.wait(lock); /* This must all wait until the Destroy function is called. */ - while (this->packets != NULL) { + while (this->packets != nullptr) { Packet *p = this->packets->next; delete this->packets; this->packets = p; } delete this->current; - - if (this->mutex != NULL) this->mutex->EndCritical(); - - delete this->mutex; - this->mutex = NULL; } /** * Begin the destruction of this packet writer. It can happen in two ways: * in the first case the client disconnected while saving the map. In this * case the saving has not finished and killed this PacketWriter. In that - * case we simply set cs to NULL, triggering the appending to fail due to + * case we simply set cs to nullptr, triggering the appending to fail due to * the connection problem and eventually triggering the destructor. In the * second case the destructor is already called, and it is waiting for our * signal which we will send. Only then the packets will be removed by the @@ -108,13 +101,12 @@ struct PacketWriter : SaveFilter { */ void Destroy() { - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::unique_lock lock(this->mutex); - this->cs = NULL; + this->cs = nullptr; - if (this->mutex != NULL) this->mutex->SendSignal(); - - if (this->mutex != NULL) this->mutex->EndCritical(); + this->exit_sig.notify_all(); + lock.unlock(); /* Make sure the saving is completely cancelled. Yes, * we need to handle the save finish as well as the @@ -132,7 +124,7 @@ struct PacketWriter : SaveFilter { */ bool HasPackets() { - return this->packets != NULL; + return this->packets != nullptr; } /** @@ -140,13 +132,11 @@ struct PacketWriter : SaveFilter { */ Packet *PopPacket() { - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::lock_guard lock(this->mutex); Packet *p = this->packets; this->packets = p->next; - p->next = NULL; - - if (this->mutex != NULL) this->mutex->EndCritical(); + p->next = nullptr; return p; } @@ -154,25 +144,25 @@ struct PacketWriter : SaveFilter { /** Append the current packet to the queue. */ void AppendQueue() { - if (this->current == NULL) return; + if (this->current == nullptr) return; Packet **p = &this->packets; - while (*p != NULL) { + while (*p != nullptr) { p = &(*p)->next; } *p = this->current; - this->current = NULL; + this->current = nullptr; } - /* virtual */ void Write(byte *buf, size_t size) + void Write(byte *buf, size_t size) override { /* We want to abort the saving when the socket is closed. */ - if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); + if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); - if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA); + if (this->current == nullptr) this->current = new Packet(PACKET_SERVER_MAP_DATA); - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::lock_guard lock(this->mutex); byte *bufe = buf + size; while (buf != bufe) { @@ -187,17 +177,15 @@ struct PacketWriter : SaveFilter { } } - if (this->mutex != NULL) this->mutex->EndCritical(); - this->total_size += size; } - /* virtual */ void Finish() + void Finish() override { /* We want to abort the saving when the socket is closed. */ - if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); + if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::lock_guard lock(this->mutex); /* Make sure the last packet is flushed. */ this->AppendQueue(); @@ -210,8 +198,6 @@ struct PacketWriter : SaveFilter { Packet *p = new Packet(PACKET_SERVER_MAP_SIZE); p->Send_uint32((uint32)this->total_size); this->cs->NetworkTCPSocketHandler::SendPacket(p); - - if (this->mutex != NULL) this->mutex->EndCritical(); } }; @@ -240,9 +226,9 @@ ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler() if (_redirect_console_to_client == this->client_id) _redirect_console_to_client = INVALID_CLIENT_ID; OrderBackup::ResetUser(this->client_id); - if (this->savegame != NULL) { + if (this->savegame != nullptr) { this->savegame->Destroy(); - this->savegame = NULL; + this->savegame = nullptr; } } @@ -250,12 +236,12 @@ Packet *ServerNetworkGameSocketHandler::ReceivePacket() { /* Only allow receiving when we have some buffer free; this value * can go negative, but eventually it will become positive again. */ - if (this->receive_limit <= 0) return NULL; + if (this->receive_limit <= 0) return nullptr; /* We can receive a packet, so try that and if needed account for * the amount of received data. */ Packet *p = this->NetworkTCPSocketHandler::ReceivePacket(); - if (p != NULL) this->receive_limit -= p->size; + if (p != nullptr) this->receive_limit -= p->size; return p; } @@ -278,7 +264,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta this->GetClientName(client_name, lastof(client_name)); - NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST); + NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST); /* Inform other clients of this... strange leaving ;) */ FOR_ALL_CLIENT_SOCKETS(new_cs) { @@ -375,7 +361,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo() /* Add the local player (if not dedicated) */ const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); - if (ci != NULL && Company::IsValidID(ci->client_playas)) { + if (ci != nullptr && Company::IsValidID(ci->client_playas)) { strecpy(clients[ci->client_playas], ci->client_name, lastof(clients[ci->client_playas])); } @@ -385,7 +371,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo() ((ServerNetworkGameSocketHandler*)csi)->GetClientName(client_name, lastof(client_name)); ci = csi->GetInfo(); - if (ci != NULL && Company::IsValidID(ci->client_playas)) { + if (ci != nullptr && Company::IsValidID(ci->client_playas)) { if (!StrEmpty(clients[ci->client_playas])) { strecat(clients[ci->client_playas], ", ", lastof(clients[ci->client_playas])); } @@ -448,7 +434,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str); - NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid); + NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, strid); FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { @@ -477,12 +463,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck() const GRFConfig *c; uint grf_count = 0; - for (c = _grfconfig; c != NULL; c = c->next) { + for (c = _grfconfig; c != nullptr; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) grf_count++; } p->Send_uint8 (grf_count); - for (c = _grfconfig; c != NULL; c = c->next) { + for (c = _grfconfig; c != nullptr; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); } @@ -621,7 +607,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap() if (last_packet) { /* Done reading, make sure saving is done as well */ this->savegame->Destroy(); - this->savegame = NULL; + this->savegame = nullptr; /* Set the status to DONE_MAP, no we will wait for the client * to send it is ready (maybe that happens like never ;)) */ @@ -629,17 +615,17 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap() /* Find the best candidate for joining, i.e. the first joiner. */ NetworkClientSocket *new_cs; - NetworkClientSocket *best = NULL; + NetworkClientSocket *best = nullptr; FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status == STATUS_MAP_WAIT) { - if (best == NULL || best->GetInfo()->join_date > new_cs->GetInfo()->join_date || (best->GetInfo()->join_date == new_cs->GetInfo()->join_date && best->client_id > new_cs->client_id)) { + if (best == nullptr || best->GetInfo()->join_date > new_cs->GetInfo()->join_date || (best->GetInfo()->join_date == new_cs->GetInfo()->join_date && best->client_id > new_cs->client_id)) { best = new_cs; } } } /* Is there someone else to join? */ - if (best != NULL) { + if (best != nullptr) { /* Let the first start joining. */ best->status = STATUS_AUTHORIZED; best->SendMap(); @@ -960,9 +946,9 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) this->status = STATUS_NEWGRFS_CHECK; - if (_grfconfig == NULL) { + if (_grfconfig == nullptr) { /* Behave as if we received PACKET_CLIENT_NEWGRFS_CHECKED */ - return this->Receive_CLIENT_NEWGRFS_CHECKED(NULL); + return this->Receive_CLIENT_NEWGRFS_CHECKED(nullptr); } return this->SendNewGRFCheck(); @@ -1046,7 +1032,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet * this->GetClientName(client_name, lastof(client_name)); - NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, NULL, this->client_id); + NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, nullptr, this->client_id); /* Mark the client as pre-active, and wait for an ACK * so we know he is done loading and in sync with us */ @@ -1103,7 +1089,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet NetworkClientInfo *ci = this->GetInfo(); - if (err != NULL) { + if (err != nullptr) { IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, this->GetClientIP()); return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } @@ -1169,7 +1155,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str); - NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid); + NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, strid); FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED) { @@ -1196,7 +1182,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) this->GetClientName(client_name, lastof(client_name)); - NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING); + NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, STR_NETWORK_MESSAGE_CLIENT_LEAVING); FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { @@ -1220,7 +1206,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p) /* The client is trying to catch up with the server */ if (this->status == STATUS_PRE_ACTIVE) { - /* The client is not yet catched up? */ + /* The client is not yet caught up? */ if (frame + DAY_TICKS < _frame_counter) return NETWORK_RECV_STATUS_OKAY; /* Now he is! Unpause the game */ @@ -1276,7 +1262,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co if ((ClientID)dest == CLIENT_ID_SERVER) { ci = NetworkClientInfo::GetByClientID(from_id); /* Display the text locally, and that is it */ - if (ci != NULL) { + if (ci != nullptr) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data); if (_settings_client.network.server_admin_chat) { @@ -1298,7 +1284,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co if (from_id == CLIENT_ID_SERVER) { ci = NetworkClientInfo::GetByClientID(from_id); ci_to = NetworkClientInfo::GetByClientID((ClientID)dest); - if (ci != NULL && ci_to != NULL) { + if (ci != nullptr && ci_to != nullptr) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data); } } else { @@ -1315,10 +1301,10 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co /* If this is false, the message is already displayed on the client who sent it. */ bool show_local = true; /* Find all clients that belong to this company */ - ci_to = NULL; + ci_to = nullptr; FOR_ALL_CLIENT_SOCKETS(cs) { ci = cs->GetInfo(); - if (ci != NULL && ci->client_playas == (CompanyID)dest) { + if (ci != nullptr && ci->client_playas == (CompanyID)dest) { cs->SendChat(action, from_id, false, msg, data); if (cs->client_id == from_id) show_local = false; ci_to = ci; // Remember a client that is in the company for company-name @@ -1332,17 +1318,17 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co ci = NetworkClientInfo::GetByClientID(from_id); ci_own = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); - if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) { + if (ci != nullptr && ci_own != nullptr && ci_own->client_playas == dest) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data); if (from_id == CLIENT_ID_SERVER) show_local = false; ci_to = ci_own; } /* There is no such client */ - if (ci_to == NULL) break; + if (ci_to == nullptr) break; /* Display the message locally (so you know you have sent it) */ - if (ci != NULL && show_local) { + if (ci != nullptr && show_local) { if (from_id == CLIENT_ID_SERVER) { char name[NETWORK_NAME_LENGTH]; StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS; @@ -1371,7 +1357,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co NetworkAdminChat(action, desttype, from_id, msg, data, from_admin); ci = NetworkClientInfo::GetByClientID(from_id); - if (ci != NULL) { + if (ci != nullptr) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data); } break; @@ -1442,7 +1428,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; - if (ci != NULL) { + if (ci != nullptr) { /* Display change */ if (NetworkFindName(client_name, lastof(client_name))) { NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name); @@ -1605,7 +1591,7 @@ void NetworkUpdateClientInfo(ClientID client_id) NetworkClientSocket *cs; NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); - if (ci == NULL) return; + if (ci == nullptr) return; DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id); @@ -1726,7 +1712,7 @@ bool NetworkFindName(char *new_name, const char *last) } /* Check if it is the same as the server-name */ ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); - if (ci != NULL) { + if (ci != nullptr) { if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use } @@ -1757,7 +1743,7 @@ bool NetworkServerChangeClientName(ClientID client_id, const char *new_name) } ci = NetworkClientInfo::GetByClientID(client_id); - if (ci == NULL) return false; + if (ci == nullptr) return false; NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name); @@ -1792,7 +1778,7 @@ void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, static void NetworkHandleCommandQueue(NetworkClientSocket *cs) { CommandPacket *cp; - while ((cp = cs->outgoing_queue.Pop()) != NULL) { + while ((cp = cs->outgoing_queue.Pop()) != nullptr) { cs->SendCommand(cp); free(cp); } @@ -1978,7 +1964,7 @@ void NetworkServerShowStatusToConsole() NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { NetworkClientInfo *ci = cs->GetInfo(); - if (ci == NULL) continue; + if (ci == nullptr) continue; uint lag = NetworkCalculateLag(cs); const char *status; @@ -2097,13 +2083,13 @@ uint NetworkServerKickOrBanIP(const char *ip, bool ban) /* Add address to ban-list */ if (ban) { bool contains = false; - for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) { - if (strcmp(*iter, ip) == 0) { + for (const auto &iter : _network_ban_list) { + if (iter == ip) { contains = true; break; } } - if (!contains) *_network_ban_list.Append() = stredup(ip); + if (!contains) _network_ban_list.emplace_back(ip); } uint n = 0; @@ -2112,7 +2098,7 @@ uint NetworkServerKickOrBanIP(const char *ip, bool ban) NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->client_id == CLIENT_ID_SERVER) continue; - if (cs->client_address.IsInNetmask(const_cast(ip))) { + if (cs->client_address.IsInNetmask(ip)) { NetworkServerKickClient(cs->client_id); n++; } @@ -2145,7 +2131,7 @@ void ServerNetworkGameSocketHandler::GetClientName(char *client_name, const char { const NetworkClientInfo *ci = this->GetInfo(); - if (ci == NULL || StrEmpty(ci->client_name)) { + if (ci == nullptr || StrEmpty(ci->client_name)) { seprintf(client_name, last, "Client #%4d", this->client_id); } else { strecpy(client_name, ci->client_name, last); @@ -2176,12 +2162,12 @@ void NetworkPrintClients() /** * Perform all the server specific administration of a new company. - * @param c The newly created company; can't be NULL. - * @param ci The client information of the client that made the company; can be NULL. + * @param c The newly created company; can't be nullptr. + * @param ci The client information of the client that made the company; can be nullptr. */ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci) { - assert(c != NULL); + assert(c != nullptr); if (!_network_server) return; @@ -2189,22 +2175,20 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci) _network_company_states[c->index].password[0] = '\0'; NetworkServerUpdateCompanyPassworded(c->index, false); - if (ci != NULL) { - /* ci is NULL when replaying, or for AIs. In neither case there is a client. */ + if (ci != nullptr) { + /* ci is nullptr when replaying, or for AIs. In neither case there is a client. */ ci->client_playas = c->index; NetworkUpdateClientInfo(ci->client_id); - NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index); + NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, nullptr, ci->client_name, c->index); } /* Announce new company on network. */ NetworkAdminCompanyInfo(c, true); - if (ci != NULL) { - /* ci is NULL when replaying, or for AIs. In neither case there is a client. + if (ci != nullptr) { + /* ci is nullptr when replaying, or for AIs. In neither case there is a client. We need to send Admin port update here so that they first know about the new company and then learn about a possibly joining client (see FS#6025) */ NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1); } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_server.h b/src/network/network_server.h index a52b2c9366..f13691fcd9 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -12,11 +12,8 @@ #ifndef NETWORK_SERVER_H #define NETWORK_SERVER_H -#ifdef ENABLE_NETWORK - #include "network_internal.h" #include "core/tcp_listen.h" -#include "../thread/thread.h" class ServerNetworkGameSocketHandler; /** Make the code look slightly nicer/simpler. */ @@ -28,22 +25,22 @@ extern NetworkClientSocketPool _networkclientsocket_pool; /** Class for handling the server side of the game connection. */ class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler { protected: - virtual NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_ACK(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_COMMAND(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_CHAT(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_QUIT(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_RCON(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p); - virtual NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p); + NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_ACK(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_COMMAND(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_CHAT(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_QUIT(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_RCON(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p) override; NetworkRecvStatus SendCompanyInfo(); NetworkRecvStatus SendNewGRFCheck(); @@ -81,8 +78,8 @@ public: ServerNetworkGameSocketHandler(SOCKET s); ~ServerNetworkGameSocketHandler(); - virtual Packet *ReceivePacket(); - NetworkRecvStatus CloseConnection(NetworkRecvStatus status); + virtual Packet *ReceivePacket() override; + NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; void GetClientName(char *client_name, const char *last) const; NetworkRecvStatus SendMap(); @@ -138,12 +135,4 @@ void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded) */ #define FOR_ALL_CLIENT_SOCKETS(var) FOR_ALL_CLIENT_SOCKETS_FROM(var, 0) -#else /* ENABLE_NETWORK */ -/* Network function stubs when networking is disabled */ - -static inline void NetworkServerMonthlyLoop() {} -static inline void NetworkServerYearlyLoop() {} - -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_SERVER_H */ diff --git a/src/network/network_type.h b/src/network/network_type.h index 3c390c29be..d511f5c0c8 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -14,8 +14,6 @@ #include "core/game.h" -#ifdef ENABLE_NETWORK - /** How many clients can we have */ static const uint MAX_CLIENTS = 255; @@ -40,7 +38,7 @@ enum NetworkVehicleType { }; /** 'Unique' identifier to be given to clients */ -enum ClientID { +enum ClientID : uint32 { INVALID_CLIENT_ID = 0, ///< Client is not part of anything CLIENT_ID_SERVER = 1, ///< Servers always have this ID CLIENT_ID_FIRST = 2, ///< The first client ID @@ -130,5 +128,4 @@ enum NetworkErrorCode { NETWORK_ERROR_END, }; -#endif /* ENABLE_NETWORK */ #endif /* NETWORK_TYPE_H */ diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 3fd0dd4853..d9f625719f 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -14,8 +14,6 @@ * communication before the game is being joined. */ -#ifdef ENABLE_NETWORK - #include "../stdafx.h" #include "../date_func.h" #include "../map_func.h" @@ -26,18 +24,19 @@ #include "network.h" #include "../core/endian_func.hpp" #include "../company_base.h" -#include "../thread/thread.h" +#include "../thread.h" #include "../rev.h" #include "../newgrf_text.h" #include "../strings_func.h" #include "table/strings.h" +#include #include "core/udp.h" #include "../safeguards.h" /** Mutex for all out threaded udp resolution and such. */ -static ThreadMutex *_network_udp_mutex = ThreadMutex::New(); +static std::mutex _network_udp_mutex; /** Session key to register ourselves to the master server */ static uint64 _session_key = 0; @@ -46,25 +45,9 @@ static const uint32 ADVERTISE_NORMAL_INTERVAL = 15 * 60 * 1000; ///< interval be static const uint32 ADVERTISE_RETRY_INTERVAL = 10 * 1000; ///< re-advertise when no response after this many ms (10 seconds) static const uint32 ADVERTISE_RETRY_TIMES = 3; ///< give up re-advertising after this much failed retries -NetworkUDPSocketHandler *_udp_client_socket = NULL; ///< udp client socket -NetworkUDPSocketHandler *_udp_server_socket = NULL; ///< udp server socket -NetworkUDPSocketHandler *_udp_master_socket = NULL; ///< udp master socket - -/** Simpler wrapper struct for NetworkUDPQueryServerThread */ -struct NetworkUDPQueryServerInfo : NetworkAddress { - bool manually; ///< Did we connect manually or not? - - /** - * Create the structure. - * @param address The address of the server to query. - * @param manually Whether the address was entered manually. - */ - NetworkUDPQueryServerInfo(const NetworkAddress &address, bool manually) : - NetworkAddress(address), - manually(manually) - { - } -}; +NetworkUDPSocketHandler *_udp_client_socket = nullptr; ///< udp client socket +NetworkUDPSocketHandler *_udp_server_socket = nullptr; ///< udp server socket +NetworkUDPSocketHandler *_udp_master_socket = nullptr; ///< udp master socket /** * Helper function doing the actual work for querying the server. @@ -72,33 +55,21 @@ struct NetworkUDPQueryServerInfo : NetworkAddress { * @param needs_mutex Whether we need to acquire locks when sending the packet or not. * @param manually Whether the address was entered manually. */ -static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, bool manually) +static void DoNetworkUDPQueryServer(NetworkAddress &address, bool needs_mutex, bool manually) { /* Clear item in gamelist */ NetworkGameList *item = CallocT(1); - address->GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); - strecpy(item->info.hostname, address->GetHostname(), lastof(item->info.hostname)); - item->address = *address; + address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); + strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname)); + item->address = address; item->manually = manually; NetworkGameListAddItemDelayed(item); - if (needs_mutex) _network_udp_mutex->BeginCritical(); + std::unique_lock lock(_network_udp_mutex, std::defer_lock); + if (needs_mutex) lock.lock(); /* Init the packet */ Packet p(PACKET_UDP_CLIENT_FIND_SERVER); - if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address); - if (needs_mutex) _network_udp_mutex->EndCritical(); -} - -/** - * Threaded part for resolving the IP of a server and querying it. - * @param pntr the NetworkUDPQueryServerInfo. - */ -static void NetworkUDPQueryServerThread(void *pntr) -{ - NetworkUDPQueryServerInfo *info = (NetworkUDPQueryServerInfo*)pntr; - NetworkUDPQueryServer(info, true, info->manually); - - delete info; + if (_udp_client_socket != nullptr) _udp_client_socket->SendPacket(&p, &address); } /** @@ -108,9 +79,8 @@ static void NetworkUDPQueryServerThread(void *pntr) */ void NetworkUDPQueryServer(NetworkAddress address, bool manually) { - NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually); - if (address.IsResolved() || !ThreadObject::New(NetworkUDPQueryServerThread, info, NULL, "ottd:udp-query")) { - NetworkUDPQueryServerThread(info); + if (address.IsResolved() || !StartNewThread(nullptr, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(address), true, std::move(manually))) { + DoNetworkUDPQueryServer(address, true, manually); } } @@ -119,8 +89,8 @@ void NetworkUDPQueryServer(NetworkAddress address, bool manually) /** Helper class for connecting to the master server. */ class MasterNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: - virtual void Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr); - virtual void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr); + void Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr) override; + void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr) override; public: /** * Create the socket. @@ -150,9 +120,9 @@ void MasterNetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, Networ /** Helper class for handling all server side communication. */ class ServerNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: - virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr); - virtual void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr); - virtual void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr); + void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) override; + void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) override; + void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) override; public: /** * Create the socket. @@ -291,7 +261,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ /* Find the matching GRF file */ f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); - if (f == NULL) continue; // The GRF is unknown to this server + if (f == nullptr) continue; // The GRF is unknown to this server /* If the reply might exceed the size of the packet, only reply * the current list and do not send the other data. @@ -326,10 +296,10 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ /** Helper class for handling all client side communication. */ class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: - virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr); - virtual void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr); - virtual void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr); - virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config); + void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override; + void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) override; + void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) override; + void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) override; public: virtual ~ClientNetworkUDPSocketHandler() {} }; @@ -362,7 +332,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd const GRFConfig *c; uint in_request_count = 0; - for (c = item->info.grfconfig; c != NULL; c = c->next) { + for (c = item->info.grfconfig; c != nullptr; c = c->next) { if (c->status == GCS_NOT_FOUND) item->info.compatible = false; if (c->status != GCS_NOT_FOUND || strcmp(c->GetName(), UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; in_request[in_request_count] = c; @@ -430,7 +400,7 @@ void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, Netw /* Somehow we reached the end of the packet */ if (this->HasClientQuit()) return; - NetworkUDPQueryServer(&addr, false, false); + DoNetworkUDPQueryServer(addr, false, false); } } } @@ -461,7 +431,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd * If it exists and not resolved yet, then name of the fake GRF is * overwritten with the name from the reply. */ GRFTextWrapper *unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); - if (unknown_name != NULL && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { + if (unknown_name != nullptr && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { AddGRFTextToList(&unknown_name->text, name); } } @@ -471,7 +441,7 @@ void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFCo { /* Find the matching GRF file */ const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum); - if (f == NULL) { + if (f == nullptr) { /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already */ @@ -497,12 +467,12 @@ void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFCo /** Broadcast to all ips */ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) { - for (NetworkAddress *addr = _broadcast_list.Begin(); addr != _broadcast_list.End(); addr++) { + for (NetworkAddress &addr : _broadcast_list) { Packet p(PACKET_UDP_CLIENT_FIND_SERVER); - DEBUG(net, 4, "[udp] broadcasting to %s", addr->GetHostname()); + DEBUG(net, 4, "[udp] broadcasting to %s", addr.GetHostname()); - socket->SendPacket(&p, addr, true, true); + socket->SendPacket(&p, &addr, true, true); } } @@ -536,9 +506,8 @@ void NetworkUDPSearchGame() /** * Thread entry point for de-advertising. - * @param pntr unused. */ -static void NetworkUDPRemoveAdvertiseThread(void *pntr) +static void NetworkUDPRemoveAdvertiseThread() { DEBUG(net, 1, "[udp] removing advertise from master server"); @@ -551,9 +520,8 @@ static void NetworkUDPRemoveAdvertiseThread(void *pntr) p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION); p.Send_uint16(_settings_client.network.server_port); - _network_udp_mutex->BeginCritical(); - if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true); - _network_udp_mutex->EndCritical(); + std::lock_guard lock(_network_udp_mutex); + if (_udp_master_socket != nullptr) _udp_master_socket->SendPacket(&p, &out_addr, true); } /** @@ -565,16 +533,15 @@ void NetworkUDPRemoveAdvertise(bool blocking) /* Check if we are advertising */ if (!_networking || !_network_server || !_network_udp_server) return; - if (blocking || !ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL, NULL, "ottd:udp-advert")) { - NetworkUDPRemoveAdvertiseThread(NULL); + if (blocking || !StartNewThread(nullptr, "ottd:udp-advert", &NetworkUDPRemoveAdvertiseThread)) { + NetworkUDPRemoveAdvertiseThread(); } } /** * Thread entry point for advertising. - * @param pntr unused. */ -static void NetworkUDPAdvertiseThread(void *pntr) +static void NetworkUDPAdvertiseThread() { /* Find somewhere to send */ NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT); @@ -605,9 +572,8 @@ static void NetworkUDPAdvertiseThread(void *pntr) p.Send_uint16(_settings_client.network.server_port); p.Send_uint64(_session_key); - _network_udp_mutex->BeginCritical(); - if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true); - _network_udp_mutex->EndCritical(); + std::lock_guard lock(_network_udp_mutex); + if (_udp_master_socket != nullptr) _udp_master_socket->SendPacket(&p, &out_addr, true); } /** @@ -648,8 +614,8 @@ void NetworkUDPAdvertise() if (_next_advertisement < _last_advertisement) _next_advertisement = UINT32_MAX; if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX; - if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL, NULL, "ottd:udp-advert")) { - NetworkUDPAdvertiseThread(NULL); + if (!StartNewThread(nullptr, "ottd:udp-advert", &NetworkUDPAdvertiseThread)) { + NetworkUDPAdvertiseThread(); } } @@ -657,12 +623,12 @@ void NetworkUDPAdvertise() void NetworkUDPInitialize() { /* If not closed, then do it. */ - if (_udp_server_socket != NULL) NetworkUDPClose(); + if (_udp_server_socket != nullptr) NetworkUDPClose(); DEBUG(net, 1, "[udp] initializing listeners"); - assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL); + assert(_udp_client_socket == nullptr && _udp_server_socket == nullptr && _udp_master_socket == nullptr); - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); _udp_client_socket = new ClientNetworkUDPSocketHandler(); @@ -670,29 +636,27 @@ void NetworkUDPInitialize() GetBindAddresses(&server, _settings_client.network.server_port); _udp_server_socket = new ServerNetworkUDPSocketHandler(&server); - server.Clear(); + server.clear(); GetBindAddresses(&server, 0); _udp_master_socket = new MasterNetworkUDPSocketHandler(&server); _network_udp_server = false; _network_udp_broadcast = 0; - _network_udp_mutex->EndCritical(); } /** Close all UDP related stuff. */ void NetworkUDPClose() { - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); _udp_server_socket->Close(); _udp_master_socket->Close(); _udp_client_socket->Close(); delete _udp_client_socket; delete _udp_server_socket; delete _udp_master_socket; - _udp_client_socket = NULL; - _udp_server_socket = NULL; - _udp_master_socket = NULL; - _network_udp_mutex->EndCritical(); + _udp_client_socket = nullptr; + _udp_server_socket = nullptr; + _udp_master_socket = nullptr; _network_udp_server = false; _network_udp_broadcast = 0; @@ -702,7 +666,7 @@ void NetworkUDPClose() /** Receive the UDP packets. */ void NetworkBackgroundUDPLoop() { - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); if (_network_udp_server) { _udp_server_socket->ReceivePackets(); @@ -711,8 +675,4 @@ void NetworkBackgroundUDPLoop() _udp_client_socket->ReceivePackets(); if (_network_udp_broadcast > 0) _network_udp_broadcast--; } - - _network_udp_mutex->EndCritical(); } - -#endif /* ENABLE_NETWORK */ diff --git a/src/network/network_udp.h b/src/network/network_udp.h index 3dfd076720..12de30bca3 100644 --- a/src/network/network_udp.h +++ b/src/network/network_udp.h @@ -12,8 +12,6 @@ #ifndef NETWORK_UDP_H #define NETWORK_UDP_H -#ifdef ENABLE_NETWORK - #include "core/address.h" void NetworkUDPInitialize(); @@ -25,6 +23,4 @@ void NetworkUDPRemoveAdvertise(bool blocking); void NetworkUDPClose(); void NetworkBackgroundUDPLoop(); -#endif /* ENABLE_NETWORK */ - #endif /* NETWORK_UDP_H */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 4c110c6b4f..7a67dea8bc 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -49,6 +49,7 @@ #include "vehicle_func.h" #include "language.h" #include "vehicle_base.h" +#include "road.h" #include "table/strings.h" #include "table/build_industry.h" @@ -65,7 +66,7 @@ * served as subject to the initial testing of this codec. */ /** List of all loaded GRF files */ -static SmallVector _grf_files; +static std::vector _grf_files; /** Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */ byte _misc_grf_features = 0; @@ -103,7 +104,7 @@ public: byte grf_container_ver; ///< Container format of the current GRF file. /* Kind of return values when processing certain actions */ - int skip_sprites; ///< Number of psuedo sprites to skip before processing the next one. (-1 to skip to end of file) + int skip_sprites; ///< Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file) /* Currently referenceable spritegroups */ SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1]; @@ -309,6 +310,7 @@ struct GRFTempEngineData { uint16 cargo_allowed; uint16 cargo_disallowed; RailTypeLabel railtypelabel; + uint8 roadtramtype; const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'. Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied. bool prop27_set; ///< Did the NewGRF set property 27 (misc flags)? @@ -391,11 +393,10 @@ void CDECL grfmsg(int severity, const char *str, ...) */ static GRFFile *GetFileByGRFID(uint32 grfid) { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile * const *file = _grf_files.Begin(); file != end; file++) { - if ((*file)->grfid == grfid) return *file; + for (GRFFile * const file : _grf_files) { + if (file->grfid == grfid) return file; } - return NULL; + return nullptr; } /** @@ -405,35 +406,34 @@ static GRFFile *GetFileByGRFID(uint32 grfid) */ static GRFFile *GetFileByFilename(const char *filename) { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile * const *file = _grf_files.Begin(); file != end; file++) { - if (strcmp((*file)->filename, filename) == 0) return *file; + for (GRFFile * const file : _grf_files) { + if (strcmp(file->filename, filename) == 0) return file; } - return NULL; + return nullptr; } /** Reset all NewGRFData that was used only while processing data */ static void ClearTemporaryNewGRFData(GRFFile *gf) { /* Clear the GOTO labels used for GRF processing */ - for (GRFLabel *l = gf->label; l != NULL;) { + for (GRFLabel *l = gf->label; l != nullptr;) { GRFLabel *l2 = l->next; free(l); l = l2; } - gf->label = NULL; + gf->label = nullptr; } /** * Disable a GRF * @param message Error message or STR_NULL. - * @param config GRFConfig to disable, NULL for current. + * @param config GRFConfig to disable, nullptr for current. * @return Error message of the GRF for further customisation. */ -static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = NULL) +static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = nullptr) { GRFFile *file; - if (config != NULL) { + if (config != nullptr) { file = GetFileByGRFID(config->ident.grfid); } else { config = _cur.grfconfig; @@ -441,7 +441,7 @@ static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = NUL } config->status = GCS_DISABLED; - if (file != NULL) ClearTemporaryNewGRFData(file); + if (file != nullptr) ClearTemporaryNewGRFData(file); if (config == _cur.grfconfig) _cur.skip_sprites = -1; if (message != STR_NULL) { @@ -461,7 +461,7 @@ struct StringIDMapping { StringID source; ///< Source StringID (GRF local). StringID *target; ///< Destination for mapping result. }; -typedef SmallVector StringIDMappingVector; +typedef std::vector StringIDMappingVector; static StringIDMappingVector _string_to_grf_mapping; /** @@ -472,10 +472,7 @@ static StringIDMappingVector _string_to_grf_mapping; static void AddStringForMapping(StringID source, StringID *target) { *target = STR_UNDEFINED; - StringIDMapping *item = _string_to_grf_mapping.Append(); - item->grfid = _cur.grffile->grfid; - item->source = source; - item->target = target; + _string_to_grf_mapping.push_back({_cur.grffile->grfid, source, target}); } /** @@ -553,7 +550,7 @@ StringID MapGRFStringID(uint32 grfid, StringID str) { if (IsInsideMM(str, 0xD800, 0xE000)) { /* General text provided by NewGRF. - * In the specs this is called the 0xDCxx range (misc presistent texts), + * In the specs this is called the 0xDCxx range (misc persistent texts), * but we meanwhile extended the range to 0xD800-0xDFFF. * Note: We are not involved in the "persistent" business, since we do not store * any NewGRF strings in savegames. */ @@ -594,7 +591,7 @@ static void SetNewGRFOverride(uint32 source_grfid, uint32 target_grfid) * @param file NewGRF that wants to change the engine. * @param type Vehicle type. * @param internal_id Engine ID inside the NewGRF. - * @param static_access If the engine is not present, return NULL instead of allocating a new engine. (Used for static Action 0x04). + * @param static_access If the engine is not present, return nullptr instead of allocating a new engine. (Used for static Action 0x04). * @return The requested engine. */ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 internal_id, bool static_access = false) @@ -609,7 +606,7 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 intern if (override != 0) { scope_grfid = override; const GRFFile *grf_match = GetFileByGRFID(override); - if (grf_match == NULL) { + if (grf_match == nullptr) { grfmsg(5, "Tried mapping from GRFID %x to %x but target is not loaded", BSWAP32(file->grfid), BSWAP32(override)); } else { grfmsg(5, "Mapping from GRFID %x to %x", BSWAP32(file->grfid), BSWAP32(override)); @@ -620,7 +617,7 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 intern EngineID engine = _engine_mngr.GetID(type, internal_id, scope_grfid); if (engine != INVALID_ENGINE) { Engine *e = Engine::Get(engine); - if (e->grf_prop.grffile == NULL) e->grf_prop.grffile = file; + if (e->grf_prop.grffile == nullptr) e->grf_prop.grffile = file; return e; } } @@ -630,25 +627,25 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 intern if (engine != INVALID_ENGINE) { Engine *e = Engine::Get(engine); - if (e->grf_prop.grffile == NULL) { + if (e->grf_prop.grffile == nullptr) { e->grf_prop.grffile = file; grfmsg(5, "Replaced engine at index %d for GRFID %x, type %d, index %d", e->index, BSWAP32(file->grfid), type, internal_id); } /* Reserve the engine slot */ if (!static_access) { - EngineIDMapping *eid = _engine_mngr.Get(engine); + EngineIDMapping *eid = _engine_mngr.data() + engine; eid->grfid = scope_grfid; // Note: this is INVALID_GRFID if dynamic_engines is disabled, so no reservation } return e; } - if (static_access) return NULL; + if (static_access) return nullptr; if (!Engine::CanAllocateItem()) { grfmsg(0, "Can't allocate any more engines"); - return NULL; + return nullptr; } size_t engine_pool_size = Engine::GetPoolSize(); @@ -658,12 +655,13 @@ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 intern e->grf_prop.grffile = file; /* Reserve the engine slot */ - assert(_engine_mngr.Length() == e->index); - EngineIDMapping *eid = _engine_mngr.Append(); - eid->type = type; - eid->grfid = scope_grfid; // Note: this is INVALID_GRFID if dynamic_engines is disabled, so no reservation - eid->internal_id = internal_id; - eid->substitute_id = min(internal_id, _engine_counts[type]); // substitute_id == _engine_counts[subtype] means "no substitute" + assert(_engine_mngr.size() == e->index); + _engine_mngr.push_back({ + scope_grfid, // Note: this is INVALID_GRFID if dynamic_engines is disabled, so no reservation + internal_id, + type, + static_cast(min(internal_id, _engine_counts[type])) // substitute_id == _engine_counts[subtype] means "no substitute" + }); if (engine_pool_size != Engine::GetPoolSize()) { /* Resize temporary engine data ... */ @@ -739,7 +737,7 @@ static void MapSpriteMappingRecolour(PalSpriteID *grf_sprite) * @param[out] max_palette_offset Optionally returns the number of sprites in the spriteset of the palette. (0 if no spritset) * @return Read TileLayoutFlags. */ -static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader *buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, int feature, PalSpriteID *grf_sprite, uint16 *max_sprite_offset = NULL, uint16 *max_palette_offset = NULL) +static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader *buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, int feature, PalSpriteID *grf_sprite, uint16 *max_sprite_offset = nullptr, uint16 *max_palette_offset = nullptr) { grf_sprite->sprite = buf->ReadWord(); grf_sprite->pal = buf->ReadWord(); @@ -758,7 +756,7 @@ static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader *buf, bool read_flags, grf_sprite->pal = PAL_NONE; } else { SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index; - if (max_sprite_offset != NULL) *max_sprite_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; + if (max_sprite_offset != nullptr) *max_sprite_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; SB(grf_sprite->sprite, 0, SPRITE_WIDTH, sprite); SetBit(grf_sprite->sprite, SPRITE_MODIFIER_CUSTOM_SPRITE); } @@ -776,7 +774,7 @@ static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader *buf, bool read_flags, grf_sprite->pal = PAL_NONE; } else { SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index; - if (max_palette_offset != NULL) *max_palette_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; + if (max_palette_offset != nullptr) *max_palette_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; SB(grf_sprite->pal, 0, SPRITE_WIDTH, sprite); SetBit(grf_sprite->pal, SPRITE_MODIFIER_CUSTOM_SPRITE); } @@ -801,7 +799,7 @@ static void ReadSpriteLayoutRegisters(ByteReader *buf, TileLayoutFlags flags, bo { if (!(flags & TLF_DRAWING_FLAGS)) return; - if (dts->registers == NULL) dts->AllocateRegisters(); + if (dts->registers == nullptr) dts->AllocateRegisters(); TileLayoutRegisters ®s = const_cast(dts->registers[index]); regs.flags = flags & TLF_DRAWING_FLAGS; @@ -845,7 +843,7 @@ static void ReadSpriteLayoutRegisters(ByteReader *buf, TileLayoutFlags flags, bo * @param num_building_sprites Number of building sprites to read * @param use_cur_spritesets Whether to use currently referenceable action 1 sets. * @param feature GrfSpecFeature to use spritesets from. - * @param allow_var10 Whether the spritelayout may specifiy var10 values for resolving multiple action-1-2-3 chains + * @param allow_var10 Whether the spritelayout may specify var10 values for resolving multiple action-1-2-3 chains * @param no_z_position Whether bounding boxes have no Z offset * @param dts Layout container to output into * @return True on error (GRF was disabled). @@ -928,9 +926,9 @@ static bool ReadSpriteLayout(ByteReader *buf, uint num_building_sprites, bool us /* When the Action1 sets are unknown, everything should be 0 (no spriteset usage) or UINT16_MAX (some spriteset usage) */ assert(use_cur_spritesets || (is_consistent && (dts->consistent_max_offset == 0 || dts->consistent_max_offset == UINT16_MAX))); - if (!is_consistent || dts->registers != NULL) { + if (!is_consistent || dts->registers != nullptr) { dts->consistent_max_offset = 0; - if (dts->registers == NULL) dts->AllocateRegisters(); + if (dts->registers == nullptr) dts->AllocateRegisters(); for (uint i = 0; i < num_building_sprites + 1; i++) { TileLayoutRegisters ®s = const_cast(dts->registers[i]); @@ -1049,7 +1047,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, engine + i); - if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles + if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; RailVehicleInfo *rvi = &e->u.rail; @@ -1058,7 +1056,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop case 0x05: { // Track type uint8 tracktype = buf->ReadByte(); - if (tracktype < _cur.grffile->railtype_list.Length()) { + if (tracktype < _cur.grffile->railtype_list.size()) { _gted[e->index].railtypelabel = _cur.grffile->railtype_list[tracktype]; break; } @@ -1200,7 +1198,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop break; } - if (_cur.grffile->railtype_list.Length() == 0) { + if (_cur.grffile->railtype_list.size() == 0) { /* Use traction type to select between normal and electrified * rail only when no translation list is in place. */ if (_gted[e->index].railtypelabel == RAILTYPE_RAIL_LABEL && engclass >= EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_ELECTRIC_LABEL; @@ -1343,12 +1341,18 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, engine + i); - if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles + if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; RoadVehicleInfo *rvi = &e->u.road; switch (prop) { + case 0x05: // Road/tram type + /* RoadTypeLabel is looked up later after the engine's road/tram + * flag is set, however 0 means the value has not been set. */ + _gted[e->index].roadtramtype = buf->ReadByte() + 1; + break; + case 0x08: // Speed (1 unit is 0.5 kmh) rvi->max_speed = buf->ReadByte(); break; @@ -1531,7 +1535,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, engine + i); - if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles + if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; ShipVehicleInfo *svi = &e->u.ship; @@ -1703,7 +1707,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, engine + i); - if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles + if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; AircraftVehicleInfo *avi = &e->u.air; @@ -1861,13 +1865,13 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte } /* Allocate station specs if necessary */ - if (_cur.grffile->stations == NULL) _cur.grffile->stations = CallocT(NUM_STATIONS_PER_GRF); + if (_cur.grffile->stations == nullptr) _cur.grffile->stations = CallocT(NUM_STATIONS_PER_GRF); for (int i = 0; i < numinfo; i++) { StationSpec *statspec = _cur.grffile->stations[stid + i]; /* Check that the station we are modifying is defined. */ - if (statspec == NULL && prop != 0x08) { + if (statspec == nullptr && prop != 0x08) { grfmsg(2, "StationChangeInfo: Attempt to modify undefined station %u, ignoring", stid + i); return CIR_INVALID_ID; } @@ -1877,7 +1881,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte StationSpec **spec = &_cur.grffile->stations[stid + i]; /* Property 0x08 is special; it is where the station is allocated */ - if (*spec == NULL) *spec = CallocT(1); + if (*spec == nullptr) *spec = CallocT(1); /* Swap classid because we read it in BE meaning WAYP or DFLT */ uint32 classid = buf->ReadDWord(); @@ -1905,26 +1909,27 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte /* On error, bail out immediately. Temporary GRF data was already freed */ if (_cur.skip_sprites < 0) return CIR_DISABLED; - static SmallVector tmp_layout; - tmp_layout.Clear(); + static std::vector tmp_layout; + tmp_layout.clear(); for (;;) { /* no relative bounding box support */ - DrawTileSeqStruct *dtss = tmp_layout.Append(); - MemSetT(dtss, 0); + /*C++17: DrawTileSeqStruct &dtss = */ tmp_layout.emplace_back(); + DrawTileSeqStruct &dtss = tmp_layout.back(); + MemSetT(&dtss, 0); - dtss->delta_x = buf->ReadByte(); - if (dtss->IsTerminator()) break; - dtss->delta_y = buf->ReadByte(); - dtss->delta_z = buf->ReadByte(); - dtss->size_x = buf->ReadByte(); - dtss->size_y = buf->ReadByte(); - dtss->size_z = buf->ReadByte(); + dtss.delta_x = buf->ReadByte(); + if (dtss.IsTerminator()) break; + dtss.delta_y = buf->ReadByte(); + dtss.delta_z = buf->ReadByte(); + dtss.size_x = buf->ReadByte(); + dtss.size_y = buf->ReadByte(); + dtss.size_z = buf->ReadByte(); - ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss->image); + ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss.image); /* On error, bail out immediately. Temporary GRF data was already freed */ if (_cur.skip_sprites < 0) return CIR_DISABLED; } - dts->Clone(tmp_layout.Begin()); + dts->Clone(tmp_layout.data()); } break; @@ -1932,7 +1937,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte byte srcid = buf->ReadByte(); const StationSpec *srcstatspec = _cur.grffile->stations[srcid]; - if (srcstatspec == NULL) { + if (srcstatspec == nullptr) { grfmsg(1, "StationChangeInfo: Station %u is not defined, cannot copy sprite layout to %u.", srcid, stid + i); continue; } @@ -1984,7 +1989,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte if (number > statspec->platforms[l]) { statspec->layouts[l] = ReallocT(statspec->layouts[l], number); - /* We expect NULL being 0 here, but C99 guarantees that. */ + /* We expect nullptr being 0 here, but C99 guarantees that. */ memset(statspec->layouts[l] + statspec->platforms[l], 0, (number - statspec->platforms[l]) * sizeof(**statspec->layouts)); @@ -2015,7 +2020,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte byte srcid = buf->ReadByte(); const StationSpec *srcstatspec = _cur.grffile->stations[srcid]; - if (srcstatspec == NULL) { + if (srcstatspec == nullptr) { grfmsg(1, "StationChangeInfo: Station %u is not defined, cannot copy tile layout to %u.", srcid, stid + i); continue; } @@ -2177,7 +2182,7 @@ static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteR byte tableid = buf->ReadByte(); byte numtables = buf->ReadByte(); - if (bridge->sprite_table == NULL) { + if (bridge->sprite_table == nullptr) { /* Allocate memory for sprite table pointers and zero out */ bridge->sprite_table = CallocT(7); } @@ -2189,7 +2194,7 @@ static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteR continue; } - if (bridge->sprite_table[tableid] == NULL) { + if (bridge->sprite_table[tableid] == nullptr) { bridge->sprite_table[tableid] = MallocT(32); } @@ -2323,14 +2328,14 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt } /* Allocate house specs if they haven't been allocated already. */ - if (_cur.grffile->housespec == NULL) { + if (_cur.grffile->housespec == nullptr) { _cur.grffile->housespec = CallocT(NUM_HOUSES_PER_GRF); } for (int i = 0; i < numinfo; i++) { HouseSpec *housespec = _cur.grffile->housespec[hid + i]; - if (prop != 0x08 && housespec == NULL) { + if (prop != 0x08 && housespec == nullptr) { /* If the house property 08 is not yet set, ignore this property */ ChangeInfoResult cir = IgnoreTownHouseProperty(prop, buf); if (cir > ret) ret = cir; @@ -2354,7 +2359,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt } /* Allocate space for this house. */ - if (*house == NULL) *house = CallocT(1); + if (*house == nullptr) *house = CallocT(1); housespec = *house; @@ -2565,13 +2570,13 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt * Get the language map associated with a given NewGRF and language. * @param grfid The NewGRF to get the map for. * @param language_id The (NewGRF) language ID to get the map for. - * @return The LanguageMap, or NULL if it couldn't be found. + * @return The LanguageMap, or nullptr if it couldn't be found. */ /* static */ const LanguageMap *LanguageMap::GetLanguageMap(uint32 grfid, uint8 language_id) { /* LanguageID "MAX_LANG", i.e. 7F is any. This language can't have a gender/case mapping, but has to be handled gracefully. */ const GRFFile *grffile = GetFileByGRFID(grfid); - return (grffile != NULL && grffile->language_map != NULL && language_id < MAX_LANG) ? &grffile->language_map[language_id] : NULL; + return (grffile != nullptr && grffile->language_map != nullptr && language_id < MAX_LANG) ? &grffile->language_map[language_id] : nullptr; } /** @@ -2591,10 +2596,10 @@ static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader return CIR_INVALID_ID; } - translation_table.Clear(); + translation_table.clear(); for (int i = 0; i < numinfo; i++) { uint32 item = buf->ReadDWord(); - *translation_table.Append() = BSWAP32(item); + translation_table.push_back(BSWAP32(item)); } return CIR_SUCCESS; @@ -2618,6 +2623,12 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); + case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type"); + + case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->tramtype_list, "Tram type"); + default: break; } @@ -2754,8 +2765,8 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By case 0x14: // Case translation table case 0x15: { // Plural form translation uint curidx = gvid + i; // The current index, i.e. language. - const LanguageMetadata *lang = curidx < MAX_LANG ? GetLanguage(curidx) : NULL; - if (lang == NULL) { + const LanguageMetadata *lang = curidx < MAX_LANG ? GetLanguage(curidx) : nullptr; + if (lang == nullptr) { grfmsg(1, "GlobalVarChangeInfo: Language %d is not known, ignoring", curidx); /* Skip over the data. */ if (prop == 0x15) { @@ -2768,7 +2779,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By break; } - if (_cur.grffile->language_map == NULL) _cur.grffile->language_map = new LanguageMap[MAX_LANG]; + if (_cur.grffile->language_map == nullptr) _cur.grffile->language_map = new LanguageMap[MAX_LANG]; if (prop == 0x15) { uint plural_form = buf->ReadByte(); @@ -2799,14 +2810,14 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By if (map.openttd_id >= MAX_NUM_GENDERS) { grfmsg(1, "GlobalVarChangeInfo: Gender name %s is not known, ignoring", name); } else { - *_cur.grffile->language_map[curidx].gender_map.Append() = map; + _cur.grffile->language_map[curidx].gender_map.push_back(map); } } else { map.openttd_id = lang->GetCaseIndex(name); if (map.openttd_id >= MAX_NUM_CASES) { grfmsg(1, "GlobalVarChangeInfo: Case name %s is not known, ignoring", name); } else { - *_cur.grffile->language_map[curidx].case_map.Append() = map; + _cur.grffile->language_map[curidx].case_map.push_back(map); } } newgrf_id = buf->ReadByte(); @@ -2833,6 +2844,12 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); + case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->roadtype_list, "Road type"); + + case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes) + return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->tramtype_list, "Tram type"); + default: break; } @@ -3138,14 +3155,14 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr } /* Allocate industry tile specs if they haven't been allocated already. */ - if (_cur.grffile->indtspec == NULL) { + if (_cur.grffile->indtspec == nullptr) { _cur.grffile->indtspec = CallocT(NUM_INDUSTRYTILES_PER_GRF); } for (int i = 0; i < numinfo; i++) { IndustryTileSpec *tsp = _cur.grffile->indtspec[indtid + i]; - if (prop != 0x08 && tsp == NULL) { + if (prop != 0x08 && tsp == nullptr) { ChangeInfoResult cir = IgnoreIndustryTileProperty(prop, buf); if (cir > ret) ret = cir; continue; @@ -3163,7 +3180,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr } /* Allocate space for this industry. */ - if (*tilespec == NULL) { + if (*tilespec == nullptr) { *tilespec = CallocT(1); tsp = *tilespec; @@ -3354,13 +3371,13 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader *buf) /** * Validate the industry layout; e.g. to prevent duplicate tiles. * @param layout The layout to check. - * @param size The size of the layout. * @return True if the layout is deemed valid. */ -static bool ValidateIndustryLayout(const IndustryTileTable *layout, int size) +static bool ValidateIndustryLayout(const IndustryTileLayout &layout) { - for (int i = 0; i < size - 1; i++) { - for (int j = i + 1; j < size; j++) { + const size_t size = layout.size(); + for (size_t i = 0; i < size - 1; i++) { + for (size_t j = i + 1; j < size; j++) { if (layout[i].ti.x == layout[j].ti.x && layout[i].ti.y == layout[j].ti.y) { return false; @@ -3370,20 +3387,6 @@ static bool ValidateIndustryLayout(const IndustryTileTable *layout, int size) return true; } -/** Clean the tile table of the IndustrySpec if it's needed. */ -static void CleanIndustryTileTable(IndustrySpec *ind) -{ - if (HasBit(ind->cleanup_flag, CLEAN_TILELAYOUT) && ind->table != NULL) { - for (int j = 0; j < ind->num_table; j++) { - /* remove the individual layouts */ - free(ind->table[j]); - } - /* remove the layouts pointers */ - free(ind->table); - ind->table = NULL; - } -} - /** * Define properties for industries * @param indid Local ID of the industry. @@ -3402,14 +3405,14 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } /* Allocate industry specs if they haven't been allocated already. */ - if (_cur.grffile->industryspec == NULL) { + if (_cur.grffile->industryspec == nullptr) { _cur.grffile->industryspec = CallocT(NUM_INDUSTRYTYPES_PER_GRF); } for (int i = 0; i < numinfo; i++) { IndustrySpec *indsp = _cur.grffile->industryspec[indid + i]; - if (prop != 0x08 && indsp == NULL) { + if (prop != 0x08 && indsp == nullptr) { ChangeInfoResult cir = IgnoreIndustryProperty(prop, buf); if (cir > ret) ret = cir; continue; @@ -3434,16 +3437,16 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, /* Allocate space for this industry. * Only need to do it once. If ever it is called again, it should not * do anything */ - if (*indspec == NULL) { - *indspec = CallocT(1); + if (*indspec == nullptr) { + *indspec = new IndustrySpec; indsp = *indspec; - memcpy(indsp, &_origin_industry_specs[subs_id], sizeof(_industry_specs[subs_id])); + *indsp = _origin_industry_specs[subs_id]; indsp->enabled = true; indsp->grf_prop.local_id = indid + i; indsp->grf_prop.subst_id = subs_id; indsp->grf_prop.grffile = _cur.grffile; - /* If the grf industry needs to check its surounding upon creation, it should + /* If the grf industry needs to check its surrounding upon creation, it should * rely on callbacks, not on the original placement functions */ indsp->check_proc = CHECK_NOTHING; } @@ -3464,112 +3467,101 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } case 0x0A: { // Set industry layout(s) - byte new_num_layouts = buf->ReadByte(); // Number of layaouts - /* We read the total size in bytes, but we can't rely on the - * newgrf to provide a sane value. First assume the value is - * sane but later on we make sure we enlarge the array if the - * newgrf contains more data. Each tile uses either 3 or 5 - * bytes, so to play it safe we assume 3. */ - uint32 def_num_tiles = buf->ReadDWord() / 3 + 1; - IndustryTileTable **tile_table = CallocT(new_num_layouts); // Table with tiles to compose an industry - IndustryTileTable *itt = CallocT(def_num_tiles); // Temporary array to read the tile layouts from the GRF - uint size; - const IndustryTileTable *copy_from; + byte new_num_layouts = buf->ReadByte(); + uint32 definition_size = buf->ReadDWord(); + uint32 bytes_read = 0; + std::vector new_layouts; + IndustryTileLayout layout; - try { - for (byte j = 0; j < new_num_layouts; j++) { - for (uint k = 0;; k++) { - if (k >= def_num_tiles) { - grfmsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry %u.", indid); - /* Size reported by newgrf was not big enough so enlarge the array. */ - def_num_tiles *= 2; - itt = ReallocT(itt, def_num_tiles); - } + for (byte j = 0; j < new_num_layouts; j++) { + layout.clear(); - itt[k].ti.x = buf->ReadByte(); // Offsets from northermost tile - - if (itt[k].ti.x == 0xFE && k == 0) { - /* This means we have to borrow the layout from an old industry */ - IndustryType type = buf->ReadByte(); // industry holding required layout - byte laynbr = buf->ReadByte(); // layout number to borrow - - copy_from = _origin_industry_specs[type].table[laynbr]; - for (size = 1;; size++) { - if (copy_from[size - 1].ti.x == -0x80 && copy_from[size - 1].ti.y == 0) break; - } - break; - } - - itt[k].ti.y = buf->ReadByte(); // Or table definition finalisation - - if (itt[k].ti.x == 0 && itt[k].ti.y == 0x80) { - /* Not the same terminator. The one we are using is rather - x = -80, y = x . So, adjust it. */ - itt[k].ti.x = -0x80; - itt[k].ti.y = 0; - itt[k].gfx = 0; - - size = k + 1; - copy_from = itt; - break; - } - - itt[k].gfx = buf->ReadByte(); - - if (itt[k].gfx == 0xFE) { - /* Use a new tile from this GRF */ - int local_tile_id = buf->ReadWord(); - - /* Read the ID from the _industile_mngr. */ - int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid); - - if (tempid == INVALID_INDUSTRYTILE) { - grfmsg(2, "IndustriesChangeInfo: Attempt to use industry tile %u with industry id %u, not yet defined. Ignoring.", local_tile_id, indid); - } else { - /* Declared as been valid, can be used */ - itt[k].gfx = tempid; - } - } else if (itt[k].gfx == 0xFF) { - itt[k].ti.x = (int8)GB(itt[k].ti.x, 0, 8); - itt[k].ti.y = (int8)GB(itt[k].ti.y, 0, 8); - - /* When there were only 256x256 maps, TileIndex was a uint16 and - * itt[k].ti was just a TileIndexDiff that was added to it. - * As such negative "x" values were shifted into the "y" position. - * x = -1, y = 1 -> x = 255, y = 0 - * Since GRF version 8 the position is interpreted as pair of independent int8. - * For GRF version < 8 we need to emulate the old shifting behaviour. - */ - if (_cur.grffile->grf_version < 8 && itt[k].ti.x < 0) itt[k].ti.y += 1; - } + for (uint k = 0;; k++) { + if (bytes_read >= definition_size) { + grfmsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry %u.", indid); + /* Avoid warning twice */ + definition_size = UINT32_MAX; } - if (!ValidateIndustryLayout(copy_from, size)) { - /* The industry layout was not valid, so skip this one. */ - grfmsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id %u. Ignoring", indid); - new_num_layouts--; - j--; - } else { - tile_table[j] = CallocT(size); - memcpy(tile_table[j], copy_from, sizeof(*copy_from) * size); + layout.push_back(IndustryTileLayoutTile{}); + IndustryTileLayoutTile &it = layout.back(); + + it.ti.x = buf->ReadByte(); // Offsets from northermost tile + ++bytes_read; + + if (it.ti.x == 0xFE && k == 0) { + /* This means we have to borrow the layout from an old industry */ + IndustryType type = buf->ReadByte(); + byte laynbr = buf->ReadByte(); + bytes_read += 2; + + if (type >= lengthof(_origin_industry_specs)) { + grfmsg(1, "IndustriesChangeInfo: Invalid original industry number for layout import, industry %u", indid); + DisableGrf(STR_NEWGRF_ERROR_INVALID_ID); + return CIR_DISABLED; + } + if (laynbr >= _origin_industry_specs[type].layouts.size()) { + grfmsg(1, "IndustriesChangeInfo: Invalid original industry layout index for layout import, industry %u", indid); + DisableGrf(STR_NEWGRF_ERROR_INVALID_ID); + return CIR_DISABLED; + } + layout = _origin_industry_specs[type].layouts[laynbr]; + break; + } + + it.ti.y = buf->ReadByte(); // Or table definition finalisation + ++bytes_read; + + if (it.ti.x == 0 && it.ti.y == 0x80) { + /* Terminator, remove and finish up */ + layout.pop_back(); + break; + } + + it.gfx = buf->ReadByte(); + ++bytes_read; + + if (it.gfx == 0xFE) { + /* Use a new tile from this GRF */ + int local_tile_id = buf->ReadWord(); + bytes_read += 2; + + /* Read the ID from the _industile_mngr. */ + int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid); + + if (tempid == INVALID_INDUSTRYTILE) { + grfmsg(2, "IndustriesChangeInfo: Attempt to use industry tile %u with industry id %u, not yet defined. Ignoring.", local_tile_id, indid); + } else { + /* Declared as been valid, can be used */ + it.gfx = tempid; + } + } else if (it.gfx == 0xFF) { + it.ti.x = (int8)GB(it.ti.x, 0, 8); + it.ti.y = (int8)GB(it.ti.y, 0, 8); + + /* When there were only 256x256 maps, TileIndex was a uint16 and + * it.ti was just a TileIndexDiff that was added to it. + * As such negative "x" values were shifted into the "y" position. + * x = -1, y = 1 -> x = 255, y = 0 + * Since GRF version 8 the position is interpreted as pair of independent int8. + * For GRF version < 8 we need to emulate the old shifting behaviour. + */ + if (_cur.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1; } } - } catch (...) { - for (int i = 0; i < new_num_layouts; i++) { - free(tile_table[i]); + + if (!ValidateIndustryLayout(layout)) { + /* The industry layout was not valid, so skip this one. */ + grfmsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id %u. Ignoring", indid); + new_num_layouts--; + j--; + } else { + new_layouts.push_back(layout); } - free(tile_table); - free(itt); - throw; } - /* Clean the tile table if it was already set by a previous prop A. */ - CleanIndustryTileTable(indsp); /* Install final layout construction in the industry spec */ - indsp->num_table = new_num_layouts; - indsp->table = tile_table; - SetBit(indsp->cleanup_flag, CLEAN_TILELAYOUT); - free(itt); + indsp->layouts = new_layouts; break; } @@ -3822,14 +3814,14 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B } /* Allocate industry specs if they haven't been allocated already. */ - if (_cur.grffile->airportspec == NULL) { + if (_cur.grffile->airportspec == nullptr) { _cur.grffile->airportspec = CallocT(NUM_AIRPORTS_PER_GRF); } for (int i = 0; i < numinfo; i++) { AirportSpec *as = _cur.grffile->airportspec[airport + i]; - if (as == NULL && prop != 0x08 && prop != 0x09) { + if (as == nullptr && prop != 0x08 && prop != 0x09) { grfmsg(2, "AirportChangeInfo: Attempt to modify undefined airport %u, ignoring", airport + i); return CIR_INVALID_ID; } @@ -3853,7 +3845,7 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B /* Allocate space for this airport. * Only need to do it once. If ever it is called again, it should not * do anything */ - if (*spec == NULL) { + if (*spec == nullptr) { *spec = MallocT(1); as = *spec; @@ -4040,14 +4032,14 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea } /* Allocate object specs if they haven't been allocated already. */ - if (_cur.grffile->objectspec == NULL) { + if (_cur.grffile->objectspec == nullptr) { _cur.grffile->objectspec = CallocT(NUM_OBJECTS_PER_GRF); } for (int i = 0; i < numinfo; i++) { ObjectSpec *spec = _cur.grffile->objectspec[id + i]; - if (prop != 0x08 && spec == NULL) { + if (prop != 0x08 && spec == nullptr) { /* If the object property 08 is not yet set, ignore this property */ ChangeInfoResult cir = IgnoreObjectProperty(prop, buf); if (cir > ret) ret = cir; @@ -4059,7 +4051,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea ObjectSpec **ospec = &_cur.grffile->objectspec[id + i]; /* Allocate space for this object. */ - if (*ospec == NULL) { + if (*ospec == nullptr) { *ospec = CallocT(1); (*ospec)->views = 1; // Default for NewGRFs that don't set it. } @@ -4335,7 +4327,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte if (_cur.grffile->railtype_map[id + i] != INVALID_RAILTYPE) { int n = buf->ReadByte(); for (int j = 0; j != n; j++) { - *_railtypes[_cur.grffile->railtype_map[id + i]].alternate_labels.Append() = BSWAP32(buf->ReadDWord()); + _railtypes[_cur.grffile->railtype_map[id + i]].alternate_labels.push_back(BSWAP32(buf->ReadDWord())); } break; } @@ -4371,6 +4363,228 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte return ret; } +/** + * Define properties for roadtypes + * @param id ID of the roadtype. + * @param numinfo Number of subsequent IDs to change the property for. + * @param prop The property to change. + * @param buf The property value. + * @return ChangeInfoResult. + */ +static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf, RoadTramType rtt) +{ + ChangeInfoResult ret = CIR_SUCCESS; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + if (id + numinfo > ROADTYPE_END) { + grfmsg(1, "RoadTypeChangeInfo: Road type %u is invalid, max %u, ignoring", id + numinfo, ROADTYPE_END); + return CIR_INVALID_ID; + } + + for (int i = 0; i < numinfo; i++) { + RoadType rt = type_map[id + i]; + if (rt == INVALID_ROADTYPE) return CIR_INVALID_ID; + + RoadTypeInfo *rti = &_roadtypes[rt]; + + switch (prop) { + case 0x08: // Label of road type + /* Skipped here as this is loaded during reservation stage. */ + buf->ReadDWord(); + break; + + case 0x09: { // Toolbar caption of roadtype (sets name as well for backwards compatibility for grf ver < 8) + uint16 str = buf->ReadWord(); + AddStringForMapping(str, &rti->strings.toolbar_caption); + break; + } + + case 0x0A: // Menu text of roadtype + AddStringForMapping(buf->ReadWord(), &rti->strings.menu_text); + break; + + case 0x0B: // Build window caption + AddStringForMapping(buf->ReadWord(), &rti->strings.build_caption); + break; + + case 0x0C: // Autoreplace text + AddStringForMapping(buf->ReadWord(), &rti->strings.replace_text); + break; + + case 0x0D: // New engine text + AddStringForMapping(buf->ReadWord(), &rti->strings.new_engine); + break; + + case 0x0F: // Powered roadtype list + case 0x18: // Roadtype list required for date introduction + case 0x19: { // Introduced roadtype list + /* Road type compatibility bits are added to the existing bits + * to allow multiple GRFs to modify compatibility with the + * default road types. */ + int n = buf->ReadByte(); + for (int j = 0; j != n; j++) { + RoadTypeLabel label = buf->ReadDWord(); + RoadType rt = GetRoadTypeByLabel(BSWAP32(label), false); + if (rt != INVALID_ROADTYPE) { + switch (prop) { + case 0x0F: SetBit(rti->powered_roadtypes, rt); break; + case 0x18: SetBit(rti->introduction_required_roadtypes, rt); break; + case 0x19: SetBit(rti->introduces_roadtypes, rt); break; + } + } + } + break; + } + + case 0x10: // Road Type flags + rti->flags = (RoadTypeFlags)buf->ReadByte(); + break; + + case 0x13: // Construction cost factor + rti->cost_multiplier = buf->ReadWord(); + break; + + case 0x14: // Speed limit + rti->max_speed = buf->ReadWord(); + break; + + case 0x16: // Map colour + rti->map_colour = buf->ReadByte(); + break; + + case 0x17: // Introduction date + rti->introduction_date = buf->ReadDWord(); + break; + + case 0x1A: // Sort order + rti->sorting_order = buf->ReadByte(); + break; + + case 0x1B: // Name of roadtype + AddStringForMapping(buf->ReadWord(), &rti->strings.name); + break; + + case 0x1C: // Maintenance cost factor + rti->maintenance_multiplier = buf->ReadWord(); + break; + + case 0x1D: // Alternate road type label list + /* Skipped here as this is loaded during reservation stage. */ + for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); + break; + + default: + ret = CIR_UNKNOWN; + break; + } + } + + return ret; +} + +static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_ROAD); +} + +static ChangeInfoResult TramTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_TRAM); +} + + +static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf, RoadTramType rtt) +{ + ChangeInfoResult ret = CIR_SUCCESS; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + if (id + numinfo > ROADTYPE_END) { + grfmsg(1, "RoadTypeReserveInfo: Road type %u is invalid, max %u, ignoring", id + numinfo, ROADTYPE_END); + return CIR_INVALID_ID; + } + + for (int i = 0; i < numinfo; i++) { + switch (prop) { + case 0x08: { // Label of road type + RoadTypeLabel rtl = buf->ReadDWord(); + rtl = BSWAP32(rtl); + + RoadType rt = GetRoadTypeByLabel(rtl, false); + if (rt == INVALID_ROADTYPE) { + /* Set up new road type */ + rt = AllocateRoadType(rtl, rtt); + } else if (GetRoadTramType(rt) != rtt) { + grfmsg(1, "RoadTypeReserveInfo: Road type %u is invalid type (road/tram), ignoring", id + numinfo); + return CIR_INVALID_ID; + } + + type_map[id + i] = rt; + break; + } + case 0x09: // Toolbar caption of roadtype + case 0x0A: // Menu text + case 0x0B: // Build window caption + case 0x0C: // Autoreplace text + case 0x0D: // New loco + case 0x13: // Construction cost + case 0x14: // Speed limit + case 0x1B: // Name of roadtype + case 0x1C: // Maintenance cost factor + buf->ReadWord(); + break; + + case 0x1D: // Alternate road type label list + if (type_map[id + i] != INVALID_ROADTYPE) { + int n = buf->ReadByte(); + for (int j = 0; j != n; j++) { + _roadtypes[type_map[id + i]].alternate_labels.push_back(BSWAP32(buf->ReadDWord())); + } + break; + } + grfmsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type %u because no label was set", id + i); + /* FALL THROUGH */ + + case 0x0F: // Powered roadtype list + case 0x18: // Roadtype list required for date introduction + case 0x19: // Introduced roadtype list + for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); + break; + + case 0x10: // Road Type flags + case 0x12: // Station graphic + case 0x15: // Acceleration model + case 0x16: // Map colour + case 0x1A: // Sort order + buf->ReadByte(); + break; + + case 0x17: // Introduction date + buf->ReadDWord(); + break; + + default: + ret = CIR_UNKNOWN; + break; + } + } + + return ret; +} + +static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_ROAD); +} + +static ChangeInfoResult TramTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf) +{ + return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_TRAM); +} + static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; @@ -4381,14 +4595,14 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro } /* Allocate airport tile specs if they haven't been allocated already. */ - if (_cur.grffile->airtspec == NULL) { + if (_cur.grffile->airtspec == nullptr) { _cur.grffile->airtspec = CallocT(NUM_AIRPORTTILES_PER_GRF); } for (int i = 0; i < numinfo; i++) { AirportTileSpec *tsp = _cur.grffile->airtspec[airtid + i]; - if (prop != 0x08 && tsp == NULL) { + if (prop != 0x08 && tsp == nullptr) { grfmsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile %u. Ignoring.", airtid + i); return CIR_INVALID_ID; } @@ -4405,7 +4619,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro } /* Allocate space for this airport tile. */ - if (*tilespec == NULL) { + if (*tilespec == nullptr) { *tilespec = CallocT(1); tsp = *tilespec; @@ -4516,13 +4730,15 @@ static void FeatureChangeInfo(ByteReader *buf) /* GSF_GLOBALVAR */ GlobalVarChangeInfo, /* GSF_INDUSTRYTILES */ IndustrytilesChangeInfo, /* GSF_INDUSTRIES */ IndustriesChangeInfo, - /* GSF_CARGOES */ NULL, // Cargo is handled during reservation + /* GSF_CARGOES */ nullptr, // Cargo is handled during reservation /* GSF_SOUNDFX */ SoundEffectChangeInfo, /* GSF_AIRPORTS */ AirportChangeInfo, - /* GSF_SIGNALS */ NULL, + /* GSF_SIGNALS */ nullptr, /* GSF_OBJECTS */ ObjectChangeInfo, /* GSF_RAILTYPES */ RailTypeChangeInfo, /* GSF_AIRPORTTILES */ AirportTilesChangeInfo, + /* GSF_ROADTYPES */ RoadTypeChangeInfo, + /* GSF_TRAMTYPES */ TramTypeChangeInfo, }; uint8 feature = buf->ReadByte(); @@ -4538,7 +4754,7 @@ static void FeatureChangeInfo(ByteReader *buf) grfmsg(6, "FeatureChangeInfo: Feature 0x%02X, %d properties, to apply to %d+%d", feature, numprops, engine, numinfo); - if (feature >= lengthof(handler) || handler[feature] == NULL) { + if (feature >= lengthof(handler) || handler[feature] == nullptr) { if (feature != GSF_CARGOES) grfmsg(1, "FeatureChangeInfo: Unsupported feature 0x%02X, skipping", feature); return; } @@ -4576,7 +4792,7 @@ static void SafeChangeInfo(ByteReader *buf) uint32 s = buf->ReadDWord(); buf->ReadDWord(); // dest const GRFConfig *grfconfig = GetGRFConfig(s); - if (grfconfig != NULL && !HasBit(grfconfig->flags, GCF_STATIC)) { + if (grfconfig != nullptr && !HasBit(grfconfig->flags, GCF_STATIC)) { is_safe = false; break; } @@ -4596,7 +4812,7 @@ static void ReserveChangeInfo(ByteReader *buf) { uint8 feature = buf->ReadByte(); - if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES) return; + if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES && feature != GSF_ROADTYPES && feature != GSF_TRAMTYPES) return; uint8 numprops = buf->ReadByte(); uint8 numinfo = buf->ReadByte(); @@ -4619,6 +4835,14 @@ static void ReserveChangeInfo(ByteReader *buf) case GSF_RAILTYPES: cir = RailTypeReserveInfo(index, numinfo, prop, buf); break; + + case GSF_ROADTYPES: + cir = RoadTypeReserveInfo(index, numinfo, prop, buf); + break; + + case GSF_TRAMTYPES: + cir = TramTypeReserveInfo(index, numinfo, prop, buf); + break; } if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return; @@ -4700,9 +4924,9 @@ static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 grou return new CallbackResultSpriteGroup(groupid, _cur.grffile->grf_version >= 8); } - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == NULL) { + if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { grfmsg(1, "GetGroupFromGroupID(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid); - return NULL; + return nullptr; } return _cur.spritegroups[groupid]; @@ -4725,7 +4949,7 @@ static const SpriteGroup *CreateGroupFromGroupID(byte feature, byte setid, byte if (!_cur.IsValidSpriteSet(feature, spriteid)) { grfmsg(1, "CreateGroupFromGroupID(0x%02X:0x%02X): Sprite set %u invalid", setid, type, spriteid); - return NULL; + return nullptr; } SpriteID spriteset_start = _cur.GetSprite(feature, spriteid); @@ -4751,7 +4975,7 @@ static void NewSpriteGroup(ByteReader *buf) * otherwise it specifies a number of entries, the exact * meaning depends on the feature * V feature-specific-data (huge mess, don't even look it up --pasky) */ - SpriteGroup *act_group = NULL; + SpriteGroup *act_group = nullptr; uint8 feature = buf->ReadByte(); if (feature >= GSF_END) { @@ -4790,43 +5014,44 @@ static void NewSpriteGroup(ByteReader *buf) case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break; } - static SmallVector adjusts; - adjusts.Clear(); + static std::vector adjusts; + adjusts.clear(); /* Loop through the var adjusts. Unfortunately we don't know how many we have * from the outset, so we shall have to keep reallocing. */ do { - DeterministicSpriteGroupAdjust *adjust = adjusts.Append(); + /*C++17: DeterministicSpriteGroupAdjust &adjust = */ adjusts.emplace_back(); + DeterministicSpriteGroupAdjust &adjust = adjusts.back(); /* The first var adjust doesn't have an operation specified, so we set it to add. */ - adjust->operation = adjusts.Length() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf->ReadByte(); - adjust->variable = buf->ReadByte(); - if (adjust->variable == 0x7E) { + adjust.operation = adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf->ReadByte(); + adjust.variable = buf->ReadByte(); + if (adjust.variable == 0x7E) { /* Link subroutine group */ - adjust->subroutine = GetGroupFromGroupID(setid, type, buf->ReadByte()); + adjust.subroutine = GetGroupFromGroupID(setid, type, buf->ReadByte()); } else { - adjust->parameter = IsInsideMM(adjust->variable, 0x60, 0x80) ? buf->ReadByte() : 0; + adjust.parameter = IsInsideMM(adjust.variable, 0x60, 0x80) ? buf->ReadByte() : 0; } varadjust = buf->ReadByte(); - adjust->shift_num = GB(varadjust, 0, 5); - adjust->type = (DeterministicSpriteGroupAdjustType)GB(varadjust, 6, 2); - adjust->and_mask = buf->ReadVarSize(varsize); + adjust.shift_num = GB(varadjust, 0, 5); + adjust.type = (DeterministicSpriteGroupAdjustType)GB(varadjust, 6, 2); + adjust.and_mask = buf->ReadVarSize(varsize); - if (adjust->type != DSGA_TYPE_NONE) { - adjust->add_val = buf->ReadVarSize(varsize); - adjust->divmod_val = buf->ReadVarSize(varsize); + if (adjust.type != DSGA_TYPE_NONE) { + adjust.add_val = buf->ReadVarSize(varsize); + adjust.divmod_val = buf->ReadVarSize(varsize); } else { - adjust->add_val = 0; - adjust->divmod_val = 0; + adjust.add_val = 0; + adjust.divmod_val = 0; } /* Continue reading var adjusts while bit 5 is set. */ } while (HasBit(varadjust, 5)); - group->num_adjusts = adjusts.Length(); + group->num_adjusts = (uint)adjusts.size(); group->adjusts = MallocT(group->num_adjusts); - MemCpyT(group->adjusts, adjusts.Begin(), group->num_adjusts); + MemCpyT(group->adjusts, adjusts.data(), group->num_adjusts); std::vector ranges; ranges.resize(buf->ReadByte()); @@ -4930,6 +5155,8 @@ static void NewSpriteGroup(ByteReader *buf) case GSF_CARGOES: case GSF_AIRPORTS: case GSF_RAILTYPES: + case GSF_ROADTYPES: + case GSF_TRAMTYPES: { byte num_loaded = type; byte num_loading = buf->ReadByte(); @@ -5085,7 +5312,7 @@ static CargoID TranslateCargo(uint8 feature, uint8 ctype) if (feature == GSF_STATIONS && ctype == 0xFE) return CT_DEFAULT_NA; if (ctype == 0xFF) return CT_PURCHASE; - if (_cur.grffile->cargo_list.Length() == 0) { + if (_cur.grffile->cargo_list.size() == 0) { /* No cargo table, so use bitnum values */ if (ctype >= 32) { grfmsg(1, "TranslateCargo: Cargo bitnum %d out of range (max 31), skipping.", ctype); @@ -5105,8 +5332,8 @@ static CargoID TranslateCargo(uint8 feature, uint8 ctype) } /* Check if the cargo type is out of bounds of the cargo translation table */ - if (ctype >= _cur.grffile->cargo_list.Length()) { - grfmsg(1, "TranslateCargo: Cargo type %d out of range (max %d), skipping.", ctype, _cur.grffile->cargo_list.Length() - 1); + if (ctype >= _cur.grffile->cargo_list.size()) { + grfmsg(1, "TranslateCargo: Cargo type %d out of range (max %d), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1); return CT_INVALID; } @@ -5130,7 +5357,7 @@ static CargoID TranslateCargo(uint8 feature, uint8 ctype) static bool IsValidGroupID(uint16 groupid, const char *function) { - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == NULL) { + if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { grfmsg(1, "%s: Spritegroup 0x%04X out of range or empty, skipping.", function, groupid); return false; } @@ -5167,7 +5394,7 @@ static void VehicleMapSpriteGroup(ByteReader *buf, byte feature, uint8 idcount) EngineID *engines = AllocaM(EngineID, idcount); for (uint i = 0; i < idcount; i++) { Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, buf->ReadExtendedByte()); - if (e == NULL) { + if (e == nullptr) { /* No engine could be allocated?!? Deal with it. Okay, * this might look bad. Also make sure this NewGRF * gets disabled, as a half loaded one is bad. */ @@ -5265,9 +5492,9 @@ static void StationMapSpriteGroup(ByteReader *buf, uint8 idcount) if (ctype == CT_INVALID) continue; for (uint i = 0; i < idcount; i++) { - StationSpec *statspec = _cur.grffile->stations == NULL ? NULL : _cur.grffile->stations[stations[i]]; + StationSpec *statspec = _cur.grffile->stations == nullptr ? nullptr : _cur.grffile->stations[stations[i]]; - if (statspec == NULL) { + if (statspec == nullptr) { grfmsg(1, "StationMapSpriteGroup: Station with ID 0x%02X does not exist, skipping", stations[i]); continue; } @@ -5280,14 +5507,14 @@ static void StationMapSpriteGroup(ByteReader *buf, uint8 idcount) if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) return; for (uint i = 0; i < idcount; i++) { - StationSpec *statspec = _cur.grffile->stations == NULL ? NULL : _cur.grffile->stations[stations[i]]; + StationSpec *statspec = _cur.grffile->stations == nullptr ? nullptr : _cur.grffile->stations[stations[i]]; - if (statspec == NULL) { + if (statspec == nullptr) { grfmsg(1, "StationMapSpriteGroup: Station with ID 0x%02X does not exist, skipping", stations[i]); continue; } - if (statspec->grf_prop.grffile != NULL) { + if (statspec->grf_prop.grffile != nullptr) { grfmsg(1, "StationMapSpriteGroup: Station with ID 0x%02X mapped multiple times, skipping", stations[i]); continue; } @@ -5314,7 +5541,7 @@ static void TownHouseMapSpriteGroup(ByteReader *buf, uint8 idcount) uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return; - if (_cur.grffile->housespec == NULL) { + if (_cur.grffile->housespec == nullptr) { grfmsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping"); return; } @@ -5322,7 +5549,7 @@ static void TownHouseMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { HouseSpec *hs = _cur.grffile->housespec[houses[i]]; - if (hs == NULL) { + if (hs == nullptr) { grfmsg(1, "TownHouseMapSpriteGroup: House %d undefined, skipping.", houses[i]); continue; } @@ -5345,7 +5572,7 @@ static void IndustryMapSpriteGroup(ByteReader *buf, uint8 idcount) uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return; - if (_cur.grffile->industryspec == NULL) { + if (_cur.grffile->industryspec == nullptr) { grfmsg(1, "IndustryMapSpriteGroup: No industries defined, skipping"); return; } @@ -5353,7 +5580,7 @@ static void IndustryMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { IndustrySpec *indsp = _cur.grffile->industryspec[industries[i]]; - if (indsp == NULL) { + if (indsp == nullptr) { grfmsg(1, "IndustryMapSpriteGroup: Industry %d undefined, skipping", industries[i]); continue; } @@ -5376,7 +5603,7 @@ static void IndustrytileMapSpriteGroup(ByteReader *buf, uint8 idcount) uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return; - if (_cur.grffile->indtspec == NULL) { + if (_cur.grffile->indtspec == nullptr) { grfmsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping"); return; } @@ -5384,7 +5611,7 @@ static void IndustrytileMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { IndustryTileSpec *indtsp = _cur.grffile->indtspec[indtiles[i]]; - if (indtsp == NULL) { + if (indtsp == nullptr) { grfmsg(1, "IndustrytileMapSpriteGroup: Industry tile %d undefined, skipping", indtiles[i]); continue; } @@ -5423,7 +5650,7 @@ static void CargoMapSpriteGroup(ByteReader *buf, uint8 idcount) static void ObjectMapSpriteGroup(ByteReader *buf, uint8 idcount) { - if (_cur.grffile->objectspec == NULL) { + if (_cur.grffile->objectspec == nullptr) { grfmsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping"); return; } @@ -5445,7 +5672,7 @@ static void ObjectMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { ObjectSpec *spec = _cur.grffile->objectspec[objects[i]]; - if (spec == NULL) { + if (spec == nullptr) { grfmsg(1, "ObjectMapSpriteGroup: Object with ID 0x%02X undefined, skipping", objects[i]); continue; } @@ -5460,12 +5687,12 @@ static void ObjectMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { ObjectSpec *spec = _cur.grffile->objectspec[objects[i]]; - if (spec == NULL) { + if (spec == nullptr) { grfmsg(1, "ObjectMapSpriteGroup: Object with ID 0x%02X undefined, skipping", objects[i]); continue; } - if (spec->grf_prop.grffile != NULL) { + if (spec->grf_prop.grffile != nullptr) { grfmsg(1, "ObjectMapSpriteGroup: Object with ID 0x%02X mapped multiple times, skipping", objects[i]); continue; } @@ -5507,6 +5734,39 @@ static void RailTypeMapSpriteGroup(ByteReader *buf, uint8 idcount) buf->ReadWord(); } +static void RoadTypeMapSpriteGroup(ByteReader *buf, uint8 idcount, RoadTramType rtt) +{ + RoadType *type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + + uint8 *roadtypes = AllocaM(uint8, idcount); + for (uint i = 0; i < idcount; i++) { + uint8 id = buf->ReadByte(); + roadtypes[i] = id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE; + } + + uint8 cidcount = buf->ReadByte(); + for (uint c = 0; c < cidcount; c++) { + uint8 ctype = buf->ReadByte(); + uint16 groupid = buf->ReadWord(); + if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue; + + if (ctype >= ROTSG_END) continue; + + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + for (uint i = 0; i < idcount; i++) { + if (roadtypes[i] != INVALID_ROADTYPE) { + RoadTypeInfo *rti = &_roadtypes[roadtypes[i]]; + + rti->grffile[ctype] = _cur.grffile; + rti->group[ctype] = _cur.spritegroups[groupid]; + } + } + } + + /* Roadtypes do not use the default group. */ + buf->ReadWord(); +} + static void AirportMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *airports = AllocaM(uint8, idcount); @@ -5521,7 +5781,7 @@ static void AirportMapSpriteGroup(ByteReader *buf, uint8 idcount) uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return; - if (_cur.grffile->airportspec == NULL) { + if (_cur.grffile->airportspec == nullptr) { grfmsg(1, "AirportMapSpriteGroup: No airports defined, skipping"); return; } @@ -5529,7 +5789,7 @@ static void AirportMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { AirportSpec *as = _cur.grffile->airportspec[airports[i]]; - if (as == NULL) { + if (as == nullptr) { grfmsg(1, "AirportMapSpriteGroup: Airport %d undefined, skipping", airports[i]); continue; } @@ -5552,7 +5812,7 @@ static void AirportTileMapSpriteGroup(ByteReader *buf, uint8 idcount) uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return; - if (_cur.grffile->airtspec == NULL) { + if (_cur.grffile->airtspec == nullptr) { grfmsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping"); return; } @@ -5560,7 +5820,7 @@ static void AirportTileMapSpriteGroup(ByteReader *buf, uint8 idcount) for (uint i = 0; i < idcount; i++) { AirportTileSpec *airtsp = _cur.grffile->airtspec[airptiles[i]]; - if (airtsp == NULL) { + if (airtsp == nullptr) { grfmsg(1, "AirportTileMapSpriteGroup: Airport tile %d undefined, skipping", airptiles[i]); continue; } @@ -5657,6 +5917,14 @@ static void FeatureMapSpriteGroup(ByteReader *buf) RailTypeMapSpriteGroup(buf, idcount); break; + case GSF_ROADTYPES: + RoadTypeMapSpriteGroup(buf, idcount, RTT_ROAD); + break; + + case GSF_TRAMTYPES: + RoadTypeMapSpriteGroup(buf, idcount, RTT_TRAM); + break; + case GSF_AIRPORTTILES: AirportTileMapSpriteGroup(buf, idcount); return; @@ -5724,7 +5992,7 @@ static void FeatureNewName(ByteReader *buf) case GSF_AIRCRAFT: if (!generic) { Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, id, HasBit(_cur.grfconfig->flags, GCF_STATIC)); - if (e == NULL) break; + if (e == nullptr) break; StringID string = AddGRFString(_cur.grffile->grfid, e->index, lang, new_scheme, false, name, e->info.string_id); e->info.string_id = string; } else { @@ -5740,7 +6008,7 @@ static void FeatureNewName(ByteReader *buf) switch (GB(id, 8, 8)) { case 0xC4: // Station class name - if (_cur.grffile->stations == NULL || _cur.grffile->stations[GB(id, 0, 8)] == NULL) { + if (_cur.grffile->stations == nullptr || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) { grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8)); } else { StationClassID cls_id = _cur.grffile->stations[GB(id, 0, 8)]->cls_id; @@ -5749,7 +6017,7 @@ static void FeatureNewName(ByteReader *buf) break; case 0xC5: // Station name - if (_cur.grffile->stations == NULL || _cur.grffile->stations[GB(id, 0, 8)] == NULL) { + if (_cur.grffile->stations == nullptr || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) { grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8)); } else { _cur.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); @@ -5757,7 +6025,7 @@ static void FeatureNewName(ByteReader *buf) break; case 0xC7: // Airporttile name - if (_cur.grffile->airtspec == NULL || _cur.grffile->airtspec[GB(id, 0, 8)] == NULL) { + if (_cur.grffile->airtspec == nullptr || _cur.grffile->airtspec[GB(id, 0, 8)] == nullptr) { grfmsg(1, "FeatureNewName: Attempt to name undefined airport tile 0x%X, ignoring", GB(id, 0, 8)); } else { _cur.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); @@ -5765,7 +6033,7 @@ static void FeatureNewName(ByteReader *buf) break; case 0xC9: // House name - if (_cur.grffile->housespec == NULL || _cur.grffile->housespec[GB(id, 0, 8)] == NULL) { + if (_cur.grffile->housespec == nullptr || _cur.grffile->housespec[GB(id, 0, 8)] == nullptr) { grfmsg(1, "FeatureNewName: Attempt to name undefined house 0x%X, ignoring.", GB(id, 0, 8)); } else { _cur.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); @@ -5912,20 +6180,27 @@ static void GraphicsNew(ByteReader *buf) return; } - /* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extentions) */ + /* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extensions) */ uint16 skip_num = SanitizeSpriteOffset(num, offset, action5_type->max_sprites, action5_type->name); SpriteID replace = action5_type->sprite_base + offset; /* Load sprites starting from , then skip sprites. */ grfmsg(2, "GraphicsNew: Replacing sprites %d to %d of %s (type 0x%02X) at SpriteID 0x%04X", offset, offset + num - 1, action5_type->name, type, replace); + if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; + + if (type == 0x0B) { + static const SpriteID depot_with_track_offset = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_TRAMWAY_BASE; + static const SpriteID depot_no_track_offset = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_TRAMWAY_BASE; + if (offset <= depot_with_track_offset && offset + num > depot_with_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_WITH_TRACK; + if (offset <= depot_no_track_offset && offset + num > depot_no_track_offset) _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NO_TRACK; + } + for (; num > 0; num--) { _cur.nfo_line++; LoadNextSprite(replace == 0 ? _cur.spriteid++ : replace++, _cur.file_index, _cur.nfo_line, _cur.grf_container_ver); } - if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; - _cur.skip_sprites = skip_num; } @@ -6102,7 +6377,7 @@ static uint32 GetParamVal(byte param, uint32 *cond_val) } case 0x85: // TTDPatch flags, only for bit tests - if (cond_val == NULL) { + if (cond_val == nullptr) { /* Supported in Action 0x07 and 0x09, not 0x0D */ return 0; } else { @@ -6145,7 +6420,7 @@ static void CfgApply(ByteReader *buf) size_t pos = FioGetPos(); uint32 num = _cur.grf_container_ver >= 2 ? FioReadDword() : FioReadWord(); uint8 type = FioReadByte(); - byte *preload_sprite = NULL; + byte *preload_sprite = nullptr; /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */ if (type == 0xFF) { @@ -6207,7 +6482,7 @@ static void CfgApply(ByteReader *buf) bool carry = false; for (i = 0; i < param_size && offset + i < num; i++) { - uint32 value = GetParamVal(param_num + i / 4, NULL); + uint32 value = GetParamVal(param_num + i / 4, nullptr); /* Reset carry flag for each iteration of the variable (only really * matters if param_size is greater than 4) */ if (i % 4 == 0) carry = false; @@ -6293,12 +6568,12 @@ static void SkipIf(ByteReader *buf) GRFConfig *c = GetGRFConfig(cond_val, mask); - if (c != NULL && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) { + if (c != nullptr && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) { DisableStaticNewGRFInfluencingNonStaticNewGRFs(c); - c = NULL; + c = nullptr; } - if (condtype != 10 && c == NULL) { + if (condtype != 10 && c == nullptr) { grfmsg(7, "SkipIf: GRFID 0x%08X unknown, skipping test", BSWAP32(cond_val)); return; } @@ -6323,7 +6598,7 @@ static void SkipIf(ByteReader *buf) case 0x0A: // GRFID is not nor will be active /* This is the only condtype that doesn't get ignored if the GRFID is not found */ - result = c == NULL || c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND; + result = c == nullptr || c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND; break; default: grfmsg(1, "SkipIf: Unsupported GRF condition type %02X. Ignoring", condtype); return; @@ -6351,6 +6626,14 @@ static void SkipIf(ByteReader *buf) break; case 0x0E: result = GetRailTypeByLabel(BSWAP32(cond_val)) != INVALID_RAILTYPE; break; + case 0x0F: result = GetRoadTypeByLabel(BSWAP32(cond_val)) == INVALID_ROADTYPE; + break; + case 0x10: result = GetRoadTypeByLabel(BSWAP32(cond_val)) != INVALID_ROADTYPE; + break; + case 0x11: result = GetRoadTypeByLabel(BSWAP32(cond_val)) == INVALID_ROADTYPE; + break; + case 0x12: result = GetRoadTypeByLabel(BSWAP32(cond_val)) != INVALID_ROADTYPE; + break; default: grfmsg(1, "SkipIf: Unsupported condition type %02X. Ignoring", condtype); return; } @@ -6367,12 +6650,12 @@ static void SkipIf(ByteReader *buf) * file. The jump will always be the first matching label that follows * the current nfo_line. If no matching label is found, the first matching * label in the file is used. */ - GRFLabel *choice = NULL; - for (GRFLabel *label = _cur.grffile->label; label != NULL; label = label->next) { + GRFLabel *choice = nullptr; + for (GRFLabel *label = _cur.grffile->label; label != nullptr; label = label->next) { if (label->label != numsprites) continue; /* Remember a goto before the current line */ - if (choice == NULL) choice = label; + if (choice == nullptr) choice = label; /* If we find a label here, this is definitely good */ if (label->nfo_line > _cur.nfo_line) { choice = label; @@ -6380,7 +6663,7 @@ static void SkipIf(ByteReader *buf) } } - if (choice != NULL) { + if (choice != nullptr) { grfmsg(2, "SkipIf: Jumping to label 0x%0X at line %d, test was true", choice->label, choice->nfo_line); FioSeekTo(choice->pos, SEEK_SET); _cur.nfo_line = choice->nfo_line; @@ -6517,7 +6800,7 @@ static void GRFLoadError(ByteReader *buf) { /* <0B> [ 00] [] 00 [] * - * B severity 00: notice, contine loading grf file + * B severity 00: notice, continue loading grf file * 01: warning, continue loading grf file * 02: error, but continue loading grf file, and attempt * loading grf again when loading or starting next game @@ -6572,7 +6855,7 @@ static void GRFLoadError(ByteReader *buf) /* Make sure we show fatal errors, instead of silly infos from before */ delete _cur.grfconfig->error; - _cur.grfconfig->error = NULL; + _cur.grfconfig->error = nullptr; } if (message_id >= lengthof(msgstr) && message_id != 0xFF) { @@ -6586,7 +6869,7 @@ static void GRFLoadError(ByteReader *buf) } /* For now we can only show one message per newgrf file. */ - if (_cur.grfconfig->error != NULL) return; + if (_cur.grfconfig->error != nullptr) return; GRFError *error = new GRFError(sevstr[severity]); @@ -6595,7 +6878,7 @@ static void GRFLoadError(ByteReader *buf) if (buf->HasData()) { const char *message = buf->ReadString(); - error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, NULL, SCC_RAW_STRING_POINTER); + error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, nullptr, SCC_RAW_STRING_POINTER); } else { grfmsg(7, "GRFLoadError: No custom message supplied."); error->custom_message = stredup(""); @@ -6696,7 +6979,7 @@ static uint32 GetPatchVariable(uint8 param) */ case 0x13: { byte map_bits = 0; - byte log_X = MapLogX() - 6; // substraction is required to make the minimal size (64) zero based + byte log_X = MapLogX() - 6; // subtraction is required to make the minimal size (64) zero based byte log_Y = MapLogY() - 6; byte max_edge = max(log_X, log_Y); @@ -6913,11 +7196,11 @@ static void ParamSet(ByteReader *buf) /* Read another GRF File's parameter */ const GRFFile *file = GetFileByGRFID(data); GRFConfig *c = GetGRFConfig(data); - if (c != NULL && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) { + if (c != nullptr && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) { /* Disable the read GRF if it is a static NewGRF. */ DisableStaticNewGRFInfluencingNonStaticNewGRFs(c); src1 = 0; - } else if (file == NULL || c == NULL || c->status == GCS_DISABLED) { + } else if (file == nullptr || c == nullptr || c->status == GCS_DISABLED) { src1 = 0; } else if (src1 == 0xFE) { src1 = c->version; @@ -6931,8 +7214,8 @@ static void ParamSet(ByteReader *buf) * variables available in action 7, or they can be FF to use the value * of . If referring to parameters that are undefined, a value * of 0 is used instead. */ - src1 = (src1 == 0xFF) ? data : GetParamVal(src1, NULL); - src2 = (src2 == 0xFF) ? data : GetParamVal(src2, NULL); + src1 = (src1 == 0xFF) ? data : GetParamVal(src1, nullptr); + src2 = (src2 == 0xFF) ? data : GetParamVal(src2, nullptr); } uint32 res; @@ -6989,7 +7272,7 @@ static void ParamSet(ByteReader *buf) } break; - case 0x0A: // Signed divison + case 0x0A: // Signed division if (src2 == 0) { res = src1; } else { @@ -7118,7 +7401,7 @@ static void GRFInhibit(ByteReader *buf) GRFConfig *file = GetGRFConfig(grfid); /* Unset activation flag */ - if (file != NULL && file != _cur.grfconfig) { + if (file != nullptr && file != _cur.grfconfig) { grfmsg(2, "GRFInhibit: Deactivating file '%s'", file->filename); GRFError *error = DisableGrf(STR_NEWGRF_ERROR_FORCEFULLY_DISABLED, file); error->data = stredup(_cur.grfconfig->GetName()); @@ -7224,15 +7507,15 @@ static void DefineGotoLabel(ByteReader *buf) label->label = nfo_label; label->nfo_line = _cur.nfo_line; label->pos = FioGetPos(); - label->next = NULL; + label->next = nullptr; /* Set up a linked list of goto targets which we will search in an Action 0x7/0x9 */ - if (_cur.grffile->label == NULL) { + if (_cur.grffile->label == nullptr) { _cur.grffile->label = label; } else { /* Attach the label to the end of the list */ GRFLabel *l; - for (l = _cur.grffile->label; l->next != NULL; l = l->next) {} + for (l = _cur.grffile->label; l->next != nullptr; l = l->next) {} l->next = label; } @@ -7250,7 +7533,7 @@ static void ImportGRFSound(SoundEntry *sound) SoundID sound_id = FioReadWord(); file = GetFileByGRFID(grfid); - if (file == NULL || file->sound_offset == 0) { + if (file == nullptr || file->sound_offset == 0) { grfmsg(1, "ImportGRFSound: Source file not available"); return; } @@ -7460,7 +7743,7 @@ static void TranslateGRFStrings(ByteReader *buf) uint32 grfid = buf->ReadDWord(); const GRFConfig *c = GetGRFConfig(grfid); - if (c == NULL || (c->status != GCS_INITIALISED && c->status != GCS_ACTIVATED)) { + if (c == nullptr || (c->status != GCS_INITIALISED && c->status != GCS_ACTIVATED)) { grfmsg(7, "TranslateGRFStrings: GRFID 0x%08x unknown, skipping action 13", BSWAP32(grfid)); return; } @@ -7811,7 +8094,7 @@ static bool ChangeGRFParamValueNames(ByteReader *buf) if (val_name != _cur_parameter->value_names.End()) { AddGRFTextToList(&val_name->second, langid, _cur.grfconfig->ident.grfid, false, name_string); } else { - GRFText *list = NULL; + GRFText *list = nullptr; AddGRFTextToList(&list, langid, _cur.grfconfig->ident.grfid, false, name_string); _cur_parameter->value_names.Insert(id, list); } @@ -7851,12 +8134,10 @@ static bool HandleParameterInfo(ByteReader *buf) continue; } - if (id >= _cur.grfconfig->param_info.Length()) { - uint num_to_add = id - _cur.grfconfig->param_info.Length() + 1; - GRFParameterInfo **newdata = _cur.grfconfig->param_info.Append(num_to_add); - MemSetT(newdata, 0, num_to_add); + if (id >= _cur.grfconfig->param_info.size()) { + _cur.grfconfig->param_info.resize(id + 1); } - if (_cur.grfconfig->param_info[id] == NULL) { + if (_cur.grfconfig->param_info[id] == nullptr) { _cur.grfconfig->param_info[id] = new GRFParameterInfo(id); } _cur_parameter = _cur.grfconfig->param_info[id]; @@ -8097,12 +8378,11 @@ static void InitializeGRFSpecial() /** Reset and clear all NewGRF stations */ static void ResetCustomStations() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - StationSpec **&stations = (*file)->stations; - if (stations == NULL) continue; + for (GRFFile * const file : _grf_files) { + StationSpec **&stations = file->stations; + if (stations == nullptr) continue; for (uint i = 0; i < NUM_STATIONS_PER_GRF; i++) { - if (stations[i] == NULL) continue; + if (stations[i] == nullptr) continue; StationSpec *statspec = stations[i]; delete[] statspec->renderdata; @@ -8125,37 +8405,35 @@ static void ResetCustomStations() /* Free and reset the station data */ free(stations); - stations = NULL; + stations = nullptr; } } /** Reset and clear all NewGRF houses */ static void ResetCustomHouses() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - HouseSpec **&housespec = (*file)->housespec; - if (housespec == NULL) continue; + for (GRFFile * const file : _grf_files) { + HouseSpec **&housespec = file->housespec; + if (housespec == nullptr) continue; for (uint i = 0; i < NUM_HOUSES_PER_GRF; i++) { free(housespec[i]); } free(housespec); - housespec = NULL; + housespec = nullptr; } } /** Reset and clear all NewGRF airports */ static void ResetCustomAirports() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - AirportSpec **aslist = (*file)->airportspec; - if (aslist != NULL) { + for (GRFFile * const file : _grf_files) { + AirportSpec **aslist = file->airportspec; + if (aslist != nullptr) { for (uint i = 0; i < NUM_AIRPORTS_PER_GRF; i++) { AirportSpec *as = aslist[i]; - if (as != NULL) { + if (as != nullptr) { /* We need to remove the tiles layouts */ for (int j = 0; j < as->num_table; j++) { /* remove the individual layouts */ @@ -8169,16 +8447,16 @@ static void ResetCustomAirports() } } free(aslist); - (*file)->airportspec = NULL; + file->airportspec = nullptr; } - AirportTileSpec **&airporttilespec = (*file)->airtspec; - if (airporttilespec != NULL) { + AirportTileSpec **&airporttilespec = file->airtspec; + if (airporttilespec != nullptr) { for (uint i = 0; i < NUM_AIRPORTTILES_PER_GRF; i++) { free(airporttilespec[i]); } free(airporttilespec); - airporttilespec = NULL; + airporttilespec = nullptr; } } } @@ -8186,78 +8464,65 @@ static void ResetCustomAirports() /** Reset and clear all NewGRF industries */ static void ResetCustomIndustries() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - IndustrySpec **&industryspec = (*file)->industryspec; - IndustryTileSpec **&indtspec = (*file)->indtspec; + for (GRFFile * const file : _grf_files) { + IndustrySpec **&industryspec = file->industryspec; + IndustryTileSpec **&indtspec = file->indtspec; /* We are verifiying both tiles and industries specs loaded from the grf file * First, let's deal with industryspec */ - if (industryspec != NULL) { + if (industryspec != nullptr) { for (uint i = 0; i < NUM_INDUSTRYTYPES_PER_GRF; i++) { IndustrySpec *ind = industryspec[i]; - if (ind == NULL) continue; - - /* We need to remove the sounds array */ - if (HasBit(ind->cleanup_flag, CLEAN_RANDOMSOUNDS)) { - free(ind->random_sounds); - } - - /* We need to remove the tiles layouts */ - CleanIndustryTileTable(ind); - - free(ind); + delete ind; } free(industryspec); - industryspec = NULL; + industryspec = nullptr; } - if (indtspec == NULL) continue; + if (indtspec == nullptr) continue; for (uint i = 0; i < NUM_INDUSTRYTILES_PER_GRF; i++) { free(indtspec[i]); } free(indtspec); - indtspec = NULL; + indtspec = nullptr; } } /** Reset and clear all NewObjects */ static void ResetCustomObjects() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - ObjectSpec **&objectspec = (*file)->objectspec; - if (objectspec == NULL) continue; + for (GRFFile * const file : _grf_files) { + ObjectSpec **&objectspec = file->objectspec; + if (objectspec == nullptr) continue; for (uint i = 0; i < NUM_OBJECTS_PER_GRF; i++) { free(objectspec[i]); } free(objectspec); - objectspec = NULL; + objectspec = nullptr; } } /** Reset and clear all NewGRFs */ static void ResetNewGRF() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - delete *file; + for (GRFFile * const file : _grf_files) { + delete file; } - _grf_files.Clear(); - _cur.grffile = NULL; + _grf_files.clear(); + _cur.grffile = nullptr; } /** Clear all NewGRF errors */ static void ResetNewGRFErrors() { - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { - if (!HasBit(c->flags, GCF_COPY) && c->error != NULL) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { + if (!HasBit(c->flags, GCF_COPY) && c->error != nullptr) { delete c->error; - c->error = NULL; + c->error = nullptr; } } } @@ -8279,6 +8544,9 @@ void ResetNewGRFData() /* Reset rail type information */ ResetRailTypes(); + /* Copy/reset original road type info data */ + ResetRoadTypes(); + /* Allocate temporary refit/cargo class data */ _gted = CallocT(Engine::GetPoolSize()); @@ -8347,6 +8615,7 @@ void ResetNewGRFData() _loaded_newgrf_features.has_newhouses = false; _loaded_newgrf_features.has_newindustries = false; _loaded_newgrf_features.shore = SHORE_REPLACE_NONE; + _loaded_newgrf_features.tram = TRAMWAY_REPLACE_DEPOT_NONE; /* Clear all GRF overrides */ _grf_id_overrides.clear(); @@ -8381,13 +8650,13 @@ static void BuildCargoTranslationMap() const CargoSpec *cs = CargoSpec::Get(c); if (!cs->IsValid()) continue; - if (_cur.grffile->cargo_list.Length() == 0) { + if (_cur.grffile->cargo_list.size() == 0) { /* Default translation table, so just a straight mapping to bitnum */ _cur.grffile->cargo_map[c] = cs->bitnum; } else { /* Check the translation table for this cargo's label */ - int index = _cur.grffile->cargo_list.FindIndex(cs->label); - if (index >= 0) _cur.grffile->cargo_map[c] = index; + int idx = find_index(_cur.grffile->cargo_list, {cs->label}); + if (idx >= 0) _cur.grffile->cargo_map[c] = idx; } } } @@ -8399,14 +8668,14 @@ static void BuildCargoTranslationMap() static void InitNewGRFFile(const GRFConfig *config) { GRFFile *newfile = GetFileByFilename(config->filename); - if (newfile != NULL) { + if (newfile != nullptr) { /* We already loaded it once. */ _cur.grffile = newfile; return; } newfile = new GRFFile(config); - *_grf_files.Append() = _cur.grffile = newfile; + _grf_files.push_back(_cur.grffile = newfile); } /** @@ -8434,6 +8703,14 @@ GRFFile::GRFFile(const GRFConfig *config) this->railtype_map[2] = RAILTYPE_MONO; this->railtype_map[3] = RAILTYPE_MAGLEV; + /* Initialise road type map with default road types */ + memset(this->roadtype_map, INVALID_ROADTYPE, sizeof(this->roadtype_map)); + this->roadtype_map[0] = ROADTYPE_ROAD; + + /* Initialise tram type map with default tram types */ + memset(this->tramtype_map, INVALID_ROADTYPE, sizeof(this->tramtype_map)); + this->tramtype_map[0] = ROADTYPE_TRAM; + /* Copy the initial parameter list * 'Uninitialised' parameters are zeroed as that is their default value when dynamically creating them. */ assert_compile(lengthof(this->param) == lengthof(config->param) && lengthof(this->param) == 0x80); @@ -8557,16 +8834,16 @@ static void CalculateRefitMasks() * cargo type. Finally disable the vehicle, if there is still no cargo. */ if (ei->cargo_type == CT_INVALID && ei->refit_mask != 0) { /* Figure out which CTT to use for the default cargo, if it is 'first refittable'. */ - const uint8 *cargo_map_for_first_refittable = NULL; + const uint8 *cargo_map_for_first_refittable = nullptr; { const GRFFile *file = _gted[engine].defaultcargo_grf; - if (file == NULL) file = e->GetGRF(); - if (file != NULL && file->grf_version >= 8 && file->cargo_list.Length() != 0) { + if (file == nullptr) file = e->GetGRF(); + if (file != nullptr && file->grf_version >= 8 && file->cargo_list.size() != 0) { cargo_map_for_first_refittable = file->cargo_map; } } - if (cargo_map_for_first_refittable != NULL) { + if (cargo_map_for_first_refittable != nullptr) { /* Use first refittable cargo from cargo translation table */ byte best_local_slot = 0xFF; CargoID cargo_type; @@ -8597,7 +8874,7 @@ static void CalculateRefitMasks() static void FinaliseCanals() { for (uint i = 0; i < CF_END; i++) { - if (_water_feature[i].grffile != NULL) { + if (_water_feature[i].grffile != nullptr) { _water_feature[i].callback_mask = _water_feature[i].grffile->canal_local_properties[i].callback_mask; _water_feature[i].flags = _water_feature[i].grffile->canal_local_properties[i].flags; } @@ -8610,7 +8887,7 @@ static void FinaliseEngineArray() Engine *e; FOR_ALL_ENGINES(e) { - if (e->GetGRF() == NULL) { + if (e->GetGRF() == nullptr) { const EngineIDMapping &eid = _engine_mngr[e->index]; if (eid.grfid != INVALID_GRFID || eid.internal_id != eid.substitute_id) { e->info.string_id = STR_NEWGRF_INVALID_ENGINE; @@ -8622,13 +8899,13 @@ static void FinaliseEngineArray() /* When the train does not set property 27 (misc flags), but it * is overridden by a NewGRF graphically we want to disable the * flipping possibility. */ - if (e->type == VEH_TRAIN && !_gted[e->index].prop27_set && e->GetGRF() != NULL && is_custom_sprite(e->u.rail.image_index)) { + if (e->type == VEH_TRAIN && !_gted[e->index].prop27_set && e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { ClrBit(e->info.misc_flags, EF_RAIL_FLIPS); } /* Skip wagons, there livery is defined via the engine */ if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { - LiveryScheme ls = GetEngineLiveryScheme(e->index, INVALID_ENGINE, NULL); + LiveryScheme ls = GetEngineLiveryScheme(e->index, INVALID_ENGINE, nullptr); SetBit(_loaded_newgrf_features.used_liveries, ls); /* Note: For ships and roadvehicles we assume that they cannot be refitted between passenger and freight */ @@ -8682,12 +8959,12 @@ static void FinaliseCargoArray() static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseSpec *next2, const HouseSpec *next3, const char *filename) { if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 && - (next1 == NULL || !next1->enabled || (next1->building_flags & BUILDING_HAS_1_TILE) != 0)) || + (next1 == nullptr || !next1->enabled || (next1->building_flags & BUILDING_HAS_1_TILE) != 0)) || ((hs->building_flags & BUILDING_HAS_4_TILES) != 0 && - (next2 == NULL || !next2->enabled || (next2->building_flags & BUILDING_HAS_1_TILE) != 0 || - next3 == NULL || !next3->enabled || (next3->building_flags & BUILDING_HAS_1_TILE) != 0))) { + (next2 == nullptr || !next2->enabled || (next2->building_flags & BUILDING_HAS_1_TILE) != 0 || + next3 == nullptr || !next3->enabled || (next3->building_flags & BUILDING_HAS_1_TILE) != 0))) { hs->enabled = false; - if (filename != NULL) DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d as multitile, but no suitable tiles follow. Disabling house.", filename, hs->grf_prop.local_id); + if (filename != nullptr) DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d as multitile, but no suitable tiles follow. Disabling house.", filename, hs->grf_prop.local_id); return false; } @@ -8697,13 +8974,13 @@ static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseS if (((hs->building_flags & BUILDING_HAS_2_TILES) != 0 && next1->population != 0) || ((hs->building_flags & BUILDING_HAS_4_TILES) != 0 && (next2->population != 0 || next3->population != 0))) { hs->enabled = false; - if (filename != NULL) DEBUG(grf, 1, "FinaliseHouseArray: %s defines multitile house %d with non-zero population on additional tiles. Disabling house.", filename, hs->grf_prop.local_id); + if (filename != nullptr) DEBUG(grf, 1, "FinaliseHouseArray: %s defines multitile house %d with non-zero population on additional tiles. Disabling house.", filename, hs->grf_prop.local_id); return false; } /* Substitute type is also used for override, and having an override with a different size causes crashes. * This check should only be done for NewGRF houses because grf_prop.subst_id is not set for original houses.*/ - if (filename != NULL && (hs->building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs->grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) { + if (filename != nullptr && (hs->building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs->grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) { hs->enabled = false; DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d with different house size then it's substitute type. Disabling house.", filename, hs->grf_prop.local_id); return false; @@ -8712,7 +8989,7 @@ static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseS /* Make sure that additional parts of multitile houses are not available. */ if ((hs->building_flags & BUILDING_HAS_1_TILE) == 0 && (hs->building_availability & HZ_ZONALL) != 0 && (hs->building_availability & HZ_CLIMALL) != 0) { hs->enabled = false; - if (filename != NULL) DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d without a size but marked it as available. Disabling house.", filename, hs->grf_prop.local_id); + if (filename != nullptr) DEBUG(grf, 1, "FinaliseHouseArray: %s defines house %d without a size but marked it as available. Disabling house.", filename, hs->grf_prop.local_id); return false; } @@ -8731,7 +9008,7 @@ static void EnsureEarlyHouse(HouseZones bitmask) for (int i = 0; i < NUM_HOUSES; i++) { HouseSpec *hs = HouseSpec::Get(i); - if (hs == NULL || !hs->enabled) continue; + if (hs == nullptr || !hs->enabled) continue; if ((hs->building_availability & bitmask) != bitmask) continue; if (hs->min_year < min_year) min_year = hs->min_year; } @@ -8740,7 +9017,7 @@ static void EnsureEarlyHouse(HouseZones bitmask) for (int i = 0; i < NUM_HOUSES; i++) { HouseSpec *hs = HouseSpec::Get(i); - if (hs == NULL || !hs->enabled) continue; + if (hs == nullptr || !hs->enabled) continue; if ((hs->building_availability & bitmask) != bitmask) continue; if (hs->min_year == min_year) hs->min_year = 0; } @@ -8763,21 +9040,20 @@ static void FinaliseHouseArray() * On the other hand, why 1930? Just 'fix' the houses with the lowest * minimum introduction date to 0. */ - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - HouseSpec **&housespec = (*file)->housespec; - if (housespec == NULL) continue; + for (GRFFile * const file : _grf_files) { + HouseSpec **&housespec = file->housespec; + if (housespec == nullptr) continue; for (int i = 0; i < NUM_HOUSES_PER_GRF; i++) { HouseSpec *hs = housespec[i]; - if (hs == NULL) continue; + if (hs == nullptr) continue; - const HouseSpec *next1 = (i + 1 < NUM_HOUSES_PER_GRF ? housespec[i + 1] : NULL); - const HouseSpec *next2 = (i + 2 < NUM_HOUSES_PER_GRF ? housespec[i + 2] : NULL); - const HouseSpec *next3 = (i + 3 < NUM_HOUSES_PER_GRF ? housespec[i + 3] : NULL); + const HouseSpec *next1 = (i + 1 < NUM_HOUSES_PER_GRF ? housespec[i + 1] : nullptr); + const HouseSpec *next2 = (i + 2 < NUM_HOUSES_PER_GRF ? housespec[i + 2] : nullptr); + const HouseSpec *next3 = (i + 3 < NUM_HOUSES_PER_GRF ? housespec[i + 3] : nullptr); - if (!IsHouseSpecValid(hs, next1, next2, next3, (*file)->filename)) continue; + if (!IsHouseSpecValid(hs, next1, next2, next3, file->filename)) continue; _house_mngr.SetEntitySpec(hs); } @@ -8785,13 +9061,13 @@ static void FinaliseHouseArray() for (int i = 0; i < NUM_HOUSES; i++) { HouseSpec *hs = HouseSpec::Get(i); - const HouseSpec *next1 = (i + 1 < NUM_HOUSES ? HouseSpec::Get(i + 1) : NULL); - const HouseSpec *next2 = (i + 2 < NUM_HOUSES ? HouseSpec::Get(i + 2) : NULL); - const HouseSpec *next3 = (i + 3 < NUM_HOUSES ? HouseSpec::Get(i + 3) : NULL); + const HouseSpec *next1 = (i + 1 < NUM_HOUSES ? HouseSpec::Get(i + 1) : nullptr); + const HouseSpec *next2 = (i + 2 < NUM_HOUSES ? HouseSpec::Get(i + 2) : nullptr); + const HouseSpec *next3 = (i + 3 < NUM_HOUSES ? HouseSpec::Get(i + 3) : nullptr); /* We need to check all houses again to we are sure that multitile houses * did get consecutive IDs and none of the parts are missing. */ - if (!IsHouseSpecValid(hs, next1, next2, next3, NULL)) { + if (!IsHouseSpecValid(hs, next1, next2, next3, nullptr)) { /* GetHouseNorthPart checks 3 houses that are directly before * it in the house pool. If any of those houses have multi-tile * flags set it assumes it's part of a multitile house. Since @@ -8826,15 +9102,14 @@ static void FinaliseHouseArray() */ static void FinaliseIndustriesArray() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - IndustrySpec **&industryspec = (*file)->industryspec; - IndustryTileSpec **&indtspec = (*file)->indtspec; - if (industryspec != NULL) { + for (GRFFile * const file : _grf_files) { + IndustrySpec **&industryspec = file->industryspec; + IndustryTileSpec **&indtspec = file->indtspec; + if (industryspec != nullptr) { for (int i = 0; i < NUM_INDUSTRYTYPES_PER_GRF; i++) { IndustrySpec *indsp = industryspec[i]; - if (indsp != NULL && indsp->enabled) { + if (indsp != nullptr && indsp->enabled) { StringID strid; /* process the conversion of text at the end, so to be sure everything will be fine * and available. Check if it does not return undefind marker, which is a very good sign of a @@ -8867,10 +9142,10 @@ static void FinaliseIndustriesArray() } } - if (indtspec != NULL) { + if (indtspec != nullptr) { for (int i = 0; i < NUM_INDUSTRYTILES_PER_GRF; i++) { IndustryTileSpec *indtsp = indtspec[i]; - if (indtsp != NULL) { + if (indtsp != nullptr) { _industile_mngr.SetEntitySpec(indtsp); } } @@ -8879,7 +9154,7 @@ static void FinaliseIndustriesArray() for (uint j = 0; j < NUM_INDUSTRYTYPES; j++) { IndustrySpec *indsp = &_industry_specs[j]; - if (indsp->enabled && indsp->grf_prop.grffile != NULL) { + if (indsp->enabled && indsp->grf_prop.grffile != nullptr) { for (uint i = 0; i < 3; i++) { indsp->conflicting[i] = MapNewGRFIndustryType(indsp->conflicting[i], indsp->grf_prop.grffile->grfid); } @@ -8897,12 +9172,11 @@ static void FinaliseIndustriesArray() */ static void FinaliseObjectsArray() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - ObjectSpec **&objectspec = (*file)->objectspec; - if (objectspec != NULL) { + for (GRFFile * const file : _grf_files) { + ObjectSpec **&objectspec = file->objectspec; + if (objectspec != nullptr) { for (int i = 0; i < NUM_OBJECTS_PER_GRF; i++) { - if (objectspec[i] != NULL && objectspec[i]->grf_prop.grffile != NULL && objectspec[i]->enabled) { + if (objectspec[i] != nullptr && objectspec[i]->grf_prop.grffile != nullptr && objectspec[i]->enabled) { _object_mngr.SetEntitySpec(objectspec[i]); } } @@ -8917,21 +9191,20 @@ static void FinaliseObjectsArray() */ static void FinaliseAirportsArray() { - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - AirportSpec **&airportspec = (*file)->airportspec; - if (airportspec != NULL) { + for (GRFFile * const file : _grf_files) { + AirportSpec **&airportspec = file->airportspec; + if (airportspec != nullptr) { for (int i = 0; i < NUM_AIRPORTS_PER_GRF; i++) { - if (airportspec[i] != NULL && airportspec[i]->enabled) { + if (airportspec[i] != nullptr && airportspec[i]->enabled) { _airport_mngr.SetEntitySpec(airportspec[i]); } } } - AirportTileSpec **&airporttilespec = (*file)->airtspec; - if (airporttilespec != NULL) { + AirportTileSpec **&airporttilespec = file->airtspec; + if (airporttilespec != nullptr) { for (uint i = 0; i < NUM_AIRPORTTILES_PER_GRF; i++) { - if (airporttilespec[i] != NULL && airporttilespec[i]->enabled) { + if (airporttilespec[i] != nullptr && airporttilespec[i]->enabled) { _airporttile_mngr.SetEntitySpec(airporttilespec[i]); } } @@ -8960,27 +9233,27 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage) * is not in memory and scanning the file every time would be too expensive. * In other stages we skip action 0x10 since it's already dealt with. */ static const SpecialSpriteHandler handlers[][GLS_END] = { - /* 0x00 */ { NULL, SafeChangeInfo, NULL, NULL, ReserveChangeInfo, FeatureChangeInfo, }, - /* 0x01 */ { SkipAct1, SkipAct1, SkipAct1, SkipAct1, SkipAct1, NewSpriteSet, }, - /* 0x02 */ { NULL, NULL, NULL, NULL, NULL, NewSpriteGroup, }, - /* 0x03 */ { NULL, GRFUnsafe, NULL, NULL, NULL, FeatureMapSpriteGroup, }, - /* 0x04 */ { NULL, NULL, NULL, NULL, NULL, FeatureNewName, }, - /* 0x05 */ { SkipAct5, SkipAct5, SkipAct5, SkipAct5, SkipAct5, GraphicsNew, }, - /* 0x06 */ { NULL, NULL, NULL, CfgApply, CfgApply, CfgApply, }, - /* 0x07 */ { NULL, NULL, NULL, NULL, SkipIf, SkipIf, }, - /* 0x08 */ { ScanInfo, NULL, NULL, GRFInfo, GRFInfo, GRFInfo, }, - /* 0x09 */ { NULL, NULL, NULL, SkipIf, SkipIf, SkipIf, }, - /* 0x0A */ { SkipActA, SkipActA, SkipActA, SkipActA, SkipActA, SpriteReplace, }, - /* 0x0B */ { NULL, NULL, NULL, GRFLoadError, GRFLoadError, GRFLoadError, }, - /* 0x0C */ { NULL, NULL, NULL, GRFComment, NULL, GRFComment, }, - /* 0x0D */ { NULL, SafeParamSet, NULL, ParamSet, ParamSet, ParamSet, }, - /* 0x0E */ { NULL, SafeGRFInhibit, NULL, GRFInhibit, GRFInhibit, GRFInhibit, }, - /* 0x0F */ { NULL, GRFUnsafe, NULL, FeatureTownName, NULL, NULL, }, - /* 0x10 */ { NULL, NULL, DefineGotoLabel, NULL, NULL, NULL, }, - /* 0x11 */ { SkipAct11,GRFUnsafe, SkipAct11, GRFSound, SkipAct11, GRFSound, }, - /* 0x12 */ { SkipAct12, SkipAct12, SkipAct12, SkipAct12, SkipAct12, LoadFontGlyph, }, - /* 0x13 */ { NULL, NULL, NULL, NULL, NULL, TranslateGRFStrings, }, - /* 0x14 */ { StaticGRFInfo, NULL, NULL, NULL, NULL, NULL, }, + /* 0x00 */ { nullptr, SafeChangeInfo, nullptr, nullptr, ReserveChangeInfo, FeatureChangeInfo, }, + /* 0x01 */ { SkipAct1, SkipAct1, SkipAct1, SkipAct1, SkipAct1, NewSpriteSet, }, + /* 0x02 */ { nullptr, nullptr, nullptr, nullptr, nullptr, NewSpriteGroup, }, + /* 0x03 */ { nullptr, GRFUnsafe, nullptr, nullptr, nullptr, FeatureMapSpriteGroup, }, + /* 0x04 */ { nullptr, nullptr, nullptr, nullptr, nullptr, FeatureNewName, }, + /* 0x05 */ { SkipAct5, SkipAct5, SkipAct5, SkipAct5, SkipAct5, GraphicsNew, }, + /* 0x06 */ { nullptr, nullptr, nullptr, CfgApply, CfgApply, CfgApply, }, + /* 0x07 */ { nullptr, nullptr, nullptr, nullptr, SkipIf, SkipIf, }, + /* 0x08 */ { ScanInfo, nullptr, nullptr, GRFInfo, GRFInfo, GRFInfo, }, + /* 0x09 */ { nullptr, nullptr, nullptr, SkipIf, SkipIf, SkipIf, }, + /* 0x0A */ { SkipActA, SkipActA, SkipActA, SkipActA, SkipActA, SpriteReplace, }, + /* 0x0B */ { nullptr, nullptr, nullptr, GRFLoadError, GRFLoadError, GRFLoadError, }, + /* 0x0C */ { nullptr, nullptr, nullptr, GRFComment, nullptr, GRFComment, }, + /* 0x0D */ { nullptr, SafeParamSet, nullptr, ParamSet, ParamSet, ParamSet, }, + /* 0x0E */ { nullptr, SafeGRFInhibit, nullptr, GRFInhibit, GRFInhibit, GRFInhibit, }, + /* 0x0F */ { nullptr, GRFUnsafe, nullptr, FeatureTownName, nullptr, nullptr, }, + /* 0x10 */ { nullptr, nullptr, DefineGotoLabel, nullptr, nullptr, nullptr, }, + /* 0x11 */ { SkipAct11, GRFUnsafe, SkipAct11, GRFSound, SkipAct11, GRFSound, }, + /* 0x12 */ { SkipAct12, SkipAct12, SkipAct12, SkipAct12, SkipAct12, LoadFontGlyph, }, + /* 0x13 */ { nullptr, nullptr, nullptr, nullptr, nullptr, TranslateGRFStrings, }, + /* 0x14 */ { StaticGRFInfo, nullptr, nullptr, nullptr, nullptr, nullptr, }, }; GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line); @@ -9011,7 +9284,7 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage) grfmsg(2, "DecodeSpecialSprite: Unexpected import block, skipping"); } else if (action >= lengthof(handlers)) { grfmsg(7, "DecodeSpecialSprite: Skipping unknown action 0x%02X", action); - } else if (handlers[action][stage] == NULL) { + } else if (handlers[action][stage] == nullptr) { grfmsg(7, "DecodeSpecialSprite: Skipping action 0x%02X in stage %d", action, stage); } else { grfmsg(7, "DecodeSpecialSprite: Handling action 0x%02X in stage %d", action, stage); @@ -9072,7 +9345,7 @@ void LoadNewGRFFile(GRFConfig *config, uint file_index, GrfLoadingStage stage, S * processed once at initialization. */ if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) { _cur.grffile = GetFileByFilename(filename); - if (_cur.grffile == NULL) usererror("File '%s' lost in cache.\n", filename); + if (_cur.grffile == nullptr) usererror("File '%s' lost in cache.\n", filename); if (stage == GLS_RESERVE && config->status != GCS_INITIALISED) return; if (stage == GLS_ACTIVATION && !HasBit(config->flags, GCF_RESERVED)) return; } @@ -9207,6 +9480,21 @@ static void ActivateOldShore() } } +/** + * Replocate the old tram depot sprites to the new position, if no new ones were loaded. + */ +static void ActivateOldTramDepot() +{ + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK) { + DupSprite(SPR_ROAD_DEPOT + 0, SPR_TRAMWAY_DEPOT_NO_TRACK + 0); // use road depot graphics for "no tracks" + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 1, SPR_TRAMWAY_DEPOT_NO_TRACK + 1); + DupSprite(SPR_ROAD_DEPOT + 2, SPR_TRAMWAY_DEPOT_NO_TRACK + 2); // use road depot graphics for "no tracks" + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 3, SPR_TRAMWAY_DEPOT_NO_TRACK + 3); + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 4, SPR_TRAMWAY_DEPOT_NO_TRACK + 4); + DupSprite(SPR_TRAMWAY_DEPOT_WITH_TRACK + 5, SPR_TRAMWAY_DEPOT_NO_TRACK + 5); + } +} + /** * Decide whether price base multipliers of grfs shall apply globally or only to the grf specifying them */ @@ -9217,7 +9505,7 @@ static void FinalisePriceBaseMultipliers() static const uint32 override_features = (1 << GSF_TRAINS) | (1 << GSF_ROADVEHICLES) | (1 << GSF_SHIPS) | (1 << GSF_AIRCRAFT); /* Evaluate grf overrides */ - int num_grfs = _grf_files.Length(); + int num_grfs = (uint)_grf_files.size(); int *grf_overrides = AllocaM(int, num_grfs); for (int i = 0; i < num_grfs; i++) { grf_overrides[i] = -1; @@ -9227,9 +9515,9 @@ static void FinalisePriceBaseMultipliers() if (override == 0) continue; GRFFile *dest = GetFileByGRFID(override); - if (dest == NULL) continue; + if (dest == nullptr) continue; - grf_overrides[i] = _grf_files.FindIndex(dest); + grf_overrides[i] = find_index(_grf_files, dest); assert(grf_overrides[i] >= 0); } @@ -9289,10 +9577,9 @@ static void FinalisePriceBaseMultipliers() } /* Apply fallback prices for grf version < 8 */ - const GRFFile * const *end = _grf_files.End(); - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - if ((*file)->grf_version >= 8) continue; - PriceMultipliers &price_base_multipliers = (*file)->price_base_multipliers; + for (GRFFile * const file : _grf_files) { + if (file->grf_version >= 8) continue; + PriceMultipliers &price_base_multipliers = file->price_base_multipliers; for (Price p = PR_BEGIN; p < PR_END; p++) { Price fallback_price = _price_base_specs[p].fallback_price; if (fallback_price != INVALID_PRICE && price_base_multipliers[p] == INVALID_PRICE_MODIFIER) { @@ -9304,21 +9591,21 @@ static void FinalisePriceBaseMultipliers() } /* Decide local/global scope of price base multipliers */ - for (GRFFile **file = _grf_files.Begin(); file != end; file++) { - PriceMultipliers &price_base_multipliers = (*file)->price_base_multipliers; + for (GRFFile * const file : _grf_files) { + PriceMultipliers &price_base_multipliers = file->price_base_multipliers; for (Price p = PR_BEGIN; p < PR_END; p++) { if (price_base_multipliers[p] == INVALID_PRICE_MODIFIER) { /* No multiplier was set; set it to a neutral value */ price_base_multipliers[p] = 0; } else { - if (!HasBit((*file)->grf_features, _price_base_specs[p].grf_feature)) { + if (!HasBit(file->grf_features, _price_base_specs[p].grf_feature)) { /* The grf does not define any objects of the feature, * so it must be a difficulty setting. Apply it globally */ - DEBUG(grf, 3, "'%s' sets global price base multiplier %d", (*file)->filename, p); + DEBUG(grf, 3, "'%s' sets global price base multiplier %d", file->filename, p); SetPriceBaseMultiplier(p, price_base_multipliers[p]); price_base_multipliers[p] = 0; } else { - DEBUG(grf, 3, "'%s' sets local price base multiplier %d", (*file)->filename, p); + DEBUG(grf, 3, "'%s' sets local price base multiplier %d", file->filename, p); } } } @@ -9330,10 +9617,10 @@ extern void InitGRFTownGeneratorNames(); /** Finish loading NewGRFs and execute needed post-processing */ static void AfterLoadGRFs() { - for (StringIDMapping *it = _string_to_grf_mapping.Begin(); it != _string_to_grf_mapping.End(); it++) { - *it->target = MapGRFStringID(it->grfid, it->source); + for (StringIDMapping &it : _string_to_grf_mapping) { + *it.target = MapGRFStringID(it.grfid, it.source); } - _string_to_grf_mapping.Clear(); + _string_to_grf_mapping.clear(); /* Free the action 6 override sprites. */ for (GRFLineToSpriteOverride::iterator it = _grf_line_to_action6_sprite_override.begin(); it != _grf_line_to_action6_sprite_override.end(); it++) { @@ -9386,8 +9673,12 @@ static void AfterLoadGRFs() /* Load old shore sprites in new position, if they were replaced by ActionA */ ActivateOldShore(); + /* Load old tram depot sprites in new position, if no new ones are present */ + ActivateOldTramDepot(); + /* Set up custom rail types */ InitRailTypes(); + InitRoadTypes(); Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { @@ -9395,6 +9686,31 @@ static void AfterLoadGRFs() /* Set RV maximum speed from the mph/0.8 unit value */ e->u.road.max_speed = _gted[e->index].rv_max_speed * 4; } + + RoadTramType rtt = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? RTT_TRAM : RTT_ROAD; + + const GRFFile *file = e->GetGRF(); + if (file == nullptr || _gted[e->index].roadtramtype == 0) { + e->u.road.roadtype = (rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; + continue; + } + + /* Remove +1 offset. */ + _gted[e->index].roadtramtype--; + + const std::vector *list = (rtt == RTT_TRAM) ? &file->tramtype_list : &file->roadtype_list; + if (_gted[e->index].roadtramtype < list->size()) + { + RoadTypeLabel rtl = (*list)[_gted[e->index].roadtramtype]; + RoadType rt = GetRoadTypeByLabel(rtl); + if (rt != INVALID_ROADTYPE && GetRoadTramType(rt) == rtt) { + e->u.road.roadtype = rt; + continue; + } + } + + /* Road type is not available, so disable this engine */ + e->info.climates = 0; } FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { @@ -9449,11 +9765,11 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) /* * Reset the status of all files, so we can 'retry' to load them. * This is needed when one for example rearranges the NewGRFs in-game - * and a previously disabled NewGRF becomes useable. If it would not + * and a previously disabled NewGRF becomes usable. If it would not * be reset, the NewGRF would remain disabled even though it should * have been enabled. */ - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (c->status != GCS_NOT_FOUND) c->status = GCS_UNKNOWN; } @@ -9465,7 +9781,7 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) for (GrfLoadingStage stage = GLS_LABELSCAN; stage <= GLS_ACTIVATION; stage++) { /* Set activated grfs back to will-be-activated between reservation- and activation-stage. * This ensures that action7/9 conditions 0x06 - 0x0A work correctly. */ - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (c->status == GCS_ACTIVATED) c->status = GCS_INITIALISED; } @@ -9484,7 +9800,7 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset) uint num_non_static = 0; _cur.stage = stage; - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue; if (stage > GLS_INIT && HasBit(c->flags, GCF_INIT_ONLY)) continue; diff --git a/src/newgrf.h b/src/newgrf.h index 27970dece8..4adcae9b8e 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -14,6 +14,7 @@ #include "cargotype.h" #include "rail_type.h" +#include "road_type.h" #include "fileio_type.h" #include "core/bitmath_func.hpp" #include "core/alloc_type.hpp" @@ -83,6 +84,8 @@ enum GrfSpecFeature { GSF_OBJECTS, GSF_RAILTYPES, GSF_AIRPORTTILES, + GSF_ROADTYPES, + GSF_TRAMTYPES, GSF_END, GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope) @@ -122,17 +125,23 @@ struct GRFFile : ZeroedMemoryAllocator { GRFLabel *label; ///< Pointer to the first label. This is a linked list, not an array. - SmallVector cargo_list; ///< Cargo translation table (local ID -> label) + std::vector cargo_list; ///< Cargo translation table (local ID -> label) uint8 cargo_map[NUM_CARGO]; ///< Inverse cargo translation table (CargoID -> local ID) - SmallVector railtype_list; ///< Railtype translation table - RailTypeByte railtype_map[RAILTYPE_END]; + std::vector railtype_list; ///< Railtype translation table + RailType railtype_map[RAILTYPE_END]; + + std::vector roadtype_list; ///< Roadtype translation table (road) + RoadType roadtype_map[ROADTYPE_END]; + + std::vector tramtype_list; ///, Roadtype translation table (tram) + RoadType tramtype_map[ROADTYPE_END]; CanalProperties canal_local_properties[CF_END]; ///< Canal properties as set by this NewGRF struct LanguageMap *language_map; ///< Mappings related to the languages. - int traininfo_vehicle_pitch; ///< Vertical offset for draing train images in depot GUI and vehicle details + int traininfo_vehicle_pitch; ///< Vertical offset for drawing train images in depot GUI and vehicle details uint traininfo_vehicle_width; ///< Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details uint32 grf_features; ///< Bitset of GrfSpecFeature the grf uses @@ -158,12 +167,19 @@ enum ShoreReplacement { SHORE_REPLACE_ONLY_NEW, ///< Only corner-shores were loaded by Action5 (openttd(w/d).grf only). }; +enum TramReplacement { + TRAMWAY_REPLACE_DEPOT_NONE, ///< No tram depot graphics were loaded. + TRAMWAY_REPLACE_DEPOT_WITH_TRACK, ///< Electrified depot graphics with tram track were loaded. + TRAMWAY_REPLACE_DEPOT_NO_TRACK, ///< Electrified depot graphics without tram track were loaded. +}; + struct GRFLoadedFeatures { bool has_2CC; ///< Set if any vehicle is loaded which uses 2cc (two company colours). uint64 used_liveries; ///< Bitmask of #LiveryScheme used by the defined engines. bool has_newhouses; ///< Set if there are any newhouses loaded. bool has_newindustries; ///< Set if there are any newindustries loaded. ShoreReplacement shore; ///< In which way shore sprites were replaced. + TramReplacement tram; ///< In which way tram depots were replaced. }; /** diff --git a/src/newgrf_airport.cpp b/src/newgrf_airport.cpp index d0621f60e6..e654dcc78c 100644 --- a/src/newgrf_airport.cpp +++ b/src/newgrf_airport.cpp @@ -21,7 +21,7 @@ /** Resolver for the airport scope. */ struct AirportScopeResolver : public ScopeResolver { - struct Station *st; ///< Station of the airport for which the callback is run, or \c NULL for build gui. + struct Station *st; ///< Station of the airport for which the callback is run, or \c nullptr for build gui. byte airport_id; ///< Type of airport for which the callback is run. byte layout; ///< Layout of the airport to build. TileIndex tile; ///< Tile for the callback, only valid for airporttile callbacks. @@ -30,7 +30,7 @@ struct AirportScopeResolver : public ScopeResolver { * Constructor of the scope resolver for an airport. * @param ro Surrounding resolver. * @param tile %Tile for the callback, only valid for airporttile callbacks. - * @param st %Station of the airport for which the callback is run, or \c NULL for build gui. + * @param st %Station of the airport for which the callback is run, or \c nullptr for build gui. * @param airport_id Type of airport for which the callback is run. * @param layout Layout of the airport to build. */ @@ -39,9 +39,9 @@ struct AirportScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; - /* virtual */ void StorePSA(uint pos, int32 value); + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + void StorePSA(uint pos, int32 value) override; }; /** Resolver object for airports. */ @@ -51,7 +51,7 @@ struct AirportResolverObject : public ResolverObject { AirportResolverObject(TileIndex tile, Station *st, byte airport_id, byte layout, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &this->airport_scope; @@ -59,7 +59,7 @@ struct AirportResolverObject : public ResolverObject { } } - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; /** @@ -130,6 +130,24 @@ bool AirportSpec::IsAvailable() const return _cur_year <= this->max_year; } +/** + * Check if the airport would be within the map bounds at the given tile. + * @param table Selected layout table. This affects airport rotation, and therefore dimensions. + * @param tile Top corner of the airport. + * @return true iff the airport would be within the map bounds at the given tile. + */ +bool AirportSpec::IsWithinMapBounds(byte table, TileIndex tile) const +{ + if (table >= this->num_table) return false; + + byte w = this->size_x; + byte h = this->size_y; + if (this->rotation[table] == DIR_E || this->rotation[table] == DIR_W) Swap(w, h); + + return TileX(tile) + w < MapSizeX() && + TileY(tile) + h < MapSizeY(); +} + /** * This function initializes the airportspec array. */ @@ -184,14 +202,14 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) case 0x40: return this->layout; } - if (this->st == NULL) { + if (this->st == nullptr) { *available = false; return UINT_MAX; } switch (variable) { /* Get a variable from the persistent storage */ - case 0x7C: return (this->st->airport.psa != NULL) ? this->st->airport.psa->GetValue(parameter) : 0; + case 0x7C: return (this->st->airport.psa != nullptr) ? this->st->airport.psa->GetValue(parameter) : 0; case 0xF0: return this->st->facilities; case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); @@ -207,12 +225,12 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) if (group->num_loaded > 0) return group->loaded[0]; if (group->num_loading > 0) return group->loading[0]; - return NULL; + return nullptr; } /* virtual */ uint32 AirportScopeResolver::GetRandomBits() const { - return this->st == NULL ? 0 : this->st->random_bits; + return this->st == nullptr ? 0 : this->st->random_bits; } /** @@ -222,14 +240,14 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) */ /* virtual */ void AirportScopeResolver::StorePSA(uint pos, int32 value) { - if (this->st == NULL) return; + if (this->st == nullptr) return; - if (this->st->airport.psa == NULL) { + if (this->st->airport.psa == nullptr) { /* There is no need to create a storage if the value is zero. */ if (value == 0) return; /* Create storage on first modification. */ - uint32 grfid = (this->ro.grffile != NULL) ? this->ro.grffile->grfid : 0; + uint32 grfid = (this->ro.grffile != nullptr) ? this->ro.grffile->grfid : 0; assert(PersistentStorage::CanAllocateItem()); this->st->airport.psa = new PersistentStorage(grfid, GSF_AIRPORTS, this->st->airport.tile); } @@ -239,7 +257,7 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) /** * Constructor of the airport resolver. * @param tile %Tile for the callback, only valid for airporttile callbacks. - * @param st %Station of the airport for which the callback is run, or \c NULL for build gui. + * @param st %Station of the airport for which the callback is run, or \c nullptr for build gui. * @param airport_id Type of airport for which the callback is run. * @param layout Layout of the airport to build. * @param callback Callback ID. @@ -255,9 +273,9 @@ AirportResolverObject::AirportResolverObject(TileIndex tile, Station *st, byte a SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout) { - AirportResolverObject object(INVALID_TILE, NULL, as->GetIndex(), layout); + AirportResolverObject object(INVALID_TILE, nullptr, as->GetIndex(), layout); const SpriteGroup *group = object.Resolve(); - if (group == NULL) return as->preview_sprite; + if (group == nullptr) return as->preview_sprite; return group->GetResult(); } @@ -277,7 +295,7 @@ uint16 GetAirportCallback(CallbackID callback, uint32 param1, uint32 param2, Sta */ StringID GetAirportTextCallback(const AirportSpec *as, byte layout, uint16 callback) { - AirportResolverObject object(INVALID_TILE, NULL, as->GetIndex(), layout, (CallbackID)callback); + AirportResolverObject object(INVALID_TILE, nullptr, as->GetIndex(), layout, (CallbackID)callback); uint16 cb_res = object.ResolveCallback(); if (cb_res == CALLBACK_FAILED || cb_res == 0x400) return STR_UNDEFINED; if (cb_res > 0x400) { diff --git a/src/newgrf_airport.h b/src/newgrf_airport.h index 867362e9ad..7b752e741a 100644 --- a/src/newgrf_airport.h +++ b/src/newgrf_airport.h @@ -123,6 +123,7 @@ struct AirportSpec { static AirportSpec *GetWithoutOverride(byte type); bool IsAvailable() const; + bool IsWithinMapBounds(byte table, TileIndex index) const; static void ResetAirports(); diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp index 2d3a5129c9..42f4f1d36b 100644 --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -149,7 +149,7 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32 } } /* Not an 'old type' tile */ - if (ats->grf_prop.spritegroup[0] != NULL) { // tile has a spritegroup ? + if (ats->grf_prop.spritegroup[0] != nullptr) { // tile has a spritegroup ? if (ats->grf_prop.grffile->grfid == cur_grfid) { // same airport, same grf ? return ats->grf_prop.local_id; } else { @@ -162,7 +162,7 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32 /* virtual */ uint32 AirportTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { - assert(this->st != NULL); + assert(this->st != nullptr); extern uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile); @@ -203,14 +203,14 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32 /* virtual */ uint32 AirportTileScopeResolver::GetRandomBits() const { - return (this->st == NULL ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16); + return (this->st == nullptr ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16); } /** * Constructor of the resolver for airport tiles. * @param ats Specification of the airport tiles. * @param tile %Tile for the callback, only valid for airporttile callbacks. - * @param st Station of the airport for which the callback is run, or \c NULL for build gui. + * @param st Station of the airport for which the callback is run, or \c nullptr for build gui. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. @@ -230,7 +230,7 @@ uint16 GetAirportTileCallback(CallbackID callback, uint32 param1, uint32 param2, static void AirportDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte colour, StationGfx gfx) { - const DrawTileSprites *dts = group->ProcessRegisters(NULL); + const DrawTileSprites *dts = group->ProcessRegisters(nullptr); SpriteID image = dts->ground.sprite; SpriteID pal = dts->ground.pal; @@ -261,7 +261,7 @@ bool DrawNewAirportTile(TileInfo *ti, Station *st, StationGfx gfx, const Airport AirportTileResolverObject object(airts, ti->tile, st); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->type != SGT_TILELAYOUT) { + if (group == nullptr || group->type != SGT_TILELAYOUT) { return false; } @@ -282,7 +282,7 @@ struct AirportTileAnimationBase : public AnimationBaseanimation_special_flags, 0)); } diff --git a/src/newgrf_airporttiles.h b/src/newgrf_airporttiles.h index dc04642037..313614eafe 100644 --- a/src/newgrf_airporttiles.h +++ b/src/newgrf_airporttiles.h @@ -21,7 +21,7 @@ /** Scope resolver for handling the tiles of an airport. */ struct AirportTileScopeResolver : public ScopeResolver { - struct Station *st; ///< %Station of the airport for which the callback is run, or \c NULL for build gui. + struct Station *st; ///< %Station of the airport for which the callback is run, or \c nullptr for build gui. byte airport_id; ///< Type of airport for which the callback is run. TileIndex tile; ///< Tile for the callback, only valid for airporttile callbacks. @@ -29,17 +29,17 @@ struct AirportTileScopeResolver : public ScopeResolver { * Constructor of the scope resolver specific for airport tiles. * @param ats Specification of the airport tiles. * @param tile %Tile for the callback, only valid for airporttile callbacks. - * @param st Station of the airport for which the callback is run, or \c NULL for build gui. + * @param st Station of the airport for which the callback is run, or \c nullptr for build gui. */ AirportTileScopeResolver(ResolverObject &ro, const AirportTileSpec *ats, TileIndex tile, Station *st) : ScopeResolver(ro), st(st), tile(tile) { - assert(st != NULL); + assert(st != nullptr); this->airport_id = st->airport.type; } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; }; /** Resolver for tiles of an airport. */ @@ -49,7 +49,7 @@ struct AirportTileResolverObject : public ResolverObject { AirportTileResolverObject(const AirportTileSpec *ats, TileIndex tile, Station *st, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &tiles_scope; diff --git a/src/newgrf_animation_base.h b/src/newgrf_animation_base.h index 791f3d691a..8f1135a6ba 100644 --- a/src/newgrf_animation_base.h +++ b/src/newgrf_animation_base.h @@ -39,7 +39,7 @@ struct AnimationBase { */ static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = 0) { - assert(spec != NULL); + assert(spec != nullptr); /* Acquire the animation speed from the NewGRF. */ uint8 animation_speed = spec->animation.speed; diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp index 3438bb9850..61ba601d56 100644 --- a/src/newgrf_canal.cpp +++ b/src/newgrf_canal.cpp @@ -30,8 +30,8 @@ struct CanalScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; }; /** Resolver object for canals. */ @@ -41,7 +41,7 @@ struct CanalResolverObject : public ResolverObject { CanalResolverObject(CanalFeature feature, TileIndex tile, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &this->canal_scope; @@ -49,7 +49,7 @@ struct CanalResolverObject : public ResolverObject { } } - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; /* virtual */ uint32 CanalScopeResolver::GetRandomBits() const @@ -108,7 +108,7 @@ struct CanalResolverObject : public ResolverObject { /* virtual */ const SpriteGroup *CanalResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (group->num_loaded == 0) return NULL; + if (group->num_loaded == 0) return nullptr; return group->loaded[0]; } @@ -138,7 +138,7 @@ SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile) { CanalResolverObject object(feature, tile); const SpriteGroup *group = object.Resolve(); - if (group == NULL) return 0; + if (group == nullptr) return 0; return group->GetResult(); } diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index 7d830c5730..0793d7120f 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -19,7 +19,7 @@ struct CargoResolverObject : public ResolverObject { CargoResolverObject(const CargoSpec *cs, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; /* virtual */ const SpriteGroup *CargoResolverObject::ResolveReal(const RealSpriteGroup *group) const @@ -29,7 +29,7 @@ struct CargoResolverObject : public ResolverObject { if (group->num_loaded > 0) return group->loaded[0]; if (group->num_loading > 0) return group->loading[0]; - return NULL; + return nullptr; } /** @@ -54,7 +54,7 @@ SpriteID GetCustomCargoSprite(const CargoSpec *cs) { CargoResolverObject object(cs); const SpriteGroup *group = object.Resolve(); - if (group == NULL) return 0; + if (group == nullptr) return 0; return group->GetResult(); } @@ -82,10 +82,10 @@ CargoID GetCargoTranslation(uint8 cargo, const GRFFile *grffile, bool usebit) /* Other cases use (possibly translated) cargobits */ - if (grffile->cargo_list.Length() > 0) { + if (grffile->cargo_list.size() > 0) { /* ...and the cargo is in bounds, then get the cargo ID for * the label */ - if (cargo < grffile->cargo_list.Length()) return GetCargoIDByLabel(grffile->cargo_list[cargo]); + if (cargo < grffile->cargo_list.size()) return GetCargoIDByLabel(grffile->cargo_list[cargo]); } else { /* Else the cargo value is a 'climate independent' 'bitnum' */ return GetCargoIDByBitnum(cargo); diff --git a/src/newgrf_class_func.h b/src/newgrf_class_func.h index c2a30992ae..0a90bf80e5 100644 --- a/src/newgrf_class_func.h +++ b/src/newgrf_class_func.h @@ -34,7 +34,7 @@ DEFINE_NEWGRF_CLASS_METHOD(void)::ResetClass() this->ui_count = 0; free(this->spec); - this->spec = NULL; + this->spec = nullptr; } /** Reset the classes, i.e. clear everything. */ @@ -154,7 +154,7 @@ DEFINE_NEWGRF_CLASS_METHOD(Tid)::GetUIClass(uint index) DEFINE_NEWGRF_CLASS_METHOD(const Tspec *)::GetSpec(uint index) const { /* If the custom spec isn't defined any more, then the GRF file probably was not loaded. */ - return index < this->GetSpecCount() ? this->spec[index] : NULL; + return index < this->GetSpecCount() ? this->spec[index] : nullptr; } /** @@ -191,7 +191,7 @@ DEFINE_NEWGRF_CLASS_METHOD(int)::GetUIFromIndex(int index) const * Retrieve a spec by GRF location. * @param grfid GRF ID of spec. * @param local_id Index within GRF file of spec. - * @param index Pointer to return the index of the spec in its class. If NULL then not used. + * @param index Pointer to return the index of the spec in its class. If nullptr then not used. * @return The spec. */ DEFINE_NEWGRF_CLASS_METHOD(const Tspec *)::GetByGrf(uint32 grfid, byte local_id, int *index) @@ -201,15 +201,15 @@ DEFINE_NEWGRF_CLASS_METHOD(const Tspec *)::GetByGrf(uint32 grfid, byte local_id, for (Tid i = (Tid)0; i < Tmax; i++) { for (j = 0; j < classes[i].count; j++) { const Tspec *spec = classes[i].spec[j]; - if (spec == NULL) continue; + if (spec == nullptr) continue; if (spec->grf_prop.grffile->grfid == grfid && spec->grf_prop.local_id == local_id) { - if (index != NULL) *index = j; + if (index != nullptr) *index = j; return spec; } } } - return NULL; + return nullptr; } #undef DEFINE_NEWGRF_CLASS_METHOD diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index 4caf3a5d47..49ba60529c 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -235,9 +235,9 @@ uint16 IndustryOverrideManager::AddEntityID(byte grf_local_id, uint32 grfid, byt const IndustrySpec *inds = GetIndustrySpec(id); /* This industry must be one that is not available(enabled), mostly because of climate. - * And it must not already be used by a grf (grffile == NULL). + * And it must not already be used by a grf (grffile == nullptr). * So reserve this slot here, as it is the chosen one */ - if (!inds->enabled && inds->grf_prop.grffile == NULL) { + if (!inds->enabled && inds->grf_prop.grffile == nullptr) { EntityIDMapping *map = &mapping_ID[id]; if (map->entity_id == 0 && map->grfid == 0) { @@ -279,7 +279,7 @@ void IndustryOverrideManager::SetEntitySpec(IndustrySpec *inds) } /* Now that we know we can use the given id, copy the spec to its final destination... */ - memcpy(&_industry_specs[ind_id], inds, sizeof(*inds)); + _industry_specs[ind_id] = *inds; /* ... and mark it as usable*/ _industry_specs[ind_id].enabled = true; } @@ -463,13 +463,13 @@ uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8) /** * Returns company information like in vehicle var 43 or station var 43. * @param owner Owner of the object. - * @param l Livery of the object; NULL to use default. + * @param l Livery of the object; nullptr to use default. * @return NewGRF company information. */ uint32 GetCompanyInfo(CompanyID owner, const Livery *l) { - if (l == NULL && Company::IsValidID(owner)) l = &Company::Get(owner)->livery[LS_DEFAULT]; - return owner | (Company::IsValidAiID(owner) ? 0x10000 : 0) | (l != NULL ? (l->colour1 << 24) | (l->colour2 << 28) : 0); + if (l == nullptr && Company::IsValidID(owner)) l = &Company::Get(owner)->livery[LS_DEFAULT]; + return owner | (Company::IsValidAiID(owner) ? 0x10000 : 0) | (l != nullptr ? (l->colour1 << 24) | (l->colour2 << 28) : 0); } /** @@ -579,7 +579,7 @@ bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_r } -/* static */ SmallVector NewGRFSpriteLayout::result_seq; +/* static */ std::vector NewGRFSpriteLayout::result_seq; /** * Clone the building sprites of a spritelayout. @@ -587,8 +587,8 @@ bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_r */ void NewGRFSpriteLayout::Clone(const DrawTileSeqStruct *source) { - assert(this->seq == NULL); - assert(source != NULL); + assert(this->seq == nullptr); + assert(source != nullptr); size_t count = 1; // 1 for the terminator const DrawTileSeqStruct *element; @@ -607,7 +607,7 @@ void NewGRFSpriteLayout::Clone(const NewGRFSpriteLayout *source) { this->Clone((const DrawTileSprites*)source); - if (source->registers != NULL) { + if (source->registers != nullptr) { size_t count = 1; // 1 for the ground sprite const DrawTileSeqStruct *element; foreach_draw_tile_seq(element, source->seq) count++; @@ -625,7 +625,7 @@ void NewGRFSpriteLayout::Clone(const NewGRFSpriteLayout *source) */ void NewGRFSpriteLayout::Allocate(uint num_sprites) { - assert(this->seq == NULL); + assert(this->seq == nullptr); DrawTileSeqStruct *sprites = CallocT(num_sprites + 1); sprites[num_sprites].MakeTerminator(); @@ -637,8 +637,8 @@ void NewGRFSpriteLayout::Allocate(uint num_sprites) */ void NewGRFSpriteLayout::AllocateRegisters() { - assert(this->seq != NULL); - assert(this->registers == NULL); + assert(this->seq != nullptr); + assert(this->registers == nullptr); size_t count = 1; // 1 for the ground sprite const DrawTileSeqStruct *element; @@ -650,7 +650,7 @@ void NewGRFSpriteLayout::AllocateRegisters() /** * Prepares a sprite layout before resolving action-1-2-3 chains. * Integrates offsets into the layout and determines which chains to resolve. - * @note The function uses statically allocated temporary storage, which is reused everytime when calling the function. + * @note The function uses statically allocated temporary storage, which is reused every time when calling the function. * That means, you have to use the sprite layout before calling #PrepareLayout() the next time. * @param orig_offset Offset to apply to non-action-1 sprites. * @param newgrf_ground_offset Offset to apply to action-1 ground sprites. @@ -661,12 +661,13 @@ void NewGRFSpriteLayout::AllocateRegisters() */ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, uint constr_stage, bool separate_ground) const { - result_seq.Clear(); + result_seq.clear(); uint32 var10_values = 0; /* Create a copy of the spritelayout, so we can modify some values. * Also include the groundsprite into the sequence for easier processing. */ - DrawTileSeqStruct *result = result_seq.Append(); + /*C++17: DrawTileSeqStruct *result = &*/ result_seq.emplace_back(); + DrawTileSeqStruct *result = &result_seq.back(); result->image = ground; result->delta_x = 0; result->delta_y = 0; @@ -674,17 +675,17 @@ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_groun const DrawTileSeqStruct *dtss; foreach_draw_tile_seq(dtss, this->seq) { - *result_seq.Append() = *dtss; + result_seq.push_back(*dtss); } - result_seq.Append()->MakeTerminator(); - + result_seq.emplace_back() /*C++17: .MakeTerminator()*/; + result_seq.back().MakeTerminator(); /* Determine the var10 values the action-1-2-3 chains needs to be resolved for, * and apply the default sprite offsets (unless disabled). */ const TileLayoutRegisters *regs = this->registers; bool ground = true; - foreach_draw_tile_seq(result, result_seq.Begin()) { + foreach_draw_tile_seq(result, result_seq.data()) { TileLayoutFlags flags = TLF_NOTHING; - if (regs != NULL) flags = regs->flags; + if (regs != nullptr) flags = regs->flags; /* Record var10 value for the sprite */ if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) { @@ -696,7 +697,7 @@ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_groun if (!(flags & TLF_SPRITE)) { if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) { result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset; - if (constr_stage > 0 && regs != NULL) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_sprite_offset); + if (constr_stage > 0 && regs != nullptr) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_sprite_offset); } else { result->image.sprite += orig_offset; } @@ -712,12 +713,12 @@ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_groun if (!(flags & TLF_PALETTE)) { if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) { result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset; - if (constr_stage > 0 && regs != NULL) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_palette_offset); + if (constr_stage > 0 && regs != nullptr) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_palette_offset); } } ground = false; - if (regs != NULL) regs++; + if (regs != nullptr) regs++; } return var10_values; @@ -736,9 +737,9 @@ void NewGRFSpriteLayout::ProcessRegisters(uint8 resolved_var10, uint32 resolved_ DrawTileSeqStruct *result; const TileLayoutRegisters *regs = this->registers; bool ground = true; - foreach_draw_tile_seq(result, result_seq.Begin()) { + foreach_draw_tile_seq(result, result_seq.data()) { TileLayoutFlags flags = TLF_NOTHING; - if (regs != NULL) flags = regs->flags; + if (regs != nullptr) flags = regs->flags; /* Is the sprite or bounding box affected by an action-1-2-3 chain? */ if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) { @@ -793,6 +794,6 @@ void NewGRFSpriteLayout::ProcessRegisters(uint8 resolved_var10, uint32 resolved_ } ground = false; - if (regs != NULL) regs++; + if (regs != nullptr) regs++; } } diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h index 5721b7eb20..ec6c454a0c 100644 --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -132,7 +132,7 @@ struct NewGRFSpriteLayout : ZeroedMemoryAllocator, DrawTileSprites { */ void Clone(const DrawTileSprites *source) { - assert(source != NULL && this != source); + assert(source != nullptr && this != source); this->ground = source->ground; this->Clone(source->seq); } @@ -151,7 +151,7 @@ struct NewGRFSpriteLayout : ZeroedMemoryAllocator, DrawTileSprites { */ bool NeedsPreprocessing() const { - return this->registers != NULL; + return this->registers != nullptr; } uint32 PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, uint constr_stage, bool separate_ground) const; @@ -164,13 +164,13 @@ struct NewGRFSpriteLayout : ZeroedMemoryAllocator, DrawTileSprites { */ const DrawTileSeqStruct *GetLayout(PalSpriteID *ground) const { - DrawTileSeqStruct *front = result_seq.Begin(); + DrawTileSeqStruct *front = result_seq.data(); *ground = front->image; return front + 1; } private: - static SmallVector result_seq; ///< Temporary storage when preprocessing spritelayouts. + static std::vector result_seq; ///< Temporary storage when preprocessing spritelayouts. }; /** @@ -228,6 +228,7 @@ class HouseOverrideManager : public OverrideManagerBase { public: HouseOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} + void SetEntitySpec(const HouseSpec *hs); }; @@ -238,8 +239,9 @@ public: IndustryOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} - virtual uint16 AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id); - virtual uint16 GetID(uint8 grf_local_id, uint32 grfid) const; + uint16 AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id) override; + uint16 GetID(uint8 grf_local_id, uint32 grfid) const override; + void SetEntitySpec(IndustrySpec *inds); }; @@ -296,7 +298,7 @@ extern ObjectOverrideManager _object_mngr; uint32 GetTerrainType(TileIndex tile, TileContext context = TCX_NORMAL); TileIndex GetNearbyTile(byte parameter, TileIndex tile, bool signed_offsets = true, Axis axis = INVALID_AXIS); uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8); -uint32 GetCompanyInfo(CompanyID owner, const struct Livery *l = NULL); +uint32 GetCompanyInfo(CompanyID owner, const struct Livery *l = nullptr); CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, const GRFFile *grffile, StringID default_error); void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res); diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 593851e288..676f677bcf 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -21,6 +21,8 @@ #include "video/video_driver.hpp" #include "strings_func.h" #include "textfile_gui.h" +#include "thread.h" +#include "newgrf_config.h" #include "fileio_func.h" #include "fios.h" @@ -29,7 +31,7 @@ /** Create a new GRFTextWrapper. */ GRFTextWrapper::GRFTextWrapper() : - text(NULL) + text(nullptr) { } @@ -50,7 +52,7 @@ GRFConfig::GRFConfig(const char *filename) : url(new GRFTextWrapper()), num_valid_params(lengthof(param)) { - if (filename != NULL) this->filename = stredup(filename); + if (filename != nullptr) this->filename = stredup(filename); this->name->AddRef(); this->info->AddRef(); this->url->AddRef(); @@ -78,16 +80,16 @@ GRFConfig::GRFConfig(const GRFConfig &config) : { MemCpyT(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum)); MemCpyT(this->param, config.param, lengthof(this->param)); - if (config.filename != NULL) this->filename = stredup(config.filename); + if (config.filename != nullptr) this->filename = stredup(config.filename); this->name->AddRef(); this->info->AddRef(); this->url->AddRef(); - if (config.error != NULL) this->error = new GRFError(*config.error); - for (uint i = 0; i < config.param_info.Length(); i++) { - if (config.param_info[i] == NULL) { - *this->param_info.Append() = NULL; + if (config.error != nullptr) this->error = new GRFError(*config.error); + for (uint i = 0; i < config.param_info.size(); i++) { + if (config.param_info[i] == nullptr) { + this->param_info.push_back(nullptr); } else { - *this->param_info.Append() = new GRFParameterInfo(*config.param_info[i]); + this->param_info.push_back(new GRFParameterInfo(*config.param_info[i])); } } } @@ -104,7 +106,7 @@ GRFConfig::~GRFConfig() this->info->Release(); this->url->Release(); - for (uint i = 0; i < this->param_info.Length(); i++) delete this->param_info[i]; + for (uint i = 0; i < this->param_info.size(); i++) delete this->param_info[i]; } /** @@ -155,8 +157,8 @@ void GRFConfig::SetParameterDefaults() if (!this->has_param_defaults) return; - for (uint i = 0; i < this->param_info.Length(); i++) { - if (this->param_info[i] == NULL) continue; + for (uint i = 0; i < this->param_info.size(); i++) { + if (this->param_info[i] == nullptr) continue; this->param_info[i]->SetValue(this, this->param_info[i]->def_value); } } @@ -182,9 +184,9 @@ void GRFConfig::SetSuitablePalette() */ void GRFConfig::FinalizeParameterInfo() { - for (GRFParameterInfo **info = this->param_info.Begin(); info != this->param_info.End(); ++info) { - if (*info == NULL) continue; - (*info)->Finalize(); + for (GRFParameterInfo *info : this->param_info) { + if (info == nullptr) continue; + info->Finalize(); } } @@ -216,8 +218,8 @@ GRFError::GRFError(const GRFError &error) : message(error.message), severity(error.severity) { - if (error.custom_message != NULL) this->custom_message = stredup(error.custom_message); - if (error.data != NULL) this->data = stredup(error.data); + if (error.custom_message != nullptr) this->custom_message = stredup(error.custom_message); + if (error.data != nullptr) this->data = stredup(error.data); memcpy(this->param_value, error.param_value, sizeof(this->param_value)); } @@ -232,8 +234,8 @@ GRFError::~GRFError() * @param nr The newgrf parameter that is changed. */ GRFParameterInfo::GRFParameterInfo(uint nr) : - name(NULL), - desc(NULL), + name(nullptr), + desc(nullptr), type(PTYPE_UINT_ENUM), min_value(0), max_value(UINT32_MAX), @@ -261,8 +263,8 @@ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : num_bit(info.num_bit), complete_labels(info.complete_labels) { - for (uint i = 0; i < info.value_names.Length(); i++) { - SmallPair *data = info.value_names.Get(i); + for (uint i = 0; i < info.value_names.size(); i++) { + SmallPair *data = info.value_names.data() + i; this->value_names.Insert(data->first, DuplicateGRFText(data->second)); } } @@ -272,8 +274,8 @@ GRFParameterInfo::~GRFParameterInfo() { CleanUpGRFText(this->name); CleanUpGRFText(this->desc); - for (uint i = 0; i < this->value_names.Length(); i++) { - SmallPair *data = this->value_names.Get(i); + for (uint i = 0; i < this->value_names.size(); i++) { + SmallPair *data = this->value_names.data() + i; CleanUpGRFText(data->second); } } @@ -329,9 +331,9 @@ void GRFParameterInfo::Finalize() */ bool UpdateNewGRFConfigPalette(int32 p1) { - for (GRFConfig *c = _grfconfig_newgame; c != NULL; c = c->next) c->SetSuitablePalette(); - for (GRFConfig *c = _grfconfig_static; c != NULL; c = c->next) c->SetSuitablePalette(); - for (GRFConfig *c = _all_grfs; c != NULL; c = c->next) c->SetSuitablePalette(); + for (GRFConfig *c = _grfconfig_newgame; c != nullptr; c = c->next) c->SetSuitablePalette(); + for (GRFConfig *c = _grfconfig_static; c != nullptr; c = c->next) c->SetSuitablePalette(); + for (GRFConfig *c = _all_grfs; c != nullptr; c = c->next) c->SetSuitablePalette(); return true; } @@ -379,7 +381,7 @@ static bool CalcGRFMD5Sum(GRFConfig *config, Subdirectory subdir) /* open the file */ f = FioFOpenFile(config->filename, "rb", subdir, &size); - if (f == NULL) return false; + if (f == nullptr) return false; long start = ftell(f); size = min(size, GRFGetSizeOfDataSection(f)); @@ -439,16 +441,16 @@ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir) /** * Clear a GRF Config list, freeing all nodes. * @param config Start of the list. - * @post \a config is set to \c NULL. + * @post \a config is set to \c nullptr. */ void ClearGRFConfigList(GRFConfig **config) { GRFConfig *c, *next; - for (c = *config; c != NULL; c = next) { + for (c = *config; c != nullptr; c = next) { next = c->next; delete c; } - *config = NULL; + *config = nullptr; } @@ -463,7 +465,7 @@ GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_o { /* Clear destination as it will be overwritten */ ClearGRFConfigList(dst); - for (; src != NULL; src = src->next) { + for (; src != nullptr; src = src->next) { GRFConfig *c = new GRFConfig(*src); ClrBit(c->flags, GCF_INIT_ONLY); @@ -494,9 +496,9 @@ static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list) GRFConfig *prev; GRFConfig *cur; - if (list == NULL) return; + if (list == nullptr) return; - for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) { + for (prev = list, cur = list->next; cur != nullptr; prev = cur, cur = cur->next) { if (cur->ident.grfid != list->ident.grfid) continue; prev->next = cur->next; @@ -514,7 +516,7 @@ static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list) void AppendStaticGRFConfigs(GRFConfig **dst) { GRFConfig **tail = dst; - while (*tail != NULL) tail = &(*tail)->next; + while (*tail != nullptr) tail = &(*tail)->next; CopyGRFConfigList(tail, _grfconfig_static, false); RemoveDuplicatesFromGRFConfigList(*dst); @@ -528,7 +530,7 @@ void AppendStaticGRFConfigs(GRFConfig **dst) void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el) { GRFConfig **tail = dst; - while (*tail != NULL) tail = &(*tail)->next; + while (*tail != nullptr) tail = &(*tail)->next; *tail = el; RemoveDuplicatesFromGRFConfigList(*dst); @@ -558,15 +560,15 @@ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig) { GRFListCompatibility res = GLC_ALL_GOOD; - for (GRFConfig *c = grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = grfconfig; c != nullptr; c = c->next) { const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum); - if (f == NULL || HasBit(f->flags, GCF_INVALID)) { + if (f == nullptr || HasBit(f->flags, GCF_INVALID)) { char buf[256]; /* If we have not found the exactly matching GRF try to find one with the * same grfid, as it most likely is compatible */ - f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, NULL, c->version); - if (f != NULL) { + f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, nullptr, c->version); + if (f != nullptr) { md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, buf); if (!HasBit(c->flags, GCF_COMPATIBLE)) { @@ -604,16 +606,16 @@ compatible_grf: c->info->Release(); c->info = f->name; c->info->AddRef(); - c->error = NULL; + c->error = nullptr; c->version = f->version; c->min_loadable_version = f->min_loadable_version; c->num_valid_params = f->num_valid_params; c->has_param_defaults = f->has_param_defaults; - for (uint i = 0; i < f->param_info.Length(); i++) { - if (f->param_info[i] == NULL) { - *c->param_info.Append() = NULL; + for (uint i = 0; i < f->param_info.size(); i++) { + if (f->param_info[i] == nullptr) { + c->param_info.push_back(nullptr); } else { - *c->param_info.Append() = new GRFParameterInfo(*f->param_info[i]); + c->param_info.push_back(new GRFParameterInfo(*f->param_info[i])); } } } @@ -633,7 +635,7 @@ public: { } - /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; /** Do the scan for GRFs. */ static uint DoScan() @@ -653,14 +655,14 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const bool added = true; if (FillGRFDetails(c, false)) { - if (_all_grfs == NULL) { + if (_all_grfs == nullptr) { _all_grfs = c; } else { /* Insert file into list at a position determined by its * name, so the list is sorted as we go along */ GRFConfig **pd, *d; bool stop = false; - for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) { + for (pd = &_all_grfs; (d = *pd) != nullptr; pd = &d->next) { if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false; /* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name, * before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of @@ -682,18 +684,18 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const this->num_scanned++; if (this->next_update <= _realtime_tick) { - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.lock(); - const char *name = NULL; - if (c->name != NULL) name = GetGRFStringFromGRFText(c->name->text); - if (name == NULL) name = c->filename; + const char *name = nullptr; + if (c->name != nullptr) name = GetGRFStringFromGRFText(c->name->text); + if (name == nullptr) name = c->filename; UpdateNewGRFScanStatus(this->num_scanned, name); - _modal_progress_work_mutex->BeginCritical(); - _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex.lock(); + _modal_progress_paint_mutex.unlock(); - this->next_update = _realtime_tick + 200; + this->next_update = _realtime_tick + MODAL_PROGRESS_REDRAW_TIMEOUT; } if (!added) { @@ -707,25 +709,22 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const /** * Simple sorter for GRFS - * @param p1 the first GRFConfig * - * @param p2 the second GRFConfig * - * @return the same strcmp would return for the name of the NewGRF. + * @param c1 the first GRFConfig * + * @param c2 the second GRFConfig * + * @return true if the name of first NewGRF is before the name of the second. */ -static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2) +static bool GRFSorter(GRFConfig * const &c1, GRFConfig * const &c2) { - const GRFConfig *c1 = *p1; - const GRFConfig *c2 = *p2; - - return strnatcmp(c1->GetName(), c2->GetName()); + return strnatcmp(c1->GetName(), c2->GetName()) < 0; } /** * Really perform the scan for all NewGRFs. * @param callback The callback to call after the scanning is complete. */ -void DoScanNewGRFFiles(void *callback) +void DoScanNewGRFFiles(NewGRFScanCallback *callback) { - _modal_progress_work_mutex->BeginCritical(); + std::unique_lock lock_work(_modal_progress_work_mutex); ClearGRFConfigList(&_all_grfs); TarScanner::DoScan(TarScanner::NEWGRF); @@ -734,46 +733,41 @@ void DoScanNewGRFFiles(void *callback) uint num = GRFFileScanner::DoScan(); DEBUG(grf, 1, "Scan complete, found %d files", num); - if (num != 0 && _all_grfs != NULL) { + if (num != 0 && _all_grfs != nullptr) { /* Sort the linked list using quicksort. * For that we first have to make an array, then sort and * then remake the linked list. */ - GRFConfig **to_sort = MallocT(num); + std::vector to_sort; uint i = 0; - for (GRFConfig *p = _all_grfs; p != NULL; p = p->next, i++) { - to_sort[i] = p; + for (GRFConfig *p = _all_grfs; p != nullptr; p = p->next, i++) { + to_sort.push_back(p); } /* Number of files is not necessarily right */ num = i; - QSortT(to_sort, num, &GRFSorter); + std::sort(to_sort.begin(), to_sort.end(), GRFSorter); for (i = 1; i < num; i++) { to_sort[i - 1]->next = to_sort[i]; } - to_sort[num - 1]->next = NULL; + to_sort[num - 1]->next = nullptr; _all_grfs = to_sort[0]; - free(to_sort); - -#ifdef ENABLE_NETWORK NetworkAfterNewGRFScan(); -#endif } - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->BeginCritical(); + lock_work.unlock(); + std::lock_guard lock_paint(_modal_progress_paint_mutex); /* Yes... these are the NewGRF windows */ InvalidateWindowClassesData(WC_SAVELOAD, 0, true); InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true); - if (callback != NULL) ((NewGRFScanCallback*)callback)->OnNewGRFsScanned(); + if (callback != nullptr) callback->OnNewGRFsScanned(); DeleteWindowByClass(WC_MODAL_PROGRESS); SetModalProgress(false); MarkWholeScreenDirty(); - _modal_progress_paint_mutex->EndCritical(); } /** @@ -787,14 +781,14 @@ void ScanNewGRFFiles(NewGRFScanCallback *callback) /* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */ MarkWholeScreenDirty(); - if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&DoScanNewGRFFiles, callback, NULL, "ottd:newgrf-scan")) { - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->EndCritical(); + if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(nullptr, "ottd:newgrf-scan", &DoScanNewGRFFiles, (NewGRFScanCallback *)callback)) { // Without the seemingly superfluous cast, strange compiler errors ensue. + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.unlock(); DoScanNewGRFFiles(callback); - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); + _modal_progress_paint_mutex.lock(); + _modal_progress_work_mutex.lock(); } else { - UpdateNewGRFScanStatus(0, NULL); + UpdateNewGRFScanStatus(0, nullptr); } } @@ -804,30 +798,28 @@ void ScanNewGRFFiles(NewGRFScanCallback *callback) * @param mode Restrictions for matching grfs * @param md5sum Expected MD5 sum * @param desired_version Requested version - * @return The matching grf, if it exists in #_all_grfs, else \c NULL. + * @return The matching grf, if it exists in #_all_grfs, else \c nullptr. */ const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum, uint32 desired_version) { - assert((mode == FGCM_EXACT) != (md5sum == NULL)); - const GRFConfig *best = NULL; - for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) { + assert((mode == FGCM_EXACT) != (md5sum == nullptr)); + const GRFConfig *best = nullptr; + for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) { /* if md5sum is set, we look for an exact match and continue if not found */ if (!c->ident.HasGrfIdentifier(grfid, md5sum)) continue; /* return it, if the exact same newgrf is found, or if we do not care about finding "the best" */ - if (md5sum != NULL || mode == FGCM_ANY) return c; + if (md5sum != nullptr || mode == FGCM_ANY) return c; /* Skip incompatible stuff, unless explicitly allowed */ if (mode != FGCM_NEWEST && HasBit(c->flags, GCF_INVALID)) continue; /* check version compatibility */ if (mode == FGCM_COMPATIBLE && (c->version < desired_version || c->min_loadable_version > desired_version)) continue; /* remember the newest one as "the best" */ - if (best == NULL || c->version > best->version) best = c; + if (best == nullptr || c->version > best->version) best = c; } return best; } -#ifdef ENABLE_NETWORK - /** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */ struct UnknownGRF : public GRFIdentifier { UnknownGRF *next; ///< The next unknown GRF. @@ -848,21 +840,21 @@ struct UnknownGRF : public GRFIdentifier { * @param create whether to create a new GRFConfig if the GRFConfig did not * exist in the fake list of GRFConfigs. * @return The GRFTextWrapper of the name of the GRFConfig with the given GRF ID - * and MD5 checksum or NULL when it does not exist and create is false. + * and MD5 checksum or nullptr when it does not exist and create is false. * This value must NEVER be freed by the caller. */ GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) { UnknownGRF *grf; - static UnknownGRF *unknown_grfs = NULL; + static UnknownGRF *unknown_grfs = nullptr; - for (grf = unknown_grfs; grf != NULL; grf = grf->next) { + for (grf = unknown_grfs; grf != nullptr; grf = grf->next) { if (grf->grfid == grfid) { if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name; } } - if (!create) return NULL; + if (!create) return nullptr; grf = CallocT(1); grf->grfid = grfid; @@ -877,24 +869,21 @@ GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) return grf->name; } -#endif /* ENABLE_NETWORK */ - - /** * Retrieve a NewGRF from the current config by its grfid. * @param grfid grf to look for. * @param mask GRFID mask to allow for partial matching. - * @return The grf config, if it exists, else \c NULL. + * @return The grf config, if it exists, else \c nullptr. */ GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask) { GRFConfig *c; - for (c = _grfconfig; c != NULL; c = c->next) { + for (c = _grfconfig; c != nullptr; c = c->next) { if ((c->ident.grfid & mask) == (grfid & mask)) return c; } - return NULL; + return nullptr; } @@ -919,7 +908,7 @@ static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400); /** * Search a textfile file next to this NewGRF. * @param type The type of the textfile to search for. - * @return The filename for the textfile, \c NULL otherwise. + * @return The filename for the textfile, \c nullptr otherwise. */ const char *GRFConfig::GetTextfile(TextfileType type) const { diff --git a/src/newgrf_config.h b/src/newgrf_config.h index dc3b884dd3..feee2dbad3 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -88,13 +88,13 @@ struct GRFIdentifier { /** * Does the identification match the provided values? * @param grfid Expected grfid. - * @param md5sum Expected md5sum, may be \c NULL (in which case, do not check it). + * @param md5sum Expected md5sum, may be \c nullptr (in which case, do not check it). * @return the object has the provided grfid and md5sum. */ inline bool HasGrfIdentifier(uint32 grfid, const uint8 *md5sum) const { if (this->grfid != grfid) return false; - if (md5sum == NULL) return true; + if (md5sum == nullptr) return true; return memcmp(md5sum, this->md5sum, sizeof(this->md5sum)) == 0; } }; @@ -133,7 +133,7 @@ struct GRFParameterInfo { byte param_nr; ///< GRF parameter to store content in byte first_bit; ///< First bit to use in the GRF parameter byte num_bit; ///< Number of bits to use for this parameter - SmallMap value_names; ///< Names for each value. + SmallMap value_names; ///< Names for each value. bool complete_labels; ///< True if all values have a label. uint32 GetValue(struct GRFConfig *config) const; @@ -151,31 +151,31 @@ struct GRFTextWrapper : public SimpleCountedObject { /** Information about GRF, used in the game and (part of it) in savegames */ struct GRFConfig : ZeroedMemoryAllocator { - GRFConfig(const char *filename = NULL); + GRFConfig(const char *filename = nullptr); GRFConfig(const GRFConfig &config); ~GRFConfig(); - GRFIdentifier ident; ///< grfid and md5sum to uniquely identify newgrfs - uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded - char *filename; ///< Filename - either with or without full path - GRFTextWrapper *name; ///< NOSAVE: GRF name (Action 0x08) - GRFTextWrapper *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) - GRFTextWrapper *url; ///< NOSAVE: URL belonging to this GRF. - GRFError *error; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B) + GRFIdentifier ident; ///< grfid and md5sum to uniquely identify newgrfs + uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded + char *filename; ///< Filename - either with or without full path + GRFTextWrapper *name; ///< NOSAVE: GRF name (Action 0x08) + GRFTextWrapper *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) + GRFTextWrapper *url; ///< NOSAVE: URL belonging to this GRF. + GRFError *error; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B) - uint32 version; ///< NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown - uint32 min_loadable_version; ///< NOSAVE: Minimum compatible version a NewGRF can define - uint8 flags; ///< NOSAVE: GCF_Flags, bitset - GRFStatus status; ///< NOSAVE: GRFStatus, enum - uint32 grf_bugs; ///< NOSAVE: bugs in this GRF in this run, @see enum GRFBugs - uint32 param[0x80]; ///< GRF parameters - uint8 num_params; ///< Number of used parameters - uint8 num_valid_params; ///< NOSAVE: Number of valid parameters (action 0x14) - uint8 palette; ///< GRFPalette, bitset - SmallVector param_info; ///< NOSAVE: extra information about the parameters - bool has_param_defaults; ///< NOSAVE: did this newgrf specify any defaults for it's parameters + uint32 version; ///< NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown + uint32 min_loadable_version; ///< NOSAVE: Minimum compatible version a NewGRF can define + uint8 flags; ///< NOSAVE: GCF_Flags, bitset + GRFStatus status; ///< NOSAVE: GRFStatus, enum + uint32 grf_bugs; ///< NOSAVE: bugs in this GRF in this run, @see enum GRFBugs + uint32 param[0x80]; ///< GRF parameters + uint8 num_params; ///< Number of used parameters + uint8 num_valid_params; ///< NOSAVE: Number of valid parameters (action 0x14) + uint8 palette; ///< GRFPalette, bitset + std::vector param_info; ///< NOSAVE: extra information about the parameters + bool has_param_defaults; ///< NOSAVE: did this newgrf specify any defaults for it's parameters - struct GRFConfig *next; ///< NOSAVE: Next item in the linked list + struct GRFConfig *next; ///< NOSAVE: Next item in the linked list void CopyParams(const GRFConfig &src); @@ -215,7 +215,7 @@ struct NewGRFScanCallback { size_t GRFGetSizeOfDataSection(FILE *f); void ScanNewGRFFiles(NewGRFScanCallback *callback); -const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum = NULL, uint32 desired_version = 0); +const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum = nullptr, uint32 desired_version = 0); GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask = 0xFFFFFFFF); GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only); void AppendStaticGRFConfigs(GRFConfig **dst); @@ -229,11 +229,9 @@ char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last); /* In newgrf_gui.cpp */ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config); -#ifdef ENABLE_NETWORK /** For communication about GRFs over the network */ #define UNKNOWN_GRF_NAME_PLACEHOLDER "" GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); -#endif /* ENABLE_NETWORK */ void UpdateNewGRFScanStatus(uint num, const char *name); bool UpdateNewGRFConfigPalette(int32 p1 = 0); diff --git a/src/newgrf_debug.h b/src/newgrf_debug.h index 6e514c4ce1..dac97726da 100644 --- a/src/newgrf_debug.h +++ b/src/newgrf_debug.h @@ -29,7 +29,7 @@ struct NewGrfDebugSpritePicker { NewGrfDebugSpritePickerMode mode; ///< Current state void *clicked_pixel; ///< Clicked pixel (pointer to blitter buffer) uint32 click_time; ///< Realtime tick when clicked to detect next frame - SmallVector sprites; ///< Sprites found + std::vector sprites; ///< Sprites found }; extern NewGrfDebugSpritePicker _newgrf_debug_sprite_picker; diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index e462695092..302f145560 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -47,7 +47,7 @@ #include "safeguards.h" /** The sprite picker. */ -NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector() }; +NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, nullptr, 0, std::vector() }; /** * Get the feature index related to the window number. @@ -192,11 +192,11 @@ public: * Gets the first position of the array containing the persistent storage. * @param index Index of the item. * @param grfid Parameter for the PSA. Only required for items with parameters. - * @return Pointer to the first position of the storage array or NULL if not present. + * @return Pointer to the first position of the storage array or nullptr if not present. */ virtual const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const { - return NULL; + return nullptr; } protected: @@ -252,18 +252,18 @@ static inline GrfSpecFeature GetFeatureNum(uint window_number) /** * Get the NIFeature related to the window number. * @param window_number The window to get the NIFeature for. - * @return the NIFeature, or NULL is there isn't one. + * @return the NIFeature, or nullptr is there isn't one. */ static inline const NIFeature *GetFeature(uint window_number) { GrfSpecFeature idx = GetFeatureNum(window_number); - return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL; + return idx < GSF_FAKE_END ? _nifeatures[idx] : nullptr; } /** * Get the NIHelper related to the window number. * @param window_number The window to get the NIHelper for. - * @pre GetFeature(window_number) != NULL + * @pre GetFeature(window_number) != nullptr * @return the NIHelper */ static inline const NIHelper *GetFeatureHelper(uint window_number) @@ -332,7 +332,7 @@ struct NewGRFInspectWindow : Window { assert(this->HasChainIndex()); const Vehicle *v = Vehicle::Get(index); v = v->Move(this->chain_index); - if (v != NULL) index = v->index; + if (v != nullptr) index = v->index; } return index; } @@ -348,7 +348,7 @@ struct NewGRFInspectWindow : Window { const Vehicle *v = Vehicle::Get(::GetFeatureIndex(this->window_number)); v = v->Move(this->chain_index); - if (v == NULL) this->chain_index = 0; + if (v == nullptr) this->chain_index = 0; } NewGRFInspectWindow(WindowDesc *desc, WindowNumber wno) : Window(desc) @@ -363,14 +363,14 @@ struct NewGRFInspectWindow : Window { this->OnInvalidateData(0, true); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget != WID_NGRFI_CAPTION) return; GetFeatureHelper(this->window_number)->SetStringParameters(this->GetFeatureIndex()); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NGRFI_VEH_CHAIN: { @@ -410,7 +410,7 @@ struct NewGRFInspectWindow : Window { ::DrawString(r.left + LEFT_OFFSET, r.right - RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_NGRFI_VEH_CHAIN: { @@ -418,7 +418,7 @@ struct NewGRFInspectWindow : Window { int total_width = 0; int sel_start = 0; int sel_end = 0; - for (const Vehicle *u = v->First(); u != NULL; u = u->Next()) { + for (const Vehicle *u = v->First(); u != nullptr; u = u->Next()) { if (u == v) sel_start = total_width; switch (u->type) { case VEH_TRAIN: total_width += Train ::From(u)->GetDisplayImageWidth(); break; @@ -460,9 +460,9 @@ struct NewGRFInspectWindow : Window { uint i = 0; this->DrawString(r, i++, "Industry type: %d", (int)((const Industry *)base)->type); - if (nif->variables != NULL) { + if (nif->variables != nullptr) { this->DrawString(r, i++, "Variables:"); - for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) { + for (const NIVariable *niv = nif->variables; niv->name != nullptr; niv++) { bool avail = true; uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0; uint value = nih->Resolve(index, niv->var, param, &avail); @@ -479,7 +479,7 @@ struct NewGRFInspectWindow : Window { uint psa_size = nih->GetPSASize(index, this->caller_grfid); const int32 *psa = nih->GetPSAFirstPosition(index, this->caller_grfid); - if (psa_size != 0 && psa != NULL) { + if (psa_size != 0 && psa != nullptr) { if (nih->PSAWithParameter()) { this->DrawString(r, i++, "Persistent storage [%08X]:", BSWAP32(this->caller_grfid)); } else { @@ -491,9 +491,9 @@ struct NewGRFInspectWindow : Window { } } - if (nif->properties != NULL) { + if (nif->properties != nullptr) { this->DrawString(r, i++, "Properties:"); - for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) { + for (const NIProperty *nip = nif->properties; nip->name != nullptr; nip++) { const void *ptr = (const byte *)base + nip->offset; uint value; switch (nip->read_size) { @@ -524,9 +524,9 @@ struct NewGRFInspectWindow : Window { } } - if (nif->callbacks != NULL) { + if (nif->callbacks != nullptr) { this->DrawString(r, i++, "Callbacks:"); - for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) { + for (const NICallback *nic = nif->callbacks; nic->name != nullptr; nic++) { if (nic->cb_bit != CBM_NO_BIT) { const void *ptr = (const byte *)base_spec + nic->offset; uint value; @@ -551,7 +551,7 @@ struct NewGRFInspectWindow : Window { const_cast(this)->vscroll->SetCount(i); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NGRFI_PARENT: { @@ -572,7 +572,7 @@ struct NewGRFInspectWindow : Window { if (this->HasChainIndex()) { uint index = this->GetFeatureIndex(); Vehicle *v = Vehicle::Get(index); - if (v != NULL && v->Next() != NULL) { + if (v != nullptr && v->Next() != nullptr) { this->chain_index++; this->InvalidateData(); } @@ -582,14 +582,14 @@ struct NewGRFInspectWindow : Window { case WID_NGRFI_MAINPANEL: { /* Does this feature have variables? */ const NIFeature *nif = GetFeature(this->window_number); - if (nif->variables == NULL) return; + if (nif->variables == nullptr) return; /* Get the line, make sure it's within the boundaries. */ int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, TOP_OFFSET); if (line == INT_MAX) return; /* Find the variable related to the line */ - for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) { + for (const NIVariable *niv = nif->variables; niv->name != nullptr; niv++, line--) { if (line != 1) continue; // 1 because of the "Variables:" line if (!HasVariableParameter(niv->var)) break; @@ -601,15 +601,15 @@ struct NewGRFInspectWindow : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (StrEmpty(str)) return; - NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16); + NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, nullptr, 16); this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET); } @@ -619,14 +619,14 @@ struct NewGRFInspectWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (this->HasChainIndex()) { this->ValidateChainIndex(); this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0); Vehicle *v = Vehicle::Get(this->GetFeatureIndex()); - this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == NULL || v->Next() == NULL); + this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == nullptr || v->Next() == nullptr); } } }; @@ -757,7 +757,7 @@ void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index) bool IsNewGRFInspectable(GrfSpecFeature feature, uint index) { const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index)); - if (nif == NULL) return false; + if (nif == nullptr) return false; return nif->helper->IsInspectable(index); } @@ -823,7 +823,7 @@ struct SpriteAlignerWindow : Window { while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL); switch (widget) { @@ -841,8 +841,8 @@ struct SpriteAlignerWindow : Window { /* Relative offset is new absolute offset - starting absolute offset. * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet). */ - const SmallPair *key_offs_pair = this->offs_start_map.Find(this->current_sprite); - if (key_offs_pair != this->offs_start_map.End()) { + const auto key_offs_pair = this->offs_start_map.Find(this->current_sprite); + if (key_offs_pair != this->offs_start_map.end()) { SetDParam(0, spr->x_offs - key_offs_pair->second.first); SetDParam(1, spr->y_offs - key_offs_pair->second.second); } else { @@ -857,7 +857,7 @@ struct SpriteAlignerWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_SA_LIST) return; @@ -868,7 +868,7 @@ struct SpriteAlignerWindow : Window { size->height = (1 + 200 / resize->height) * resize->height; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SA_SPRITE: { @@ -884,7 +884,7 @@ struct SpriteAlignerWindow : Window { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &new_dpi; - DrawSprite(this->current_sprite, PAL_NONE, x, y, NULL, ZOOM_LVL_GUI); + DrawSprite(this->current_sprite, PAL_NONE, x, y, nullptr, ZOOM_LVL_GUI); _cur_dpi = old_dpi; @@ -895,8 +895,8 @@ struct SpriteAlignerWindow : Window { const NWidgetBase *nwid = this->GetWidget(widget); int step_size = nwid->resize_y; - SmallVector &list = _newgrf_debug_sprite_picker.sprites; - int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length()); + std::vector &list = _newgrf_debug_sprite_picker.sprites; + int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)list.size()); int y = r.top + WD_FRAMERECT_TOP; for (int i = this->vscroll->GetPosition(); i < max; i++) { @@ -909,7 +909,7 @@ struct SpriteAlignerWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SA_PREVIOUS: @@ -941,7 +941,7 @@ struct SpriteAlignerWindow : Window { int step_size = nwid->resize_y; uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size; - if (i < _newgrf_debug_sprite_picker.sprites.Length()) { + if (i < _newgrf_debug_sprite_picker.sprites.size()) { SpriteID spr = _newgrf_debug_sprite_picker.sprites[i]; if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr; } @@ -973,7 +973,7 @@ struct SpriteAlignerWindow : Window { this->offs_start_map.Insert(this->current_sprite, XyOffs(spr->x_offs, spr->y_offs)); } switch (widget) { - /* Move ten units at a time if ctrl is pressed. */ + /* Move eight units at a time if ctrl is pressed. */ case WID_SA_UP: spr->y_offs -= _ctrl_pressed ? 8 : 1; break; case WID_SA_DOWN: spr->y_offs += _ctrl_pressed ? 8 : 1; break; case WID_SA_LEFT: spr->x_offs -= _ctrl_pressed ? 8 : 1; break; @@ -993,7 +993,7 @@ struct SpriteAlignerWindow : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (StrEmpty(str)) return; @@ -1010,17 +1010,17 @@ struct SpriteAlignerWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (data == 1) { /* Sprite picker finished */ this->RaiseWidget(WID_SA_PICKER); - this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length()); + this->vscroll->SetCount((uint)_newgrf_debug_sprite_picker.sprites.size()); } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST); } diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 660b7e476b..184cb19473 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -23,6 +23,7 @@ #include "station_base.h" #include "company_base.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "ship.h" #include "safeguards.h" @@ -65,7 +66,7 @@ const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, Eng if (wo->train_id[j] == overriding_engine) return wo->group; } } - return NULL; + return nullptr; } /** @@ -79,7 +80,7 @@ void UnloadWagonOverrides(Engine *e) } free(e->overrides); e->overrides_count = 0; - e->overrides = NULL; + e->overrides = nullptr; } @@ -88,7 +89,7 @@ void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *grou Engine *e = Engine::Get(engine); assert(cargo < lengthof(e->grf_prop.spritegroup)); - if (e->grf_prop.spritegroup[cargo] != NULL) { + if (e->grf_prop.spritegroup[cargo] != nullptr) { grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine, cargo); } e->grf_prop.spritegroup[cargo] = group; @@ -166,7 +167,7 @@ enum TTDPAircraftMovementStates { static byte MapAircraftMovementState(const Aircraft *v) { const Station *st = GetTargetAirportIfValid(v); - if (st == NULL) return AMS_TTDP_FLIGHT_TO_TOWER; + if (st == nullptr) return AMS_TTDP_FLIGHT_TO_TOWER; const AirportFTAClass *afc = st->airport.GetFTA(); uint16 amdflag = afc->MovingData(v->pos)->flag; @@ -247,7 +248,7 @@ static byte MapAircraftMovementState(const Aircraft *v) return AMS_TTDP_TO_INWAY; case HELILANDING: - case HELIENDLANDING: // Helicoptor is decending. + case HELIENDLANDING: // Helicoptor is descending. if (amdflag & AMED_HELI_LOWER) { return afc->delta_z == 0 ? AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT; @@ -339,12 +340,12 @@ static byte MapAircraftMovementAction(const Aircraft *v) /* virtual */ uint32 VehicleScopeResolver::GetRandomBits() const { - return this->v == NULL ? 0 : this->v->random_bits; + return this->v == nullptr ? 0 : this->v->random_bits; } /* virtual */ uint32 VehicleScopeResolver::GetTriggers() const { - return this->v == NULL ? 0 : this->v->waiting_triggers; + return this->v == nullptr ? 0 : this->v->waiting_triggers; } @@ -355,12 +356,12 @@ static byte MapAircraftMovementAction(const Aircraft *v) case VSG_SCOPE_PARENT: return &this->parent_scope; case VSG_SCOPE_RELATIVE: { int32 count = GB(relative, 0, 4); - if (this->self_scope.v != NULL && (relative != this->cached_relative_count || count == 0)) { + if (this->self_scope.v != nullptr && (relative != this->cached_relative_count || count == 0)) { /* Note: This caching only works as long as the VSG_SCOPE_RELATIVE cannot be used in * VarAct2 with procedure calls. */ if (count == 0) count = GetRegister(0x100); - const Vehicle *v = NULL; + const Vehicle *v = nullptr; switch (GB(relative, 6, 2)) { default: NOT_REACHED(); case 0x00: // count back (away from the engine), starting at this vehicle @@ -377,12 +378,12 @@ static byte MapAircraftMovementAction(const Aircraft *v) const Vehicle *self = this->self_scope.v; for (const Vehicle *u = self->First(); u != self; u = u->Next()) { if (u->engine_type != self->engine_type) { - v = NULL; + v = nullptr; } else { - if (v == NULL) v = u; + if (v == nullptr) v = u; } } - if (v == NULL) v = self; + if (v == nullptr) v = self; break; } } @@ -400,16 +401,16 @@ static byte MapAircraftMovementAction(const Aircraft *v) * This always uses dual company colours independent of GUI settings. So it is desync-safe. * * @param engine Engine type - * @param v Vehicle, NULL in purchase list. + * @param v Vehicle, nullptr in purchase list. * @return Livery to use */ static const Livery *LiveryHelper(EngineID engine, const Vehicle *v) { const Livery *l; - if (v == NULL) { - if (!Company::IsValidID(_current_company)) return NULL; - l = GetEngineLivery(engine, _current_company, INVALID_ENGINE, NULL, LIT_ALL); + if (v == nullptr) { + if (!Company::IsValidID(_current_company)) return nullptr; + l = GetEngineLivery(engine, _current_company, INVALID_ENGINE, nullptr, LIT_ALL); } else if (v->IsGroundVehicle()) { l = GetEngineLivery(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v, LIT_ALL); } else { @@ -437,7 +438,7 @@ static uint32 PositionHelper(const Vehicle *v, bool consecutive) if (consecutive && u->engine_type != v->engine_type) chain_before = 0; } - while (u->Next() != NULL && (!consecutive || u->Next()->engine_type == v->engine_type)) { + while (u->Next() != nullptr && (!consecutive || u->Next()->engine_type == v->engine_type)) { chain_after++; u = u->Next(); } @@ -480,7 +481,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, memset(common_cargoes, 0, sizeof(common_cargoes)); memset(common_subtypes, 0, sizeof(common_subtypes)); - for (u = v; u != NULL; u = u->Next()) { + for (u = v; u != nullptr; u = u->Next()) { if (v->type == VEH_TRAIN) user_def_data |= Train::From(u)->tcache.user_def_data; /* Skip empty engines */ @@ -500,7 +501,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, } /* Count subcargo types of common_cargo_type */ - for (u = v; u != NULL; u = u->Next()) { + for (u = v; u != nullptr; u = u->Next()) { /* Skip empty engines and engines not carrying common_cargo_type */ if (u->cargo_type != common_cargo_type || !u->GetEngine()->CanCarryCargo()) continue; @@ -530,12 +531,12 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, * - For translating the cargo type we need to use the GRF which is resolving the variable, which * is object->ro.grffile. * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF(). - * - The grffile == NULL case only happens if this function is called for default vehicles. + * - The grffile == nullptr case only happens if this function is called for default vehicles. * And this is only done by CheckCaches(). */ const GRFFile *grffile = object->ro.grffile; uint8 common_bitnum = (common_cargo_type == CT_INVALID) ? 0xFF : - (grffile == NULL || grffile->grf_version < 8) ? CargoSpec::Get(common_cargo_type)->bitnum : grffile->cargo_map[common_cargo_type]; + (grffile == nullptr || grffile->grf_version < 8) ? CargoSpec::Get(common_cargo_type)->bitnum : grffile->cargo_map[common_cargo_type]; return (v->grf_cache.consist_cargo_information & 0xFFFF00FF) | common_bitnum << 8; } @@ -557,7 +558,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, const Station *st = GetTargetAirportIfValid(Aircraft::From(v)); - if (st != NULL && st->airport.tile != INVALID_TILE) { + if (st != nullptr && st->airport.tile != INVALID_TILE) { airporttype = st->airport.GetSpec()->ttd_airport_type; } @@ -574,8 +575,8 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, const Vehicle *u_p = v->Previous(); const Vehicle *u_n = v->Next(); - DirDiff f = (u_p == NULL) ? DIRDIFF_SAME : DirDifference(u_p->direction, v->direction); - DirDiff b = (u_n == NULL) ? DIRDIFF_SAME : DirDifference(v->direction, u_n->direction); + DirDiff f = (u_p == nullptr) ? DIRDIFF_SAME : DirDifference(u_p->direction, v->direction); + DirDiff b = (u_n == nullptr) ? DIRDIFF_SAME : DirDifference(v->direction, u_n->direction); DirDiff t = ChangeDirDiff(f, b); return ((t > DIRDIFF_REVERSE ? t | 8 : t) << 16) | @@ -606,11 +607,21 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, case 0x48: return v->GetEngine()->flags; // Vehicle Type Info case 0x49: return v->build_year; - case 0x4A: { - if (v->type != VEH_TRAIN) return 0; - RailType rt = GetTileRailType(v->tile); - return (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt, object->ro.grffile); - } + case 0x4A: + switch (v->type) { + case VEH_TRAIN: { + RailType rt = GetTileRailType(v->tile); + return (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt, object->ro.grffile); + } + + case VEH_ROAD: { + RoadType rt = GetRoadType(v->tile, GetRoadTramType(RoadVehicle::From(v)->roadtype)); + return 0x100 | GetReverseRoadTypeTranslation(rt, object->ro.grffile); + } + + default: + return 0; + } case 0x4B: // Long date of last service return v->date_of_last_service; @@ -636,7 +647,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, { uint count = 0; - for (; v != NULL; v = v->Next()) { + for (; v != nullptr; v = v->Next()) { if (v->GetEngine()->grf_prop.local_id == parameter) count++; } return count; @@ -653,7 +664,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, object->ro.callback == CBID_VEHICLE_START_STOP_CHECK || object->ro.callback == CBID_VEHICLE_32DAY_CALLBACK || object->ro.callback == CBID_VEHICLE_COLOUR_MAPPING || object->ro.callback == CBID_VEHICLE_SPAWN_VISUAL_EFFECT) { Vehicle *u = v->Move((int32)GetRegister(0x10F)); - if (u == NULL) return 0; // available, but zero + if (u == nullptr) return 0; // available, but zero if (parameter == 0x5F) { /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */ @@ -676,7 +687,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, if (!v->IsGroundVehicle()) return 0; const Vehicle *u = v->Move((int8)parameter); - if (u == NULL) return 0; + if (u == nullptr) return 0; /* Get direction difference. */ bool prev = (int8)parameter < 0; @@ -810,7 +821,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, case 0x57: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 8, 24); case 0x58: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 16, 16); case 0x59: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 24, 8); - case 0x5A: return v->Next() == NULL ? INVALID_VEHICLE : v->Next()->index; + case 0x5A: return v->Next() == nullptr ? INVALID_VEHICLE : v->Next()->index; case 0x5C: return ClampToI32(v->value); case 0x5D: return GB(ClampToI32(v->value), 8, 24); case 0x5E: return GB(ClampToI32(v->value), 16, 16); @@ -882,10 +893,10 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, /* virtual */ uint32 VehicleScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { - if (this->v == NULL) { + if (this->v == nullptr) { /* Vehicle does not exist, so we're in a purchase list */ switch (variable) { - case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, NULL)); // Owner information + case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, nullptr)); // Owner information case 0x46: return 0; // Motion counter case 0x47: { // Vehicle cargo info const Engine *e = Engine::Get(this->self_type); @@ -919,17 +930,17 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, { const Vehicle *v = this->self_scope.v; - if (v == NULL) { + if (v == nullptr) { if (group->num_loading > 0) return group->loading[0]; if (group->num_loaded > 0) return group->loaded[0]; - return NULL; + return nullptr; } bool in_motion = !v->First()->current_order.IsType(OT_LOADING); uint totalsets = in_motion ? group->num_loaded : group->num_loading; - if (totalsets == 0) return NULL; + if (totalsets == 0) return nullptr; uint set = (v->cargo.StoredCount() * totalsets) / max((uint16)1, v->cargo_cap); set = min(set, totalsets - 1); @@ -945,7 +956,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, static const GRFFile *GetEngineGrfFile(EngineID engine_type) { const Engine *e = Engine::Get(engine_type); - return (e != NULL) ? e->GetGRF() : NULL; + return (e != nullptr) ? e->GetGRF() : nullptr; } /** @@ -962,14 +973,14 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(GetEngineGrfFile(engine_type), callback, callback_param1, callback_param2), self_scope(*this, engine_type, v, info_view), - parent_scope(*this, engine_type, ((v != NULL) ? v->First() : v), info_view), + parent_scope(*this, engine_type, ((v != nullptr) ? v->First() : v), info_view), relative_scope(*this, engine_type, v, info_view), cached_relative_count(0) { if (wagon_override == WO_SELF) { this->root_spritegroup = GetWagonOverrideSpriteSet(engine_type, CT_DEFAULT, engine_type); } else { - if (wagon_override != WO_NONE && v != NULL && v->IsGroundVehicle()) { + if (wagon_override != WO_NONE && v != nullptr && v->IsGroundVehicle()) { assert(v->engine_type == engine_type); // overrides make little sense with fake scopes /* For trains we always use cached value, except for callbacks because the override spriteset @@ -982,11 +993,11 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle } } - if (this->root_spritegroup == NULL) { + if (this->root_spritegroup == nullptr) { const Engine *e = Engine::Get(engine_type); - CargoID cargo = v != NULL ? v->cargo_type : CT_PURCHASE; + CargoID cargo = v != nullptr ? v->cargo_type : CT_PURCHASE; assert(cargo < lengthof(e->grf_prop.spritegroup)); - this->root_spritegroup = e->grf_prop.spritegroup[cargo] != NULL ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[CT_DEFAULT]; + this->root_spritegroup = e->grf_prop.spritegroup[cargo] != nullptr ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[CT_DEFAULT]; } } } @@ -1005,7 +1016,7 @@ void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction directio object.callback_param1 = image_type | (stack << 8); const SpriteGroup *group = object.Resolve(); uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0; - if (group != NULL && group->GetNumResults() != 0) { + if (group != nullptr && group->GetNumResults() != 0) { result->seq[result->count].sprite = group->GetResult() + (direction % group->GetNumResults()); result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring result->count++; @@ -1025,7 +1036,7 @@ void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK); result->Clear(); - uint rotor_pos = v == NULL || info_view ? 0 : v->Next()->Next()->state; + uint rotor_pos = v == nullptr || info_view ? 0 : v->Next()->Next()->state; bool sprite_stack = HasBit(e->info.misc_flags, EF_SPRITE_STACK); uint max_stack = sprite_stack ? lengthof(result->seq) : 1; @@ -1034,7 +1045,7 @@ void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info object.callback_param1 = image_type | (stack << 8); const SpriteGroup *group = object.Resolve(); uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0; - if (group != NULL && group->GetNumResults() != 0) { + if (group != nullptr && group->GetNumResults() != 0) { result->seq[result->count].sprite = group->GetResult() + (rotor_pos % group->GetNumResults()); result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring result->count++; @@ -1052,7 +1063,7 @@ void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info bool UsesWagonOverride(const Vehicle *v) { assert(v->type == VEH_TRAIN); - return Train::From(v)->tcache.cached_override != NULL; + return Train::From(v)->tcache.cached_override != nullptr; } /** @@ -1061,7 +1072,7 @@ bool UsesWagonOverride(const Vehicle *v) * @param param1 First parameter of the callback * @param param2 Second parameter of the callback * @param engine Engine type of the vehicle to evaluate the callback for - * @param v The vehicle to evaluate the callback for, or NULL if it doesnt exist yet + * @param v The vehicle to evaluate the callback for, or nullptr if it doesn't exist yet * @return The value the callback returned, or CALLBACK_FAILED if it failed */ uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v) @@ -1076,7 +1087,7 @@ uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, Eng * @param param1 First parameter of the callback * @param param2 Second parameter of the callback * @param engine Engine type of the vehicle to evaluate the callback for - * @param v The vehicle to evaluate the callback for, or NULL if it doesn't exist yet + * @param v The vehicle to evaluate the callback for, or nullptr if it doesn't exist yet * @param parent The vehicle to use for parent scope * @return The value the callback returned, or CALLBACK_FAILED if it failed */ @@ -1107,14 +1118,14 @@ uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, co static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_random_bits, bool first) { /* We can't trigger a non-existent vehicle... */ - assert(v != NULL); + assert(v != nullptr); VehicleResolverObject object(v->engine_type, v, VehicleResolverObject::WO_CACHED, false, CBID_RANDOM_TRIGGER); object.waiting_triggers = v->waiting_triggers | trigger; v->waiting_triggers = object.waiting_triggers; // store now for var 5F const SpriteGroup *group = object.Resolve(); - if (group == NULL) return; + if (group == nullptr) return; /* Store remaining triggers. */ v->waiting_triggers = object.GetRemainingTriggers(); @@ -1142,7 +1153,7 @@ static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_rando /* We now trigger the next vehicle in chain recursively. * The random bits portions may be different for each * vehicle in chain. */ - if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, 0, true); + if (v->Next() != nullptr) DoTriggerVehicle(v->Next(), trigger, 0, true); break; case VEHICLE_TRIGGER_EMPTY: @@ -1150,14 +1161,14 @@ static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_rando * recursively. The random bits portions must be same * for each vehicle in chain, so we give them all * first chained vehicle's portion of random bits. */ - if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, first ? new_random_bits : base_random_bits, false); + if (v->Next() != nullptr) DoTriggerVehicle(v->Next(), trigger, first ? new_random_bits : base_random_bits, false); break; case VEHICLE_TRIGGER_ANY_NEW_CARGO: /* Now pass the trigger recursively to the next vehicle * in chain. */ assert(!first); - if (v->Next() != NULL) DoTriggerVehicle(v->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false); + if (v->Next() != nullptr) DoTriggerVehicle(v->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false); break; case VEHICLE_TRIGGER_CALLBACK_32: @@ -1185,7 +1196,7 @@ struct ListOrderChange { uint target; ///< local ID }; -static SmallVector _list_order_changes; +static std::vector _list_order_changes; /** * Record a vehicle ListOrderChange. @@ -1196,9 +1207,7 @@ static SmallVector _list_order_changes; void AlterVehicleListOrder(EngineID engine, uint target) { /* Add the list order change to a queue */ - ListOrderChange *loc = _list_order_changes.Append(); - loc->engine = engine; - loc->target = target; + _list_order_changes.push_back({engine, target}); } /** @@ -1207,19 +1216,19 @@ void AlterVehicleListOrder(EngineID engine, uint target) * @param b right side * @return comparison result */ -static int CDECL EnginePreSort(const EngineID *a, const EngineID *b) +static bool EnginePreSort(const EngineID &a, const EngineID &b) { - const EngineIDMapping *id_a = _engine_mngr.Get(*a); - const EngineIDMapping *id_b = _engine_mngr.Get(*b); + const EngineIDMapping &id_a = _engine_mngr.at(a); + const EngineIDMapping &id_b = _engine_mngr.at(b); /* 1. Sort by engine type */ - if (id_a->type != id_b->type) return (int)id_a->type - (int)id_b->type; + if (id_a.type != id_b.type) return (int)id_a.type < (int)id_b.type; /* 2. Sort by scope-GRFID */ - if (id_a->grfid != id_b->grfid) return id_a->grfid < id_b->grfid ? -1 : 1; + if (id_a.grfid != id_b.grfid) return id_a.grfid < id_b.grfid; /* 3. Sort by local ID */ - return (int)id_a->internal_id - (int)id_b->internal_id; + return (int)id_a.internal_id < (int)id_b.internal_id; } /** @@ -1228,32 +1237,31 @@ static int CDECL EnginePreSort(const EngineID *a, const EngineID *b) void CommitVehicleListOrderChanges() { /* Pre-sort engines by scope-grfid and local index */ - SmallVector ordering; + std::vector ordering; Engine *e; FOR_ALL_ENGINES(e) { - *ordering.Append() = e->index; + ordering.push_back(e->index); } - QSortT(ordering.Begin(), ordering.Length(), EnginePreSort); + std::sort(ordering.begin(), ordering.end(), EnginePreSort); /* Apply Insertion-Sort operations */ - const ListOrderChange *end = _list_order_changes.End(); - for (const ListOrderChange *it = _list_order_changes.Begin(); it != end; ++it) { - EngineID source = it->engine; - uint local_target = it->target; + for (const ListOrderChange &it : _list_order_changes) { + EngineID source = it.engine; + uint local_target = it.target; - const EngineIDMapping *id_source = _engine_mngr.Get(source); + const EngineIDMapping *id_source = _engine_mngr.data() + source; if (id_source->internal_id == local_target) continue; EngineID target = _engine_mngr.GetID(id_source->type, local_target, id_source->grfid); if (target == INVALID_ENGINE) continue; - int source_index = ordering.FindIndex(source); - int target_index = ordering.FindIndex(target); + int source_index = find_index(ordering, source); + int target_index = find_index(ordering, target); assert(source_index >= 0 && target_index >= 0); assert(source_index != target_index); - EngineID *list = ordering.Begin(); + EngineID *list = ordering.data(); if (source_index < target_index) { --target_index; for (int i = source_index; i < target_index; ++i) list[i] = list[i + 1]; @@ -1265,14 +1273,15 @@ void CommitVehicleListOrderChanges() } /* Store final sort-order */ - const EngineID *idend = ordering.End(); uint index = 0; - for (const EngineID *it = ordering.Begin(); it != idend; ++it, ++index) { - Engine::Get(*it)->list_position = index; + for (const EngineID &eid : ordering) { + Engine::Get(eid)->list_position = index; + ++index; } /* Clear out the queue */ - _list_order_changes.Reset(); + _list_order_changes.clear(); + _list_order_changes.shrink_to_fit(); } /** diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index 51adb0b7fb..a3ead85ca4 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -40,9 +40,9 @@ struct VehicleScopeResolver : public ScopeResolver { void SetVehicle(const Vehicle *v) { this->v = v; } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; - /* virtual */ uint32 GetTriggers() const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetTriggers() const override; }; /** Resolver for a vehicle (chain) */ @@ -64,9 +64,9 @@ struct VehicleResolverObject : public ResolverObject { VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool info_view = false, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0); + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override; - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; static const uint TRAININFO_DEFAULT_VEHICLE_WIDTH = 29; @@ -81,11 +81,11 @@ void SetCustomEngineSprites(EngineID engine, byte cargo, const struct SpriteGrou void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result); #define GetCustomVehicleSprite(v, direction, image_type, result) GetCustomEngineSprite(v->engine_type, v, direction, image_type, result) -#define GetCustomVehicleIcon(et, direction, image_type, result) GetCustomEngineSprite(et, NULL, direction, image_type, result) +#define GetCustomVehicleIcon(et, direction, image_type, result) GetCustomEngineSprite(et, nullptr, direction, image_type, result) void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type, VehicleSpriteSeq *result); #define GetCustomRotorSprite(v, i, image_type, result) GetRotorOverrideSprite(v->engine_type, v, i, image_type, result) -#define GetCustomRotorIcon(et, image_type, result) GetRotorOverrideSprite(et, NULL, true, image_type, result) +#define GetCustomRotorIcon(et, image_type, result) GetRotorOverrideSprite(et, nullptr, true, image_type, result) /* Forward declaration of GRFFile, to avoid unnecessary inclusion of newgrf.h * elsewhere... */ @@ -100,7 +100,7 @@ bool UsesWagonOverride(const Vehicle *v); /* Handler to Evaluate callback 36. If the callback fails (i.e. most of the * time) orig_value is returned */ uint GetVehicleProperty(const Vehicle *v, PropertyID property, uint orig_value); -uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v = NULL); +uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v = nullptr); enum VehicleTrigger { VEHICLE_TRIGGER_NEW_CARGO = 0x01, diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index eb2cbf08f1..bb108f470c 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -42,7 +42,7 @@ struct GenericScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; private: bool ai_callback; ///< Callback comes from the AI. @@ -55,7 +55,7 @@ struct GenericResolverObject : public ResolverObject { GenericResolverObject(bool ai_callback, CallbackID callback = CBID_NO_CALLBACK); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &this->generic_scope; @@ -63,7 +63,7 @@ struct GenericResolverObject : public ResolverObject { } } - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; struct GenericCallback { @@ -140,7 +140,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g /* virtual */ const SpriteGroup *GenericResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (group->num_loaded == 0) return NULL; + if (group->num_loaded == 0) return nullptr; return group->loaded[0]; } @@ -150,7 +150,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g * @param ai_callback Callback comes from the AI. * @param callback Callback ID. */ -GenericResolverObject::GenericResolverObject(bool ai_callback, CallbackID callback) : ResolverObject(NULL, callback), generic_scope(*this, ai_callback) +GenericResolverObject::GenericResolverObject(bool ai_callback, CallbackID callback) : ResolverObject(nullptr, callback), generic_scope(*this, ai_callback) { } @@ -162,7 +162,7 @@ GenericResolverObject::GenericResolverObject(bool ai_callback, CallbackID callba * @param object pre-populated resolver object * @param param1_grfv7 callback_param1 for GRFs up to version 7. * @param param1_grfv8 callback_param1 for GRFs from version 8 on. - * @param[out] file Optionally returns the GRFFile which made the final decision for the callback result. May be NULL if not required. + * @param[out] file Optionally returns the GRFFile which made the final decision for the callback result. May be nullptr if not required. * @return callback value if successful or CALLBACK_FAILED */ static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject &object, uint32 param1_grfv7, uint32 param1_grfv8, const GRFFile **file) @@ -179,7 +179,7 @@ static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject &object, ui if (result == CALLBACK_FAILED) continue; /* Return NewGRF file if necessary */ - if (file != NULL) *file = it->file; + if (file != nullptr) *file = it->file; return result; } @@ -201,7 +201,7 @@ static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject &object, ui * @param event 'AI construction event' to pass to callback. (Variable 86) * @param count 'Construction number' to pass to callback. (Variable 87) * @param station_size 'Station size' to pass to callback. (Variable 88) - * @param[out] file Optionally returns the GRFFile which made the final decision for the callback result. May be NULL if not required. + * @param[out] file Optionally returns the GRFFile which made the final decision for the callback result. May be nullptr if not required. * @return callback value if successful or CALLBACK_FAILED */ uint16 GetAiPurchaseCallbackResult(uint8 feature, CargoID cargo_type, uint8 default_selection, IndustryType src_industry, IndustryType dst_industry, uint8 distance, AIConstructionEvent event, uint8 count, uint8 station_size, const GRFFile **file) diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 5f32b5bad5..d31d10bc88 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -48,11 +48,11 @@ void ShowNewGRFError() /* Do not show errors when entering the main screen */ if (_game_mode == GM_MENU) return; - for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { /* We only want to show fatal errors */ - if (c->error == NULL || c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL) continue; + if (c->error == nullptr || c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL) continue; - SetDParam (0, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING); + SetDParam (0, c->error->custom_message == nullptr ? c->error->message : STR_JUST_RAW_STRING); SetDParamStr(1, c->error->custom_message); SetDParamStr(2, c->filename); SetDParamStr(3, c->error->data); @@ -66,7 +66,7 @@ void ShowNewGRFError() static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint bottom, bool show_params) { - if (c->error != NULL) { + if (c->error != nullptr) { char message[512]; SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages SetDParamStr(1, c->filename); @@ -74,14 +74,14 @@ static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint for (uint i = 0; i < lengthof(c->error->param_value); i++) { SetDParam(3 + i, c->error->param_value[i]); } - GetString(message, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message)); + GetString(message, c->error->custom_message == nullptr ? c->error->message : STR_JUST_RAW_STRING, lastof(message)); SetDParamStr(0, message); y = DrawStringMultiLine(x, right, y, bottom, c->error->severity); } /* Draw filename or not if it is not known (GRF sent over internet) */ - if (c->filename != NULL) { + if (c->filename != nullptr) { SetDParamStr(0, c->filename); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_FILENAME); } @@ -166,7 +166,7 @@ struct NewGRFParametersWindow : public Window { clicked_row(UINT_MAX), editable(editable) { - this->action14present = (c->num_valid_params != lengthof(c->param) || c->param_info.Length() != 0); + this->action14present = (c->num_valid_params != lengthof(c->param) || c->param_info.size() != 0); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NP_SCROLLBAR); @@ -190,7 +190,7 @@ struct NewGRFParametersWindow : public Window { return &dummy_parameter_info; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NP_NUMPAR_DEC: @@ -220,11 +220,11 @@ struct NewGRFParametersWindow : public Window { case WID_NP_DESCRIPTION: /* Minimum size of 4 lines. The 500 is the default size of the window. */ Dimension suggestion = {500 - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT, (uint)FONT_HEIGHT_NORMAL * 4 + WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM}; - for (uint i = 0; i < this->grf_config->param_info.Length(); i++) { + for (uint i = 0; i < this->grf_config->param_info.size(); i++) { const GRFParameterInfo *par_info = this->grf_config->param_info[i]; - if (par_info == NULL) continue; + if (par_info == nullptr) continue; const char *desc = GetGRFStringFromGRFText(par_info->desc); - if (desc == NULL) continue; + if (desc == nullptr) continue; Dimension d = GetStringMultiLineBoundingBox(desc, suggestion); d.height += WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; suggestion = maxdim(d, suggestion); @@ -234,7 +234,7 @@ struct NewGRFParametersWindow : public Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_NP_NUMPAR: @@ -243,13 +243,13 @@ struct NewGRFParametersWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget == WID_NP_DESCRIPTION) { - const GRFParameterInfo *par_info = (this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; - if (par_info == NULL) return; + const GRFParameterInfo *par_info = (this->clicked_row < this->grf_config->param_info.size()) ? this->grf_config->param_info[this->clicked_row] : nullptr; + if (par_info == nullptr) return; const char *desc = GetGRFStringFromGRFText(par_info->desc); - if (desc == NULL) return; + if (desc == nullptr) return; DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_TEXTPANEL_TOP, r.bottom - WD_TEXTPANEL_BOTTOM, desc, TC_BLACK); return; } else if (widget != WID_NP_BACKGROUND) { @@ -265,8 +265,8 @@ struct NewGRFParametersWindow : public Window { int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) { - GRFParameterInfo *par_info = (i < this->grf_config->param_info.Length()) ? this->grf_config->param_info[i] : NULL; - if (par_info == NULL) par_info = GetDummyParameterInfo(i); + GRFParameterInfo *par_info = (i < this->grf_config->param_info.size()) ? this->grf_config->param_info[i] : nullptr; + if (par_info == nullptr) par_info = GetDummyParameterInfo(i); uint32 current_value = par_info->GetValue(this->grf_config); bool selected = (i == this->clicked_row); @@ -283,7 +283,7 @@ struct NewGRFParametersWindow : public Window { SetDParam(3, current_value); if (par_info->value_names.Contains(current_value)) { const char *label = GetGRFStringFromGRFText(par_info->value_names.Find(current_value)->second); - if (label != NULL) { + if (label != nullptr) { SetDParam(2, STR_JUST_RAW_STRING); SetDParamStr(3, label); } @@ -291,7 +291,7 @@ struct NewGRFParametersWindow : public Window { } const char *name = GetGRFStringFromGRFText(par_info->name); - if (name != NULL) { + if (name != nullptr) { SetDParam(0, STR_JUST_RAW_STRING); SetDParamStr(1, name); } else { @@ -304,7 +304,7 @@ struct NewGRFParametersWindow : public Window { } } - virtual void OnPaint() + void OnPaint() override { if (this->closing_dropdown) { this->closing_dropdown = false; @@ -313,7 +313,7 @@ struct NewGRFParametersWindow : public Window { this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_NP_NUMPAR_DEC: @@ -350,8 +350,8 @@ struct NewGRFParametersWindow : public Window { if (_current_text_dir == TD_RTL) x = wid->current_x - 1 - x; x -= 4; - GRFParameterInfo *par_info = (num < this->grf_config->param_info.Length()) ? this->grf_config->param_info[num] : NULL; - if (par_info == NULL) par_info = GetDummyParameterInfo(num); + GRFParameterInfo *par_info = (num < this->grf_config->param_info.size()) ? this->grf_config->param_info[num] : nullptr; + if (par_info == nullptr) par_info = GetDummyParameterInfo(num); /* One of the arrows is clicked */ uint32 old_val = par_info->GetValue(this->grf_config); @@ -376,12 +376,12 @@ struct NewGRFParametersWindow : public Window { this->clicked_dropdown = true; this->closing_dropdown = false; - DropDownList *list = new DropDownList(); + DropDownList list; for (uint32 i = par_info->min_value; i <= par_info->max_value; i++) { - *list->Append() = new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.Find(i)->second), i, false); + list.emplace_back(new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.Find(i)->second), i, false)); } - ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true); + ShowDropDownListAt(this, std::move(list), old_val, -1, wi_rect, COLOUR_ORANGE, true); } } } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { @@ -427,27 +427,27 @@ struct NewGRFParametersWindow : public Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (StrEmpty(str)) return; int32 value = atoi(str); - GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; - if (par_info == NULL) par_info = GetDummyParameterInfo(this->clicked_row); + GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.size()) ? this->grf_config->param_info[this->clicked_row] : nullptr; + if (par_info == nullptr) par_info = GetDummyParameterInfo(this->clicked_row); uint32 val = Clamp(value, par_info->min_value, par_info->max_value); par_info->SetValue(this->grf_config, val); this->SetDirty(); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { assert(this->clicked_dropdown); - GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; - if (par_info == NULL) par_info = GetDummyParameterInfo(this->clicked_row); + GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.size()) ? this->grf_config->param_info[this->clicked_row] : nullptr; + if (par_info == nullptr) par_info = GetDummyParameterInfo(this->clicked_row); par_info->SetValue(this->grf_config, index); this->SetDirty(); } - virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) + void OnDropdownClose(Point pt, int widget, int index, bool instant_close) override { /* 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. @@ -458,7 +458,7 @@ struct NewGRFParametersWindow : public Window { this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_NP_BACKGROUND); } @@ -468,7 +468,7 @@ struct NewGRFParametersWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; if (!this->action14present) { @@ -483,7 +483,7 @@ struct NewGRFParametersWindow : public Window { } } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (timeout.Elapsed(delta_ms)) { this->clicked_button = UINT_MAX; @@ -550,7 +550,7 @@ struct NewGRFTextfileWindow : public TextfileWindow { this->LoadTextfile(textfile, NEWGRF_DIR); } - /* virtual */ void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_TF_CAPTION) { SetDParam(0, STR_CONTENT_TYPE_NEWGRF); @@ -565,26 +565,6 @@ void ShowNewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) new NewGRFTextfileWindow(file_type, c); } -static GRFPresetList _grf_preset_list; ///< List of known NewGRF presets. @see GetGRFPresetList - -class DropDownListPresetItem : public DropDownListItem { -public: - DropDownListPresetItem(int result) : DropDownListItem(result, false) {} - - virtual ~DropDownListPresetItem() {} - - bool Selectable() const - { - return true; - } - - void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const - { - DrawString(left + 2, right + 2, top, _grf_preset_list[this->result], sel ? TC_WHITE : TC_BLACK); - } -}; - - typedef std::map GrfIdMap; ///< Map of grfid to the grf config. /** @@ -594,7 +574,7 @@ typedef std::map GrfIdMap; ///< Map of grfid to the g */ static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map) { - while (c != NULL) { + while (c != nullptr) { std::pair p(c->ident.grfid, c); grfid_map->insert(p); c = c->next; @@ -618,11 +598,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { static GUIGRFConfigList::FilterFunction * const filter_funcs[]; ///< Filter functions of the #GUIGRFConfigList. GUIGRFConfigList avails; ///< Available (non-active) grfs. - const GRFConfig *avail_sel; ///< Currently selected available grf. \c NULL is none is selected. + const GRFConfig *avail_sel; ///< Currently selected available grf. \c nullptr is none is selected. int avail_pos; ///< Index of #avail_sel if existing, else \c -1. StringFilter string_filter; ///< Filter for available grf. QueryString filter_editbox; ///< Filter editbox; + StringList grf_presets; ///< List of known NewGRF presets. + GRFConfig *actives; ///< Temporary active grf list to which changes are made. GRFConfig *active_sel; ///< Selected active grf item. @@ -638,10 +620,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { NewGRFWindow(WindowDesc *desc, bool editable, bool show_params, bool execute, GRFConfig **orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE) { - this->avail_sel = NULL; + this->avail_sel = nullptr; this->avail_pos = -1; - this->active_sel = NULL; - this->actives = NULL; + this->active_sel = nullptr; + this->actives = nullptr; this->orig_list = orig_list; this->editable = editable; this->execute = execute; @@ -650,7 +632,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->active_over = -1; CopyGRFConfigList(&this->actives, *orig_list, false); - GetGRFPresetList(&_grf_preset_list); + this->grf_presets = GetGRFPresetList(); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR); @@ -691,7 +673,6 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { /* Remove the temporary copy of grf-list used in window */ ClearGRFConfigList(&this->actives); - _grf_preset_list.Clear(); } /** @@ -703,7 +684,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { GrfIdMap grfid_map; FillGrfidMap(this->actives, &grfid_map); - for (const GRFConfig *a = _all_grfs; a != NULL; a = a->next) { + for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) { GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid); if (iter != grfid_map.end() && a->version > iter->second->version) return true; } @@ -716,7 +697,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { GrfIdMap grfid_map; FillGrfidMap(this->actives, &grfid_map); - for (const GRFConfig *a = _all_grfs; a != NULL; a = a->next) { + for (const GRFConfig *a = _all_grfs; a != nullptr; a = a->next) { GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid); if (iter == grfid_map.end() || iter->second->version >= a->version) continue; @@ -728,7 +709,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (this->active_sel == *c) { DeleteWindowByClass(WC_GRF_PARAMETERS); DeleteWindowByClass(WC_TEXTFILE); - this->active_sel = NULL; + this->active_sel = nullptr; } delete *c; *c = d; @@ -736,7 +717,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_NS_FILE_LIST: @@ -765,11 +746,9 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_PRESET_LIST: { Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM); - for (uint i = 0; i < _grf_preset_list.Length(); i++) { - if (_grf_preset_list[i] != NULL) { - SetDParamStr(0, _grf_preset_list[i]); - d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING)); - } + for (const auto &i : this->grf_presets) { + SetDParamStr(0, i.c_str()); + d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING)); } d.width += padding.width; *size = maxdim(d, *size); @@ -787,13 +766,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST); this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_NS_PRESET_LIST: @@ -801,7 +780,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { SetDParam(0, STR_NUM_CUSTOM); } else { SetDParam(0, STR_JUST_RAW_STRING); - SetDParamStr(1, _grf_preset_list[this->preset]); + SetDParamStr(1, this->grf_presets[this->preset].c_str()); } break; } @@ -842,7 +821,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { return pal; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_NS_FILE_LIST: { @@ -863,7 +842,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { uint warning_left = rtl ? r.right - square.width - warning.width - 10 : r.left + square.width + 10; int i = 0; - for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) { + for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) { if (this->vscroll->IsVisible(i)) { const char *text = c->GetName(); bool h = (this->active_sel == c); @@ -874,15 +853,15 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } else if (i == this->active_over) { /* Get index of current selection. */ int active_sel_pos = 0; - for (GRFConfig *c = this->actives; c != NULL && c != this->active_sel; c = c->next, active_sel_pos++) {} + for (GRFConfig *c = this->actives; c != nullptr && c != this->active_sel; c = c->next, active_sel_pos++) {} if (active_sel_pos != this->active_over) { uint top = this->active_over < active_sel_pos ? y + 1 : y + step_height - 2; GfxFillRect(r.left + WD_FRAMERECT_LEFT, top - 1, r.right - WD_FRAMERECT_RIGHT, top + 1, PC_GREY); } } DrawSprite(SPR_SQUARE, pal, square_left, y + square_offset_y); - if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, y + warning_offset_y); - uint txtoffset = c->error == NULL ? 0 : warning.width; + if (c->error != nullptr) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, y + warning_offset_y); + uint txtoffset = c->error == nullptr ? 0 : warning.width; DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), y + offset_y, text, h ? TC_WHITE : TC_ORANGE); y += step_height; } @@ -900,7 +879,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top + WD_FRAMERECT_TOP; uint min_index = this->vscroll2->GetPosition(); - uint max_index = min(min_index + this->vscroll2->GetCapacity(), this->avails.Length()); + uint max_index = min(min_index + this->vscroll2->GetCapacity(), (uint)this->avails.size()); for (uint i = min_index; i < max_index; i++) { const GRFConfig *c = this->avails[i]; @@ -922,8 +901,8 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_NEWGRF_INFO: { const GRFConfig *selected = this->active_sel; - if (selected == NULL) selected = this->avail_sel; - if (selected != NULL) { + if (selected == nullptr) selected = this->avail_sel; + if (selected != nullptr) { ShowNewGRFInfo(selected, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, r.bottom - WD_FRAMERECT_BOTTOM, this->show_params); } break; @@ -931,35 +910,33 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_END) { - if (this->active_sel == NULL && this->avail_sel == NULL) return; + if (this->active_sel == nullptr && this->avail_sel == nullptr) return; - ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != NULL ? this->active_sel : this->avail_sel); + ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != nullptr ? this->active_sel : this->avail_sel); return; } switch (widget) { case WID_NS_PRESET_LIST: { - DropDownList *list = new DropDownList(); + DropDownList list; /* Add 'None' option for clearing list */ - *list->Append() = new DropDownListStringItem(STR_NONE, -1, false); + list.emplace_back(new DropDownListStringItem(STR_NONE, -1, false)); - for (uint i = 0; i < _grf_preset_list.Length(); i++) { - if (_grf_preset_list[i] != NULL) { - *list->Append() = new DropDownListPresetItem(i); - } + for (uint i = 0; i < this->grf_presets.size(); i++) { + list.emplace_back(new DropDownListCharStringItem(this->grf_presets[i].c_str(), i, false)); } this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window - ShowDropDownList(this, list, this->preset, WID_NS_PRESET_LIST); + ShowDropDownList(this, std::move(list), this->preset, WID_NS_PRESET_LIST); break; } case WID_NS_OPEN_URL: { - const GRFConfig *c = (this->avail_sel == NULL) ? this->active_sel : this->avail_sel; + const GRFConfig *c = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel; extern void OpenBrowser(const char *url); OpenBrowser(c->GetURL()); @@ -967,24 +944,24 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } case WID_NS_PRESET_SAVE: - ShowSavePresetWindow((this->preset == -1) ? NULL : _grf_preset_list[this->preset]); + ShowSavePresetWindow((this->preset == -1) ? nullptr : this->grf_presets[this->preset].c_str()); break; case WID_NS_PRESET_DELETE: if (this->preset == -1) return; - DeleteGRFPresetFromConfig(_grf_preset_list[this->preset]); - GetGRFPresetList(&_grf_preset_list); + DeleteGRFPresetFromConfig(this->grf_presets[this->preset].c_str()); + this->grf_presets = GetGRFPresetList(); this->preset = -1; this->InvalidateData(); this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window break; case WID_NS_MOVE_UP: { // Move GRF up - if (this->active_sel == NULL || !this->editable) break; + if (this->active_sel == nullptr || !this->editable) break; int pos = 0; - for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next, pos++) { + for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) { GRFConfig *c = *pc; if (c->next == this->active_sel) { c->next = this->active_sel->next; @@ -1000,10 +977,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } case WID_NS_MOVE_DOWN: { // Move GRF down - if (this->active_sel == NULL || !this->editable) break; + if (this->active_sel == nullptr || !this->editable) break; int pos = 1; // Start at 1 as we swap the selected newgrf with the next one - for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next, pos++) { + for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next, pos++) { GRFConfig *c = *pc; if (c == this->active_sel) { *pc = c->next; @@ -1024,19 +1001,19 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST); GRFConfig *c; - for (c = this->actives; c != NULL && i > 0; c = c->next, i--) {} + for (c = this->actives; c != nullptr && i > 0; c = c->next, i--) {} if (this->active_sel != c) { DeleteWindowByClass(WC_GRF_PARAMETERS); DeleteWindowByClass(WC_TEXTFILE); } this->active_sel = c; - this->avail_sel = NULL; + this->avail_sel = nullptr; this->avail_pos = -1; this->InvalidateData(); if (click_count == 1) { - if (this->editable && this->active_sel != NULL) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); + if (this->editable && this->active_sel != nullptr) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); break; } /* With double click, continue */ @@ -1044,20 +1021,20 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } case WID_NS_REMOVE: { // Remove GRF - if (this->active_sel == NULL || !this->editable) break; + if (this->active_sel == nullptr || !this->editable) break; DeleteWindowByClass(WC_GRF_PARAMETERS); DeleteWindowByClass(WC_TEXTFILE); /* Choose the next GRF file to be the selected file. */ GRFConfig *newsel = this->active_sel->next; - for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next) { + for (GRFConfig **pc = &this->actives; *pc != nullptr; pc = &(*pc)->next) { GRFConfig *c = *pc; /* If the new selection is empty (i.e. we're deleting the last item * in the list, pick the file just before the selected file */ - if (newsel == NULL && c->next == this->active_sel) newsel = c; + if (newsel == nullptr && c->next == this->active_sel) newsel = c; if (c == this->active_sel) { - if (newsel == c) newsel = NULL; + if (newsel == c) newsel = nullptr; *pc = c->next; delete c; @@ -1068,14 +1045,14 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->active_sel = newsel; this->preset = -1; this->avail_pos = -1; - this->avail_sel = NULL; + this->avail_sel = nullptr; this->avails.ForceRebuild(); this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; } case WID_NS_UPGRADE: { // Upgrade GRF. - if (!this->editable || this->actives == NULL) break; + if (!this->editable || this->actives == nullptr) break; UpgradeCurrent(); this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; @@ -1085,16 +1062,16 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { ResetObjectToPlace(); uint i = this->vscroll2->GetScrolledRowFromWidget(pt.y, this, WID_NS_AVAIL_LIST); - this->active_sel = NULL; + this->active_sel = nullptr; DeleteWindowByClass(WC_GRF_PARAMETERS); - if (i < this->avails.Length()) { + if (i < this->avails.size()) { if (this->avail_sel != this->avails[i]) DeleteWindowByClass(WC_TEXTFILE); this->avail_sel = this->avails[i]; this->avail_pos = i; } this->InvalidateData(); if (click_count == 1) { - if (this->editable && this->avail_sel != NULL && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); + if (this->editable && this->avail_sel != nullptr && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); break; } /* With double click, continue */ @@ -1102,7 +1079,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } case WID_NS_ADD: - if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break; + if (this->avail_sel == nullptr || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break; this->AddGRFToActive(); break; @@ -1126,14 +1103,14 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_VIEW_PARAMETERS: case WID_NS_SET_PARAMETERS: { // Edit parameters - if (this->active_sel == NULL || !this->show_params || this->active_sel->num_valid_params == 0) break; + if (this->active_sel == nullptr || !this->show_params || this->active_sel->num_valid_params == 0) break; OpenGRFParameterWindow(this->active_sel, this->editable); break; } case WID_NS_TOGGLE_PALETTE: - if (this->active_sel != NULL && this->editable) { + if (this->active_sel != nullptr && this->editable) { this->active_sel->palette ^= GRFP_USE_MASK; this->SetDirty(); } @@ -1144,11 +1121,9 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { -#if defined(ENABLE_NETWORK) this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window ShowMissingContentWindow(this->actives); -#endif } break; @@ -1159,16 +1134,16 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } } - virtual void OnNewGRFsScanned() + void OnNewGRFsScanned() override { - if (this->active_sel == NULL) DeleteWindowByClass(WC_TEXTFILE); - this->avail_sel = NULL; + if (this->active_sel == nullptr) DeleteWindowByClass(WC_TEXTFILE); + this->avail_sel = nullptr; this->avail_pos = -1; this->avails.ForceRebuild(); this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (!this->editable) return; @@ -1176,27 +1151,27 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->preset = index; if (index != -1) { - this->actives = LoadGRFPresetFromConfig(_grf_preset_list[index]); + this->actives = LoadGRFPresetFromConfig(this->grf_presets[index].c_str()); } this->avails.ForceRebuild(); ResetObjectToPlace(); DeleteWindowByClass(WC_GRF_PARAMETERS); DeleteWindowByClass(WC_TEXTFILE); - this->active_sel = NULL; + this->active_sel = nullptr; this->InvalidateData(GOID_NEWGRF_PRESET_LOADED); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; SaveGRFPresetToConfig(str, this->actives); - GetGRFPresetList(&_grf_preset_list); + this->grf_presets = GetGRFPresetList(); /* Switch to this preset */ - for (uint i = 0; i < _grf_preset_list.Length(); i++) { - if (_grf_preset_list[i] != NULL && strcmp(_grf_preset_list[i], str) == 0) { + for (uint i = 0; i < this->grf_presets.size(); i++) { + if (this->grf_presets[i] == str) { this->preset = i; break; } @@ -1210,7 +1185,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { * @param data Information about the changed data. @see GameOptionsInvalidationData * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; switch (data) { @@ -1220,13 +1195,13 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case GOID_NEWGRF_RESCANNED: /* Search the list for items that are now found and mark them as such. */ - for (GRFConfig **l = &this->actives; *l != NULL; l = &(*l)->next) { + for (GRFConfig **l = &this->actives; *l != nullptr; l = &(*l)->next) { GRFConfig *c = *l; bool compatible = HasBit(c->flags, GCF_COMPATIBLE); if (c->status != GCS_NOT_FOUND && !compatible) continue; const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? c->original_md5sum : c->ident.md5sum); - if (f == NULL || HasBit(f->flags, GCF_INVALID)) continue; + if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue; *l = new GRFConfig(*f); (*l)->next = c->next; @@ -1246,7 +1221,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case GOID_NEWGRF_PRESET_LOADED: { /* Update scrollbars */ int i = 0; - for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) {} + for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {} this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling. @@ -1263,10 +1238,10 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { WID_NS_TOGGLE_PALETTE, WIDGET_LIST_END ); - this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == NULL || HasBit(this->avail_sel->flags, GCF_INVALID)); - this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives == NULL || !this->CanUpgradeCurrent()); + this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == nullptr || HasBit(this->avail_sel->flags, GCF_INVALID)); + this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives == nullptr || !this->CanUpgradeCurrent()); - bool disable_all = this->active_sel == NULL || !this->editable; + bool disable_all = this->active_sel == nullptr || !this->editable; this->SetWidgetsDisabledState(disable_all, WID_NS_REMOVE, WID_NS_MOVE_UP, @@ -1274,28 +1249,28 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { WIDGET_LIST_END ); - const GRFConfig *c = (this->avail_sel == NULL) ? this->active_sel : this->avail_sel; + const GRFConfig *c = (this->avail_sel == nullptr) ? this->active_sel : this->avail_sel; for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { - this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, c == NULL || c->GetTextfile(tft) == NULL); + this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, c == nullptr || c->GetTextfile(tft) == nullptr); } - this->SetWidgetDisabledState(WID_NS_OPEN_URL, c == NULL || StrEmpty(c->GetURL())); + this->SetWidgetDisabledState(WID_NS_OPEN_URL, c == nullptr || StrEmpty(c->GetURL())); - this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == NULL || this->active_sel->num_valid_params == 0); - this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == NULL || this->active_sel->num_valid_params == 0); + this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0); + this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == nullptr || this->active_sel->num_valid_params == 0); this->SetWidgetDisabledState(WID_NS_TOGGLE_PALETTE, disable_all || (!(_settings_client.gui.newgrf_developer_tools || _settings_client.gui.scenario_developer) && ((c->palette & GRFP_GRF_MASK) != GRFP_GRF_UNSET))); if (!disable_all) { /* All widgets are now enabled, so disable widgets we can't use */ if (this->active_sel == this->actives) this->DisableWidget(WID_NS_MOVE_UP); - if (this->active_sel->next == NULL) this->DisableWidget(WID_NS_MOVE_DOWN); + if (this->active_sel->next == nullptr) this->DisableWidget(WID_NS_MOVE_DOWN); } this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1); bool has_missing = false; bool has_compatible = false; - for (const GRFConfig *c = this->actives; !has_missing && c != NULL; c = c->next) { + for (const GRFConfig *c = this->actives; !has_missing && c != nullptr; c = c->next) { has_missing |= c->status == GCS_NOT_FOUND; has_compatible |= HasBit(c->flags, GCF_COMPATIBLE); } @@ -1316,7 +1291,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing); } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { if (!this->editable) return ES_NOT_HANDLED; @@ -1328,7 +1303,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WKC_DOWN: /* scroll down by one */ - if (this->avail_pos < (int)this->avails.Length() - 1) this->avail_pos++; + if (this->avail_pos < (int)this->avails.size() - 1) this->avail_pos++; break; case WKC_PAGEUP: @@ -1338,7 +1313,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WKC_PAGEDOWN: /* scroll down a page */ - this->avail_pos = min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.Length() - 1); + this->avail_pos = min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.size() - 1); break; case WKC_HOME: @@ -1348,16 +1323,16 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WKC_END: /* jump to end */ - this->avail_pos = this->avails.Length() - 1; + this->avail_pos = (uint)this->avails.size() - 1; break; default: return ES_NOT_HANDLED; } - if (this->avails.Length() == 0) this->avail_pos = -1; + if (this->avails.size() == 0) this->avail_pos = -1; if (this->avail_pos >= 0) { - this->active_sel = NULL; + this->active_sel = nullptr; DeleteWindowByClass(WC_GRF_PARAMETERS); if (this->avail_sel != this->avails[this->avail_pos]) DeleteWindowByClass(WC_TEXTFILE); this->avail_sel = this->avails[this->avail_pos]; @@ -1368,7 +1343,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { return ES_HANDLED; } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { if (!this->editable) return; @@ -1378,12 +1353,12 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->InvalidateData(0); } - virtual void OnDragDrop(Point pt, int widget) + void OnDragDrop(Point pt, int widget) override { if (!this->editable) return; if (widget == WID_NS_FILE_LIST) { - if (this->active_sel != NULL) { + if (this->active_sel != nullptr) { /* Get pointer to the selected file in the active list. */ int from_pos = 0; GRFConfig **from_prev; @@ -1394,7 +1369,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (to_pos != from_pos) { // Don't move NewGRF file over itself. /* Get pointer to destination position. */ GRFConfig **to_prev = &this->actives; - for (int i = from_pos < to_pos ? -1 : 0; *to_prev != NULL && i < to_pos; to_prev = &(*to_prev)->next, i++) {} + for (int i = from_pos < to_pos ? -1 : 0; *to_prev != nullptr && i < to_pos; to_prev = &(*to_prev)->next, i++) {} /* Detach NewGRF file from its original position. */ *from_prev = this->active_sel->next; @@ -1407,11 +1382,11 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->preset = -1; this->InvalidateData(); } - } else if (this->avail_sel != NULL) { + } else if (this->avail_sel != nullptr) { int to_pos = min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST), this->vscroll->GetCount() - 1); this->AddGRFToActive(to_pos); } - } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != NULL) { + } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) { /* Remove active NewGRF file by dragging it over available list. */ Point dummy = {-1, -1}; this->OnClick(dummy, WID_NS_REMOVE, 1); @@ -1426,21 +1401,21 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } } - virtual void OnMouseDrag(Point pt, int widget) + void OnMouseDrag(Point pt, int widget) override { if (!this->editable) return; - if (widget == WID_NS_FILE_LIST && (this->active_sel != NULL || this->avail_sel != NULL)) { + if (widget == WID_NS_FILE_LIST && (this->active_sel != nullptr || this->avail_sel != nullptr)) { /* An NewGRF file is dragged over the active list. */ int to_pos = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST); /* Skip the last dummy line if the source is from the active list. */ - to_pos = min(to_pos, this->vscroll->GetCount() - (this->active_sel != NULL ? 2 : 1)); + to_pos = min(to_pos, this->vscroll->GetCount() - (this->active_sel != nullptr ? 2 : 1)); if (to_pos != this->active_over) { this->active_over = to_pos; this->SetWidgetDirty(WID_NS_FILE_LIST); } - } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != NULL) { + } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != nullptr) { this->active_over = -2; this->SetWidgetDirty(WID_NS_AVAIL_LIST); } else if (this->active_over != -1) { @@ -1451,15 +1426,15 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { private: /** Sort grfs by name. */ - static int CDECL NameSorter(const GRFConfig * const *a, const GRFConfig * const *b) + static bool NameSorter(const GRFConfig * const &a, const GRFConfig * const &b) { - int i = strnatcmp((*a)->GetName(), (*b)->GetName(), true); // Sort by name (natural sorting). - if (i != 0) return i; + int i = strnatcmp(a->GetName(), b->GetName(), true); // Sort by name (natural sorting). + if (i != 0) return i < 0; - i = (*a)->version - (*b)->version; - if (i != 0) return i; + i = a->version - b->version; + if (i != 0) return i < 0; - return memcmp((*a)->ident.md5sum, (*b)->ident.md5sum, lengthof((*b)->ident.md5sum)); + return memcmp(a->ident.md5sum, b->ident.md5sum, lengthof(b->ident.md5sum)) < 0; } /** Filter grfs by tags/name */ @@ -1476,15 +1451,15 @@ private: { if (!this->avails.NeedRebuild()) return; - this->avails.Clear(); + this->avails.clear(); - for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) { + for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) { bool found = false; - for (const GRFConfig *grf = this->actives; grf != NULL && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum); + for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum); if (found) continue; if (_settings_client.gui.newgrf_show_old_versions) { - *this->avails.Append() = c; + this->avails.push_back(c); } else { const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID); /* @@ -1495,22 +1470,24 @@ private: * show that NewGRF!. */ if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum)) { - *this->avails.Append() = c; + this->avails.push_back(c); } } } this->avails.Filter(this->string_filter); - this->avails.Compact(); + this->avails.shrink_to_fit(); this->avails.RebuildDone(); this->avails.Sort(); - if (this->avail_sel != NULL) { - this->avail_pos = this->avails.FindIndex(this->avail_sel); - if (this->avail_pos < 0) this->avail_sel = NULL; + if (this->avail_sel != nullptr) { + this->avail_pos = find_index(this->avails, this->avail_sel); + if (this->avail_pos == -1) { + this->avail_sel = nullptr; + } } - this->vscroll2->SetCount(this->avails.Length()); // Update the scrollbar + this->vscroll2->SetCount((uint)this->avails.size()); // Update the scrollbar } /** @@ -1520,15 +1497,15 @@ private: */ bool AddGRFToActive(int ins_pos = -1) { - if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) return false; + if (this->avail_sel == nullptr || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) return false; DeleteWindowByClass(WC_TEXTFILE); uint count = 0; - GRFConfig **entry = NULL; + GRFConfig **entry = nullptr; GRFConfig **list; /* Find last entry in the list, checking for duplicate grfid on the way */ - for (list = &this->actives; *list != NULL; list = &(*list)->next, ins_pos--) { + for (list = &this->actives; *list != nullptr; list = &(*list)->next, ins_pos--) { if (ins_pos == 0) entry = list; // Insert position? Save. if ((*list)->ident.grfid == this->avail_sel->ident.grfid) { ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO); @@ -1536,7 +1513,7 @@ private: } if (!HasBit((*list)->flags, GCF_STATIC)) count++; } - if (entry == NULL) entry = list; + if (entry == nullptr) entry = list; if (count >= NETWORK_MAX_GRF_COUNT) { ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO); return false; @@ -1551,7 +1528,7 @@ private: /* Select next (or previous, if last one) item in the list. */ int new_pos = this->avail_pos + 1; - if (new_pos >= (int)this->avails.Length()) new_pos = this->avail_pos - 1; + if (new_pos >= (int)this->avails.size()) new_pos = this->avail_pos - 1; this->avail_pos = new_pos; if (new_pos >= 0) this->avail_sel = this->avails[new_pos]; @@ -1561,7 +1538,6 @@ private: } }; -#if defined(ENABLE_NETWORK) /** * Show the content list window with all missing grfs from the given list. * @param list The list of grfs to check for missing / not exactly matching ones. @@ -1570,7 +1546,7 @@ void ShowMissingContentWindow(const GRFConfig *list) { /* Only show the things in the current list, or everything when nothing's selected */ ContentVector cv; - for (const GRFConfig *c = list; c != NULL; c = c->next) { + for (const GRFConfig *c = list; c != nullptr; c = c->next) { if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue; ContentInfo *ci = new ContentInfo(); @@ -1579,11 +1555,10 @@ void ShowMissingContentWindow(const GRFConfig *list) strecpy(ci->name, c->GetName(), lastof(ci->name)); ci->unique_id = BSWAP32(c->ident.grfid); memcpy(ci->md5sum, HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum, sizeof(ci->md5sum)); - *cv.Append() = ci; + cv.push_back(ci); } - ShowNetworkContentListWindow(cv.Length() == 0 ? NULL : &cv, CONTENT_TYPE_NEWGRF); + ShowNetworkContentListWindow(cv.size() == 0 ? nullptr : &cv, CONTENT_TYPE_NEWGRF); } -#endif Listing NewGRFWindow::last_sorting = {false, 0}; Filtering NewGRFWindow::last_filtering = {false, 0}; @@ -1627,10 +1602,10 @@ public: this->editable = true; // Temporary setting, 'real' value is set in SetupSmallestSize(). } - virtual void SetupSmallestSize(Window *w, bool init_array) + void SetupSmallestSize(Window *w, bool init_array) override { /* Copy state flag from the window. */ - assert(dynamic_cast(w) != NULL); + assert(dynamic_cast(w) != nullptr); NewGRFWindow *ngw = (NewGRFWindow *)w; this->editable = ngw->editable; @@ -1670,7 +1645,7 @@ public: this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y); } - virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override { this->StoreSizePosition(sizing, x, y, given_width, given_height); @@ -1789,17 +1764,17 @@ public: } } - virtual NWidgetCore *GetWidgetFromPos(int x, int y) + NWidgetCore *GetWidgetFromPos(int x, int y) override { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; - NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : NULL; - if (nw == NULL) nw = this->acs->GetWidgetFromPos(x, y); - if (nw == NULL) nw = this->inf->GetWidgetFromPos(x, y); + NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : nullptr; + if (nw == nullptr) nw = this->acs->GetWidgetFromPos(x, y); + if (nw == nullptr) nw = this->inf->GetWidgetFromPos(x, y); return nw; } - virtual void Draw(const Window *w) + void Draw(const Window *w) override { if (this->editable) this->avs->Draw(w); this->acs->Draw(w); @@ -1937,13 +1912,13 @@ static const NWidgetPart _nested_newgrf_infopanel_widgets[] = { /** Construct nested container widget for managing the lists and the info panel of the NewGRF GUI. */ NWidgetBase* NewGRFDisplay(int *biggest_index) { - NWidgetBase *avs = MakeNWidgets(_nested_newgrf_availables_widgets, lengthof(_nested_newgrf_availables_widgets), biggest_index, NULL); + NWidgetBase *avs = MakeNWidgets(_nested_newgrf_availables_widgets, lengthof(_nested_newgrf_availables_widgets), biggest_index, nullptr); int biggest2; - NWidgetBase *acs = MakeNWidgets(_nested_newgrf_actives_widgets, lengthof(_nested_newgrf_actives_widgets), &biggest2, NULL); + NWidgetBase *acs = MakeNWidgets(_nested_newgrf_actives_widgets, lengthof(_nested_newgrf_actives_widgets), &biggest2, nullptr); *biggest_index = max(*biggest_index, biggest2); - NWidgetBase *inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, lengthof(_nested_newgrf_infopanel_widgets), &biggest2, NULL); + NWidgetBase *inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, lengthof(_nested_newgrf_infopanel_widgets), &biggest2, nullptr); *biggest_index = max(*biggest_index, biggest2); return new NWidgetNewGRFDisplay(avs, acs, inf); @@ -1995,9 +1970,9 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) /* Show new, updated list */ GRFConfig *c; int i = 0; - for (c = nw->actives; c != NULL && c != nw->active_sel; c = c->next, i++) {} + for (c = nw->actives; c != nullptr && c != nw->active_sel; c = c->next, i++) {} CopyGRFConfigList(&nw->actives, *nw->orig_list, false); - for (c = nw->actives; c != NULL && i > 0; c = c->next, i--) {} + for (c = nw->actives; c != nullptr && i > 0; c = c->next, i--) {} nw->active_sel = c; nw->avails.ForceRebuild(); @@ -2058,21 +2033,21 @@ static WindowDesc _save_preset_desc( /** Class for the save preset window. */ struct SavePresetWindow : public Window { QueryString presetname_editbox; ///< Edit box of the save preset. - GRFPresetList presets; ///< Available presets. + StringList presets; ///< Available presets. Scrollbar *vscroll; ///< Pointer to the scrollbar widget. int selected; ///< Selected entry in the preset list, or \c -1 if none selected. /** * Constructor of the save preset window. - * @param initial_text Initial text to display in the edit box, or \c NULL. + * @param initial_text Initial text to display in the edit box, or \c nullptr. */ SavePresetWindow(const char *initial_text) : Window(&_save_preset_desc), presetname_editbox(32) { - GetGRFPresetList(&this->presets); + this->presets = GetGRFPresetList(); this->selected = -1; - if (initial_text != NULL) { - for (uint i = 0; i < this->presets.Length(); i++) { - if (!strcmp(initial_text, this->presets[i])) { + if (initial_text != nullptr) { + for (uint i = 0; i < this->presets.size(); i++) { + if (this->presets[i] == initial_text) { this->selected = i; break; } @@ -2087,33 +2062,33 @@ struct SavePresetWindow : public Window { this->vscroll = this->GetScrollbar(WID_SVP_SCROLLBAR); this->FinishInitNested(0); - this->vscroll->SetCount(this->presets.Length()); + this->vscroll->SetCount((uint)this->presets.size()); this->SetFocusedWidget(WID_SVP_EDITBOX); - if (initial_text != NULL) this->presetname_editbox.text.Assign(initial_text); + if (initial_text != nullptr) this->presetname_editbox.text.Assign(initial_text); } ~SavePresetWindow() { } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SVP_PRESET_LIST: { resize->height = FONT_HEIGHT_NORMAL + 2U; size->height = 0; - for (uint i = 0; i < this->presets.Length(); i++) { - Dimension d = GetStringBoundingBox(this->presets[i]); + for (uint i = 0; i < this->presets.size(); i++) { + Dimension d = GetStringBoundingBox(this->presets[i].c_str()); size->width = max(size->width, d.width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); resize->height = max(resize->height, d.height); } - size->height = ClampU(this->presets.Length(), 5, 20) * resize->height + 1; + size->height = ClampU((uint)this->presets.size(), 5, 20) * resize->height + 1; break; } } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SVP_PRESET_LIST: { @@ -2123,12 +2098,12 @@ struct SavePresetWindow : public Window { int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top + WD_FRAMERECT_TOP; uint min_index = this->vscroll->GetPosition(); - uint max_index = min(min_index + this->vscroll->GetCapacity(), this->presets.Length()); + uint max_index = min(min_index + this->vscroll->GetCapacity(), (uint)this->presets.size()); for (uint i = min_index; i < max_index; i++) { if ((int)i == this->selected) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 2, PC_DARK_BLUE); - const char *text = this->presets[i]; + const char *text = this->presets[i].c_str(); DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y + offset_y, text, ((int)i == this->selected) ? TC_WHITE : TC_SILVER); y += step_height; } @@ -2137,14 +2112,14 @@ struct SavePresetWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SVP_PRESET_LIST: { uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SVP_PRESET_LIST); - if (row < this->presets.Length()) { + if (row < this->presets.size()) { this->selected = row; - this->presetname_editbox.text.Assign(this->presets[row]); + this->presetname_editbox.text.Assign(this->presets[row].c_str()); this->SetWidgetDirty(WID_SVP_PRESET_LIST); this->SetWidgetDirty(WID_SVP_EDITBOX); } @@ -2157,14 +2132,14 @@ struct SavePresetWindow : public Window { case WID_SVP_SAVE: { Window *w = FindWindowById(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); - if (w != NULL && !StrEmpty(this->presetname_editbox.text.buf)) w->OnQueryTextFinished(this->presetname_editbox.text.buf); + if (w != nullptr && !StrEmpty(this->presetname_editbox.text.buf)) w->OnQueryTextFinished(this->presetname_editbox.text.buf); delete this; break; } } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SVP_PRESET_LIST); } @@ -2172,7 +2147,7 @@ struct SavePresetWindow : public Window { /** * Open the window for saving a preset. - * @param initial_text Initial text to display in the edit box, or \c NULL. + * @param initial_text Initial text to display in the edit box, or \c nullptr. */ static void ShowSavePresetWindow(const char *initial_text) { @@ -2196,7 +2171,7 @@ static const NWidgetPart _nested_scan_progress_widgets[] = { /** Description of the widgets and other settings of the window. */ static WindowDesc _scan_progress_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, _nested_scan_progress_widgets, lengthof(_nested_scan_progress_widgets) @@ -2208,7 +2183,7 @@ struct ScanProgressWindow : public Window { int scanned; ///< The number of NewGRFs that we have seen. /** Create the window. */ - ScanProgressWindow() : Window(&_scan_progress_desc), last_name(NULL), scanned(0) + ScanProgressWindow() : Window(&_scan_progress_desc), last_name(nullptr), scanned(0) { this->InitNested(1); } @@ -2219,7 +2194,7 @@ struct ScanProgressWindow : public Window { free(last_name); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SP_PROGRESS_BAR: { @@ -2242,7 +2217,7 @@ struct ScanProgressWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SP_PROGRESS_BAR: { @@ -2260,7 +2235,7 @@ struct ScanProgressWindow : public Window { SetDParam(1, _settings_client.gui.last_newgrf_count); DrawString(r.left, r.right, r.top, STR_NEWGRF_SCAN_STATUS, TC_FROMSTRING, SA_HOR_CENTER); - DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL, this->last_name == NULL ? "" : this->last_name, TC_BLACK, SA_HOR_CENTER); + DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL, this->last_name == nullptr ? "" : this->last_name, TC_BLACK, SA_HOR_CENTER); break; } } @@ -2273,7 +2248,7 @@ struct ScanProgressWindow : public Window { void UpdateNewGRFScanStatus(uint num, const char *name) { free(this->last_name); - if (name == NULL) { + if (name == nullptr) { char buf[256]; GetString(buf, STR_NEWGRF_SCAN_ARCHIVES, lastof(buf)); this->last_name = stredup(buf); @@ -2295,6 +2270,6 @@ struct ScanProgressWindow : public Window { void UpdateNewGRFScanStatus(uint num, const char *name) { ScanProgressWindow *w = dynamic_cast(FindWindowByClass(WC_MODAL_PROGRESS)); - if (w == NULL) w = new ScanProgressWindow(); + if (w == nullptr) w = new ScanProgressWindow(); w->UpdateNewGRFScanStatus(num, name); } diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 314f02b3dc..7df48304bd 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -34,12 +34,12 @@ HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID) /** * Retrieve the grf file associated with a house. * @param house_id House to query. - * @return The associated GRF file (may be \c NULL). + * @return The associated GRF file (may be \c nullptr). */ static const GRFFile *GetHouseSpecGrf(HouseID house_id) { const HouseSpec *hs = HouseSpec::Get(house_id); - return (hs != NULL) ? hs->grf_prop.grffile : NULL; + return (hs != nullptr) ? hs->grf_prop.grffile : nullptr; } /** @@ -190,7 +190,7 @@ static bool SearchNearbyHouseID(TileIndex tile, void *user_data) if (IsTileType(tile, MP_HOUSE)) { HouseID house = GetHouseType(tile); // tile been examined const HouseSpec *hs = HouseSpec::Get(house); - if (hs->grf_prop.grffile != NULL) { // must be one from a grf file + if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data; TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! @@ -214,7 +214,7 @@ static bool SearchNearbyHouseClass(TileIndex tile, void *user_data) if (IsTileType(tile, MP_HOUSE)) { HouseID house = GetHouseType(tile); // tile been examined const HouseSpec *hs = HouseSpec::Get(house); - if (hs->grf_prop.grffile != NULL) { // must be one from a grf file + if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data; TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! @@ -238,7 +238,7 @@ static bool SearchNearbyHouseGRFID(TileIndex tile, void *user_data) if (IsTileType(tile, MP_HOUSE)) { HouseID house = GetHouseType(tile); // tile been examined const HouseSpec *hs = HouseSpec::Get(house); - if (hs->grf_prop.grffile != NULL) { // must be one from a grf file + if (hs->grf_prop.grffile != nullptr) { // must be one from a grf file SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data; TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! @@ -320,7 +320,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI /* Building counts for new houses with id = parameter. */ case 0x61: { const HouseSpec *hs = HouseSpec::Get(this->house_id); - if (hs->grf_prop.grffile == NULL) return 0; + if (hs->grf_prop.grffile == nullptr) return 0; HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.grffile->grfid); return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, this->town); @@ -350,8 +350,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI /* Collect acceptance stats. */ uint32 res = 0; - for (Station * const * st_iter = sl->Begin(); st_iter != sl->End(); st_iter++) { - const Station *st = *st_iter; + for (Station *st : *sl) { if (HasBit(st->goods[cid].status, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0); if (HasBit(st->goods[cid].status, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1); if (HasBit(st->goods[cid].status, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2); @@ -463,7 +462,7 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id) HouseResolverObject object(house_id, ti->tile, Town::GetByTile(ti->tile)); const SpriteGroup *group = object.Resolve(); - if (group != NULL && group->type == SGT_TILELAYOUT) { + if (group != nullptr && group->type == SGT_TILELAYOUT) { /* Limit the building stage to the number of stages supplied. */ const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group; byte stage = GetHouseBuildingStage(ti->tile); @@ -489,7 +488,7 @@ struct HouseAnimationBase : public AnimationBaseextra_flags, CALLBACK_1A_RANDOM_BITS)); } @@ -582,14 +581,14 @@ static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_rando HouseID hid = GetHouseType(tile); HouseSpec *hs = HouseSpec::Get(hid); - if (hs->grf_prop.spritegroup[0] == NULL) return; + if (hs->grf_prop.spritegroup[0] == nullptr) return; HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER); object.waiting_triggers = GetHouseTriggers(tile) | trigger; SetHouseTriggers(tile, object.waiting_triggers); // store now for var 5F const SpriteGroup *group = object.Resolve(); - if (group == NULL) return; + if (group == nullptr) return; /* Store remaining triggers. */ SetHouseTriggers(tile, object.GetRemainingTriggers()); diff --git a/src/newgrf_house.h b/src/newgrf_house.h index bb364f6fc6..10d61a9e99 100644 --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -44,9 +44,9 @@ struct HouseScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; - /* virtual */ uint32 GetTriggers() const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetTriggers() const override; }; /** Resolver object to be used for houses (feature 07 spritegroups). */ @@ -58,7 +58,7 @@ struct HouseResolverObject : public ResolverObject { CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0, bool not_yet_constructed = false, uint8 initial_random_bits = 0, CargoTypes watched_cargo_triggers = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &this->house_scope; diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 980059cabb..34fffea9b1 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -79,7 +79,7 @@ uint32 GetIndustryIDAtOffset(TileIndex tile, const Industry *i, uint32 cur_grfid } } /* Not an 'old type' tile */ - if (indtsp->grf_prop.spritegroup[0] != NULL) { // tile has a spritegroup ? + if (indtsp->grf_prop.spritegroup[0] != nullptr) { // tile has a spritegroup ? if (indtsp->grf_prop.grffile->grfid == cur_grfid) { // same industry, same grf ? return indtsp->grf_prop.local_id; } else { @@ -202,7 +202,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout const IndustrySpec *indspec = GetIndustrySpec(this->type); - if (this->industry == NULL) { + if (this->industry == nullptr) { DEBUG(grf, 1, "Unhandled variable 0x%X (no available industry) in callback 0x%x", variable, this->ro.callback); *available = false; @@ -240,7 +240,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout bool is_ai = false; const Company *c = Company::GetIfValid(this->industry->founder); - if (c != NULL) { + if (c != nullptr) { const Livery *l = &c->livery[LS_DEFAULT]; is_ai = c->is_ai; @@ -308,16 +308,22 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout case 0x6A: case 0x6B: case 0x6C: - case 0x6D: { + case 0x6D: + case 0x70: + case 0x71: { CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile); int index = this->industry->GetCargoProducedIndex(cargo); if (index < 0) return 0; // invalid cargo - if (variable == 0x69) return this->industry->produced_cargo_waiting[index]; - if (variable == 0x6A) return this->industry->this_month_production[index]; - if (variable == 0x6B) return this->industry->this_month_transported[index]; - if (variable == 0x6C) return this->industry->last_month_production[index]; - if (variable == 0x6D) return this->industry->last_month_transported[index]; - NOT_REACHED(); + switch (variable) { + case 0x69: return this->industry->produced_cargo_waiting[index]; + case 0x6A: return this->industry->this_month_production[index]; + case 0x6B: return this->industry->this_month_transported[index]; + case 0x6C: return this->industry->last_month_production[index]; + case 0x6D: return this->industry->last_month_transported[index]; + case 0x70: return this->industry->production_rate[index]; + case 0x71: return this->industry->last_month_pct_transported[index]; + default: NOT_REACHED(); + } } @@ -332,7 +338,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout } /* Get a variable from the persistent storage */ - case 0x7C: return (this->industry->psa != NULL) ? this->industry->psa->GetValue(parameter) : 0; + case 0x7C: return (this->industry->psa != nullptr) ? this->industry->psa->GetValue(parameter) : 0; /* Industry structure access*/ case 0x80: return this->industry->location.tile; @@ -405,7 +411,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout /* virtual */ uint32 IndustriesScopeResolver::GetRandomBits() const { - return this->industry != NULL ? this->industry->random : 0; + return this->industry != nullptr ? this->industry->random : 0; } /* virtual */ uint32 IndustriesScopeResolver::GetTriggers() const @@ -417,13 +423,13 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout { if (this->industry->index == INVALID_INDUSTRY) return; - if (this->industry->psa == NULL) { + if (this->industry->psa == nullptr) { /* There is no need to create a storage if the value is zero. */ if (value == 0) return; /* Create storage on first modification. */ const IndustrySpec *indsp = GetIndustrySpec(this->industry->type); - uint32 grfid = (indsp->grf_prop.grffile != NULL) ? indsp->grf_prop.grffile->grfid : 0; + uint32 grfid = (indsp->grf_prop.grffile != nullptr) ? indsp->grf_prop.grffile->grfid : 0; assert(PersistentStorage::CanAllocateItem()); this->industry->psa = new PersistentStorage(grfid, GSF_INDUSTRIES, this->industry->location.tile); } @@ -439,7 +445,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout static const GRFFile *GetGrffile(IndustryType type) { const IndustrySpec *indspec = GetIndustrySpec(type); - return (indspec != NULL) ? indspec->grf_prop.grffile : NULL; + return (indspec != nullptr) ? indspec->grf_prop.grffile : nullptr; } /** @@ -456,7 +462,7 @@ IndustriesResolverObject::IndustriesResolverObject(TileIndex tile, Industry *ind CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(GetGrffile(type), callback, callback_param1, callback_param2), industries_scope(*this, tile, indus, type, random_bits), - town_scope(NULL) + town_scope(nullptr) { this->root_spritegroup = GetIndustrySpec(type)->grf_prop.spritegroup[0]; } @@ -472,16 +478,16 @@ IndustriesResolverObject::~IndustriesResolverObject() */ TownScopeResolver *IndustriesResolverObject::GetTown() { - if (this->town_scope == NULL) { - Town *t = NULL; + if (this->town_scope == nullptr) { + Town *t = nullptr; bool readonly = true; - if (this->industries_scope.industry != NULL) { + if (this->industries_scope.industry != nullptr) { t = this->industries_scope.industry->town; readonly = this->industries_scope.industry->index == INVALID_INDUSTRY; } else if (this->industries_scope.tile != INVALID_TILE) { t = ClosestTownFromTile(this->industries_scope.tile, UINT_MAX); } - if (t == NULL) return NULL; + if (t == nullptr) return nullptr; this->town_scope = new TownScopeResolver(*this, t, readonly); } return this->town_scope; @@ -514,7 +520,7 @@ uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, In * @param creation_type The circumstances the industry is created under. * @return Succeeded or failed command. */ -CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type) +CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, size_t layout, uint32 seed, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type) { const IndustrySpec *indspec = GetIndustrySpec(type); @@ -523,11 +529,11 @@ CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uin ind.location.tile = tile; ind.location.w = 0; // important to mark the industry invalid ind.type = type; - ind.selected_layout = layout; + ind.selected_layout = (byte)layout; ind.town = ClosestTownFromTile(tile, UINT_MAX); ind.random = initial_random_bits; ind.founder = founder; - ind.psa = NULL; + ind.psa = nullptr; IndustriesResolverObject object(tile, &ind, type, seed, CBID_INDUSTRY_LOCATION, 0, creation_type); uint16 result = object.ResolveCallback(); @@ -550,7 +556,7 @@ uint32 GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCal const IndustrySpec *indspec = GetIndustrySpec(type); if (HasBit(indspec->callback_mask, CBM_IND_PROBABILITY)) { - uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROBABILITY, 0, creation_type, NULL, type, INVALID_TILE); + uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROBABILITY, 0, creation_type, nullptr, type, INVALID_TILE); if (res != CALLBACK_FAILED) { if (indspec->grf_prop.grffile->grf_version < 8) { /* Disallow if result != 0 */ @@ -602,7 +608,7 @@ void IndustryProductionCallback(Industry *ind, int reason) SB(object.callback_param2, 8, 16, loop); const SpriteGroup *tgroup = object.Resolve(); - if (tgroup == NULL || tgroup->type != SGT_INDUSTRY_PRODUCTION) break; + if (tgroup == nullptr || tgroup->type != SGT_INDUSTRY_PRODUCTION) break; const IndustryProductionSpriteGroup *group = (const IndustryProductionSpriteGroup *)tgroup; if (group->version == 0xFF) { diff --git a/src/newgrf_industries.h b/src/newgrf_industries.h index fa809fcd73..d66ab319b8 100644 --- a/src/newgrf_industries.h +++ b/src/newgrf_industries.h @@ -34,16 +34,16 @@ struct IndustriesScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; - /* virtual */ uint32 GetTriggers() const; - /* virtual */ void StorePSA(uint pos, int32 value); + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetTriggers() const override; + void StorePSA(uint pos, int32 value) override; }; /** Resolver for industries. */ struct IndustriesResolverObject : public ResolverObject { IndustriesScopeResolver industries_scope; ///< Scope resolver for the industry. - TownScopeResolver *town_scope; ///< Scope resolver for the associated town (if needed and available, else \c NULL). + TownScopeResolver *town_scope; ///< Scope resolver for the associated town (if needed and available, else \c nullptr). IndustriesResolverObject(TileIndex tile, Industry *indus, IndustryType type, uint32 random_bits = 0, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); @@ -51,13 +51,13 @@ struct IndustriesResolverObject : public ResolverObject { TownScopeResolver *GetTown(); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &industries_scope; case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); - if (tsr != NULL) return tsr; + if (tsr != nullptr) return tsr; } FALLTHROUGH; @@ -89,7 +89,7 @@ enum IndustryAvailabilityCallType { uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, Industry *industry, IndustryType type, TileIndex tile); uint32 GetIndustryIDAtOffset(TileIndex new_tile, const Industry *i, uint32 cur_grfid); void IndustryProductionCallback(Industry *ind, int reason); -CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type); +CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, size_t layout, uint32 seed, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type); uint32 GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32 default_prob); bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type); diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp index 0b2a55000e..d5b2ee3258 100644 --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -80,7 +80,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) /* Land info of nearby tiles */ case 0x60: return GetNearbyIndustryTileInformation(parameter, this->tile, - this->industry == NULL ? (IndustryID)INVALID_INDUSTRY : this->industry->index, true, this->ro.grffile->grf_version >= 8); + this->industry == nullptr ? (IndustryID)INVALID_INDUSTRY : this->industry->index, true, this->ro.grffile->grf_version >= 8); /* Animation stage of nearby tiles */ case 0x61: { @@ -103,7 +103,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) /* virtual */ uint32 IndustryTileScopeResolver::GetRandomBits() const { - assert(this->industry != NULL && IsValidTile(this->tile)); + assert(this->industry != nullptr && IsValidTile(this->tile)); assert(this->industry->index == INVALID_INDUSTRY || IsTileType(this->tile, MP_INDUSTRY)); return (this->industry->index != INVALID_INDUSTRY) ? GetIndustryRandomBits(this->tile) : 0; @@ -111,7 +111,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) /* virtual */ uint32 IndustryTileScopeResolver::GetTriggers() const { - assert(this->industry != NULL && IsValidTile(this->tile)); + assert(this->industry != nullptr && IsValidTile(this->tile)); assert(this->industry->index == INVALID_INDUSTRY || IsTileType(this->tile, MP_INDUSTRY)); if (this->industry->index == INVALID_INDUSTRY) return 0; return GetIndustryTriggers(this->tile); @@ -125,7 +125,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) static const GRFFile *GetIndTileGrffile(IndustryGfx gfx) { const IndustryTileSpec *its = GetIndustryTileSpec(gfx); - return (its != NULL) ? its->grf_prop.grffile : NULL; + return (its != nullptr) ? its->grf_prop.grffile : nullptr; } /** @@ -171,7 +171,7 @@ static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGro uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile) { - assert(industry != NULL && IsValidTile(tile)); + assert(industry != nullptr && IsValidTile(tile)); assert(industry->index == INVALID_INDUSTRY || IsTileType(tile, MP_INDUSTRY)); IndustryTileResolverObject object(gfx_id, tile, industry, callback, param1, param2); @@ -194,7 +194,7 @@ bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const Indus IndustryTileResolverObject object(gfx, ti->tile, i); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->type != SGT_TILELAYOUT) return false; + if (group == nullptr || group->type != SGT_TILELAYOUT) return false; /* Limit the building stage to the number of stages supplied. */ const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group; @@ -212,13 +212,13 @@ extern bool IsSlopeRefused(Slope current, Slope refused); * @param its Tile specification. * @param type Industry type. * @param gfx Gfx of the tile. - * @param itspec_index Layout. + * @param layout_index Layout. * @param initial_random_bits Random bits of industry after construction * @param founder Industry founder * @param creation_type The circumstances the industry is created under. * @return Succeeded or failed command. */ -CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type) +CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, size_t layout_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type) { Industry ind; ind.index = INVALID_INDUSTRY; @@ -228,7 +228,7 @@ CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind ind.random = initial_random_bits; ind.founder = founder; - uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_SHAPE_CHECK, 0, creation_type << 8 | itspec_index, gfx, &ind, ind_tile); + uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_SHAPE_CHECK, 0, creation_type << 8 | (uint32)layout_index, gfx, &ind, ind_tile); if (callback_res == CALLBACK_FAILED) { if (!IsSlopeRefused(GetTileSlope(ind_tile), its->slopes_refused)) return CommandCost(); return_cmd_error(STR_ERROR_SITE_UNSUITABLE); @@ -259,7 +259,7 @@ struct IndustryAnimationBase : public AnimationBasespecial_flags & INDTILE_SPECIAL_NEXTFRAME_RANDOMBITS) != 0); } @@ -305,14 +305,14 @@ static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, I IndustryGfx gfx = GetIndustryGfx(tile); const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); - if (itspec->grf_prop.spritegroup[0] == NULL) return; + if (itspec->grf_prop.spritegroup[0] == nullptr) return; IndustryTileResolverObject object(gfx, tile, ind, CBID_RANDOM_TRIGGER); object.waiting_triggers = GetIndustryTriggers(tile) | trigger; SetIndustryTriggers(tile, object.waiting_triggers); // store now for var 5F const SpriteGroup *group = object.Resolve(); - if (group == NULL) return; + if (group == nullptr) return; /* Store remaining triggers. */ SetIndustryTriggers(tile, object.GetRemainingTriggers()); @@ -335,7 +335,7 @@ static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, I */ static void DoReseedIndustry(Industry *ind, uint32 reseed) { - if (reseed == 0 || ind == NULL) return; + if (reseed == 0 || ind == nullptr) return; uint16 random_bits = Random(); ind->random &= reseed; diff --git a/src/newgrf_industrytiles.h b/src/newgrf_industrytiles.h index 6051c1062b..9370853052 100644 --- a/src/newgrf_industrytiles.h +++ b/src/newgrf_industrytiles.h @@ -32,9 +32,9 @@ struct IndustryTileScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; - /* virtual */ uint32 GetTriggers() const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; + uint32 GetTriggers() const override; }; /** Resolver for industry tiles. */ @@ -45,7 +45,7 @@ struct IndustryTileResolverObject : public ResolverObject { IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &indtile_scope; @@ -57,7 +57,7 @@ struct IndustryTileResolverObject : public ResolverObject { bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds); uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile); -CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type); +CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, size_t layout_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type); void AnimateNewIndustryTile(TileIndex tile); bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random = Random()); diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index 1501cb9b8a..6038f092f2 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -151,7 +151,7 @@ static uint32 GetObjectIDAtOffset(TileIndex tile, uint32 cur_grfid) const ObjectSpec *spec = ObjectSpec::Get(o->type); /* Default objects have no associated NewGRF file */ - if (spec->grf_prop.grffile == NULL) { + if (spec->grf_prop.grffile == nullptr) { return 0xFFFE; // Defined in another grf file } @@ -237,9 +237,9 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, { /* We get the town from the object, or we calculate the closest * town if we need to when there's no object. */ - const Town *t = NULL; + const Town *t = nullptr; - if (this->obj == NULL) { + if (this->obj == nullptr) { switch (variable) { /* Allow these when there's no object. */ case 0x41: @@ -325,7 +325,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, } /* Land info of nearby tiles */ - case 0x62: return GetNearbyObjectTileInformation(parameter, this->tile, this->obj == NULL ? INVALID_OBJECT : this->obj->index, this->ro.grffile->grf_version >= 8); + case 0x62: return GetNearbyObjectTileInformation(parameter, this->tile, this->obj == nullptr ? INVALID_OBJECT : this->obj->index, this->ro.grffile->grf_version >= 8); /* Animation counter of nearby tile */ case 0x63: { @@ -357,8 +357,8 @@ ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, CallbackID callback, uint32 param1, uint32 param2) : ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(*this, obj, tile, view) { - this->town_scope = NULL; - this->root_spritegroup = (obj == NULL && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != NULL) ? + this->town_scope = nullptr; + this->root_spritegroup = (obj == nullptr && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != nullptr) ? spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] : spec->grf_prop.spritegroup[0]; } @@ -374,15 +374,15 @@ ObjectResolverObject::~ObjectResolverObject() */ TownScopeResolver *ObjectResolverObject::GetTown() { - if (this->town_scope == NULL) { + if (this->town_scope == nullptr) { Town *t; - if (this->object_scope.obj != NULL) { + if (this->object_scope.obj != nullptr) { t = this->object_scope.obj->town; } else { t = ClosestTownFromTile(this->object_scope.tile, UINT_MAX); } - if (t == NULL) return NULL; - this->town_scope = new TownScopeResolver(*this, t, this->object_scope.obj == NULL); + if (t == nullptr) return nullptr; + this->town_scope = new TownScopeResolver(*this, t, this->object_scope.obj == nullptr); } return this->town_scope; } @@ -395,7 +395,7 @@ TownScopeResolver *ObjectResolverObject::GetTown() * @param spec The specification of the object / the entry point. * @param o The object to call the callback for. * @param tile The tile the callback is called for. - * @param view The view of the object (only used when o == NULL). + * @param view The view of the object (only used when o == nullptr). * @return The result of the callback. */ uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view) @@ -412,7 +412,7 @@ uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, cons */ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec) { - const DrawTileSprites *dts = group->ProcessRegisters(NULL); + const DrawTileSprites *dts = group->ProcessRegisters(nullptr); PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour; SpriteID image = dts->ground.sprite; @@ -442,7 +442,7 @@ void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec) ObjectResolverObject object(spec, o, ti->tile); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->type != SGT_TILELAYOUT) return; + if (group == nullptr || group->type != SGT_TILELAYOUT) return; DrawTileLayout(ti, (const TileLayoutSpriteGroup *)group, spec); } @@ -456,11 +456,11 @@ void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec) */ void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view) { - ObjectResolverObject object(spec, NULL, INVALID_TILE, view); + ObjectResolverObject object(spec, nullptr, INVALID_TILE, view); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->type != SGT_TILELAYOUT) return; + if (group == nullptr || group->type != SGT_TILELAYOUT) return; - const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(NULL); + const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(nullptr); PaletteID palette; if (Company::IsValidID(_local_company)) { @@ -518,7 +518,7 @@ struct ObjectAnimationBase : public AnimationBaseflags & OBJECT_FLAG_ANIMATION)) return; + if (spec == nullptr || !(spec->flags & OBJECT_FLAG_ANIMATION)) return; ObjectAnimationBase::AnimateTile(spec, Object::GetByTile(tile), tile, (spec->flags & OBJECT_FLAG_ANIM_RANDOM_BITS) != 0); } diff --git a/src/newgrf_object.h b/src/newgrf_object.h index 43c8de031c..dcc5caa8b5 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -116,8 +116,8 @@ struct ObjectScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; }; /** A resolver object to be used with feature 0F spritegroups. */ @@ -129,7 +129,7 @@ struct ObjectResolverObject : public ResolverObject { CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0); ~ObjectResolverObject(); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: @@ -137,7 +137,7 @@ struct ObjectResolverObject : public ResolverObject { case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); - if (tsr != NULL) return tsr; + if (tsr != nullptr) return tsr; FALLTHROUGH; } diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 8421844717..63121c1e8e 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -44,13 +44,13 @@ if (IsRailDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date; return _date; case 0x44: { - const Town *t = NULL; + const Town *t = nullptr; if (IsRailDepotTile(this->tile)) { t = Depot::GetByTile(this->tile)->town; } else if (IsLevelCrossingTile(this->tile)) { t = ClosestTownFromTile(this->tile, UINT_MAX); } - return t != NULL ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; + return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; } } @@ -64,12 +64,12 @@ { if (group->num_loading > 0) return group->loading[0]; if (group->num_loaded > 0) return group->loaded[0]; - return NULL; + return nullptr; } /** * Resolver object for rail types. - * @param rti Railtype. NULL in NewGRF Inspect window. + * @param rti Railtype. nullptr in NewGRF Inspect window. * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. * @param context Are we resolving sprites for the upper halftile, or on a bridge? * @param rtsg Railpart of interest @@ -77,9 +77,9 @@ * @param param2 Extra parameter (second parameter of the callback, except railtypes do not have callbacks). */ RailTypeResolverObject::RailTypeResolverObject(const RailtypeInfo *rti, TileIndex tile, TileContext context, RailTypeSpriteGroup rtsg, uint32 param1, uint32 param2) - : ResolverObject(rti != NULL ? rti->grffile[rtsg] : NULL, CBID_NO_CALLBACK, param1, param2), railtype_scope(*this, tile, context) + : ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), railtype_scope(*this, tile, context) { - this->root_spritegroup = rti != NULL ? rti->group[rtsg] : NULL; + this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr; } /** @@ -88,18 +88,18 @@ RailTypeResolverObject::RailTypeResolverObject(const RailtypeInfo *rti, TileInde * @param tile The tile to get the sprite for. * @param rtsg The type of sprite to draw. * @param context Where are we drawing the tile? - * @param[out] num_results If not NULL, return the number of sprites in the spriteset. + * @param[out] num_results If not nullptr, return the number of sprites in the spriteset. * @return The sprite to draw. */ SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context, uint *num_results) { assert(rtsg < RTSG_END); - if (rti->group[rtsg] == NULL) return 0; + if (rti->group[rtsg] == nullptr) return 0; RailTypeResolverObject object(rti, tile, context, rtsg); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->GetNumResults() == 0) return 0; + if (group == nullptr || group->GetNumResults() == 0) return 0; if (num_results) *num_results = group->GetNumResults(); @@ -118,14 +118,14 @@ SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSp */ SpriteID GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, SignalState state, bool gui) { - if (rti->group[RTSG_SIGNALS] == NULL) return 0; + if (rti->group[RTSG_SIGNALS] == nullptr) return 0; uint32 param1 = gui ? 0x10 : 0x00; uint32 param2 = (type << 16) | (var << 8) | state; RailTypeResolverObject object(rti, tile, TCX_NORMAL, RTSG_SIGNALS, param1, param2); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->GetNumResults() == 0) return 0; + if (group == nullptr || group->GetNumResults() == 0) return 0; return group->GetResult(); } @@ -139,12 +139,13 @@ SpriteID GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalTy uint8 GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile) { /* No rail type table present, return rail type as-is */ - if (grffile == NULL || grffile->railtype_list.Length() == 0) return railtype; + if (grffile == nullptr || grffile->railtype_list.size() == 0) return railtype; /* Look for a matching rail type label in the table */ RailTypeLabel label = GetRailTypeInfo(railtype)->label; - int index = grffile->railtype_list.FindIndex(label); - if (index >= 0) return index; + + int idx = find_index(grffile->railtype_list, label); + if (idx >= 0) return idx; /* If not found, return as invalid */ return 0xFF; diff --git a/src/newgrf_railtype.h b/src/newgrf_railtype.h index 5fadcd2ab5..ddcbd71aeb 100644 --- a/src/newgrf_railtype.h +++ b/src/newgrf_railtype.h @@ -32,8 +32,8 @@ struct RailTypeScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + uint32 GetRandomBits() const override; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; }; /** Resolver object for rail types. */ @@ -42,7 +42,7 @@ struct RailTypeResolverObject : public ResolverObject { RailTypeResolverObject(const RailtypeInfo *rti, TileIndex tile, TileContext context, RailTypeSpriteGroup rtsg, uint32 param1 = 0, uint32 param2 = 0); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &this->railtype_scope; @@ -50,10 +50,10 @@ struct RailTypeResolverObject : public ResolverObject { } } - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; -SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = NULL); +SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr); SpriteID GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, SignalState state, bool gui = false); uint8 GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile); diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp new file mode 100644 index 0000000000..1fb8e5ec1a --- /dev/null +++ b/src/newgrf_roadtype.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 newgrf_roadtype.cpp NewGRF handling of road types. */ + +#include "stdafx.h" +#include "debug.h" +#include "newgrf_roadtype.h" +#include "date_func.h" +#include "depot_base.h" +#include "town.h" + +#include "safeguards.h" + +/* virtual */ uint32 RoadTypeScopeResolver::GetRandomBits() const +{ + uint tmp = CountBits(this->tile + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE); + return GB(tmp, 0, 2); +} + +/* virtual */ uint32 RoadTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const +{ + if (this->tile == INVALID_TILE) { + switch (variable) { + case 0x40: return 0; + case 0x41: return 0; + case 0x42: return 0; + case 0x43: return _date; + case 0x44: return HZB_TOWN_EDGE; + } + } + + switch (variable) { + case 0x40: return GetTerrainType(this->tile, this->context); + case 0x41: return 0; + case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile); + case 0x43: + if (IsRoadDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date; + return _date; + case 0x44: { + const Town *t = nullptr; + if (IsRoadDepotTile(this->tile)) { + t = Depot::GetByTile(this->tile)->town; + } else if (IsTileType(this->tile, MP_ROAD)) { + t = ClosestTownFromTile(this->tile, UINT_MAX); + } + return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; + } + } + + DEBUG(grf, 1, "Unhandled road type tile variable 0x%X", variable); + + *available = false; + return UINT_MAX; +} + +/* virtual */ const SpriteGroup *RoadTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const +{ + if (group->num_loading > 0) return group->loading[0]; + if (group->num_loaded > 0) return group->loaded[0]; + return nullptr; +} + +/** + * Constructor of the roadtype scope resolvers. + * @param ro Surrounding resolver. + * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. + * @param context Are we resolving sprites for the upper halftile, or on a bridge? + */ +RoadTypeScopeResolver::RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context) : ScopeResolver(ro) +{ + this->tile = tile; + this->context = context; +} + +/** + * Resolver object for road types. + * @param rti Roadtype. nullptr in NewGRF Inspect window. + * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. + * @param context Are we resolving sprites for the upper halftile, or on a bridge? + * @param rtsg Roadpart of interest + * @param param1 Extra parameter (first parameter of the callback, except roadtypes do not have callbacks). + * @param param2 Extra parameter (second parameter of the callback, except roadtypes do not have callbacks). + */ +RoadTypeResolverObject::RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1, uint32 param2) + : ResolverObject(rti != nullptr ? rti->grffile[rtsg] : nullptr, CBID_NO_CALLBACK, param1, param2), roadtype_scope(*this, tile, context) +{ + this->root_spritegroup = rti != nullptr ? rti->group[rtsg] : nullptr; +} + +/** + * Get the sprite to draw for the given tile. + * @param rti The road type data (spec). + * @param tile The tile to get the sprite for. + * @param rtsg The type of sprite to draw. + * @param content Where are we drawing the tile? + * @param [out] num_results If not nullptr, return the number of sprites in the spriteset. + * @return The sprite to draw. + */ +SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context, uint *num_results) +{ + assert(rtsg < ROTSG_END); + + if (rti->group[rtsg] == nullptr) return 0; + + RoadTypeResolverObject object(rti, tile, context, rtsg); + const SpriteGroup *group = object.Resolve(); + if (group == nullptr || group->GetNumResults() == 0) return 0; + + if (num_results) *num_results = group->GetNumResults(); + + return group->GetResult(); +} + +/** + * Perform a reverse roadtype lookup to get the GRF internal ID. + * @param roadtype The global (OpenTTD) roadtype. + * @param grffile The GRF to do the lookup for. + * @return the GRF internal ID. + */ +uint8 GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile) +{ + /* No road type table present, return road type as-is */ + if (grffile == nullptr) return roadtype; + + const std::vector *list = RoadTypeIsRoad(roadtype) ? &grffile->roadtype_list : &grffile->tramtype_list; + if (list->size() == 0) return roadtype; + + /* Look for a matching road type label in the table */ + RoadTypeLabel label = GetRoadTypeInfo(roadtype)->label; + + int index = find_index(*list, label); + if (index >= 0) return index; + + /* If not found, return as invalid */ + return 0xFF; +} diff --git a/src/newgrf_roadtype.h b/src/newgrf_roadtype.h new file mode 100644 index 0000000000..2da7a82c1f --- /dev/null +++ b/src/newgrf_roadtype.h @@ -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 newgrf_roadtype.h NewGRF handling of road types. */ + +#ifndef NEWGRF_ROADTYPE_H +#define NEWGRF_ROADTYPE_H + +#include "road.h" +#include "newgrf_commons.h" +#include "newgrf_spritegroup.h" + +/** Resolver for the railtype scope. */ +struct RoadTypeScopeResolver : public ScopeResolver { + TileIndex tile; ///< Tracktile. For track on a bridge this is the southern bridgehead. + TileContext context; ///< Are we resolving sprites for the upper halftile, or on a bridge? + + RoadTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context); + + /* virtual */ uint32 GetRandomBits() const; + /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; +}; + +/** Resolver object for road types. */ +struct RoadTypeResolverObject : public ResolverObject { + RoadTypeScopeResolver roadtype_scope; ///< Resolver for the roadtype scope. + + RoadTypeResolverObject(const RoadTypeInfo *rti, TileIndex tile, TileContext context, RoadTypeSpriteGroup rtsg, uint32 param1 = 0, uint32 param2 = 0); + + /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + { + switch (scope) { + case VSG_SCOPE_SELF: return &this->roadtype_scope; + default: return ResolverObject::GetScope(scope, relative); + } + } + + /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; +}; + +SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSpriteGroup rtsg, TileContext context = TCX_NORMAL, uint *num_results = nullptr); + +uint8 GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile); + +#endif /* NEWGRF_ROADTYPE_H */ diff --git a/src/newgrf_sound.cpp b/src/newgrf_sound.cpp index 0cc113d9df..0756d798f7 100644 --- a/src/newgrf_sound.cpp +++ b/src/newgrf_sound.cpp @@ -22,7 +22,7 @@ #include "safeguards.h" -static SmallVector _sounds; +static std::vector _sounds; /** @@ -32,15 +32,15 @@ static SmallVector _sounds; */ SoundEntry *AllocateSound(uint num) { - SoundEntry *sound = _sounds.Append(num); - MemSetT(sound, 0, num); - return sound; + size_t pos = _sounds.size(); + _sounds.insert(_sounds.end(), num, SoundEntry()); + return &_sounds[pos]; } void InitializeSoundPool() { - _sounds.Clear(); + _sounds.clear(); /* Copy original sound data to the pool */ SndCopyToPool(); @@ -49,14 +49,14 @@ void InitializeSoundPool() SoundEntry *GetSound(SoundID index) { - if (index >= _sounds.Length()) return NULL; + if (index >= _sounds.size()) return nullptr; return &_sounds[index]; } uint GetNumSounds() { - return _sounds.Length(); + return (uint)_sounds.size(); } @@ -173,7 +173,7 @@ SoundID GetNewGRFSoundID(const GRFFile *file, SoundID sound_id) if (sound_id < ORIGINAL_SAMPLE_COUNT) return sound_id; sound_id -= ORIGINAL_SAMPLE_COUNT; - if (file == NULL || sound_id >= file->num_sounds) return INVALID_SOUND; + if (file == nullptr || sound_id >= file->num_sounds) return INVALID_SOUND; return file->sound_offset + sound_id; } @@ -192,7 +192,7 @@ bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event) uint16 callback; /* If the engine has no GRF ID associated it can't ever play any new sounds */ - if (file == NULL) return false; + if (file == nullptr) return false; /* Check that the vehicle type uses the sound effect callback */ if (!HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_SOUND_EFFECT)) return false; diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index d8a10914cc..9e8ec0b55f 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -26,7 +26,7 @@ TemporaryStorageArray _temp_store; /** * ResolverObject (re)entry point. * This cannot be made a call to a virtual function because virtual functions - * do not like NULL and checking for NULL *everywhere* is more cumbersome than + * do not like nullptr and checking for nullptr *everywhere* is more cumbersome than * this little helper function. * @param group the group to resolve for * @param object information needed to resolve the group @@ -35,7 +35,7 @@ TemporaryStorageArray _temp_store; */ /* static */ const SpriteGroup *SpriteGroup::Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level) { - if (group == NULL) return NULL; + if (group == nullptr) return nullptr; if (top_level) { _temp_store.ClearChanges(); } @@ -73,7 +73,7 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc case 0x7D: return _temp_store.GetValue(parameter); case 0x7F: - if (object.grffile == NULL) return 0; + if (object.grffile == nullptr) return 0; return object.grffile->GetParam(parameter); default: @@ -130,7 +130,7 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc */ /* virtual */ const SpriteGroup *ResolverObject::ResolveReal(const RealSpriteGroup *group) const { - return NULL; + return nullptr; } /** @@ -208,7 +208,7 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con bool available = true; if (adjust->variable == 0x7E) { const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object, false); - if (subgroup == NULL) { + if (subgroup == nullptr) { value = CALLBACK_FAILED; } else { value = subgroup->GetCallbackResult(); @@ -294,24 +294,24 @@ const SpriteGroup *RealSpriteGroup::Resolve(ResolverObject &object) const * Process registers and the construction stage into the sprite layout. * The passed construction stage might get reset to zero, if it gets incorporated into the layout * during the preprocessing. - * @param[in,out] stage Construction stage (0-3), or NULL if not applicable. + * @param[in,out] stage Construction stage (0-3), or nullptr if not applicable. * @return sprite layout to draw. */ const DrawTileSprites *TileLayoutSpriteGroup::ProcessRegisters(uint8 *stage) const { if (!this->dts.NeedsPreprocessing()) { - if (stage != NULL && this->dts.consistent_max_offset > 0) *stage = GetConstructionStageOffset(*stage, this->dts.consistent_max_offset); + if (stage != nullptr && this->dts.consistent_max_offset > 0) *stage = GetConstructionStageOffset(*stage, this->dts.consistent_max_offset); return &this->dts; } static DrawTileSprites result; - uint8 actual_stage = stage != NULL ? *stage : 0; + uint8 actual_stage = stage != nullptr ? *stage : 0; this->dts.PrepareLayout(0, 0, 0, actual_stage, false); this->dts.ProcessRegisters(0, 0, false); result.seq = this->dts.GetLayout(&result.ground); /* Stage has been processed by PrepareLayout(), set it to zero. */ - if (stage != NULL) *stage = 0; + if (stage != nullptr) *stage = 0; return &result; } diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 2db78f6bad..55fb0b58fb 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -316,13 +316,13 @@ struct ScopeResolver { struct ResolverObject { /** * Resolver constructor. - * @param grffile NewGRF file associated with the object (or \c NULL if none). + * @param grffile NewGRF file associated with the object (or \c nullptr if none). * @param callback Callback code being resolved (default value is #CBID_NO_CALLBACK). * @param callback_param1 First parameter (var 10) of the callback (only used when \a callback is also set). * @param callback_param2 Second parameter (var 18) of the callback (only used when \a callback is also set). */ ResolverObject(const GRFFile *grffile, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0) - : default_scope(*this), callback(callback), callback_param1(callback_param1), callback_param2(callback_param2), grffile(grffile), root_spritegroup(NULL) + : default_scope(*this), callback(callback), callback_param1(callback_param1), callback_param2(callback_param2), grffile(grffile), root_spritegroup(nullptr) { this->ResetState(); } @@ -360,7 +360,7 @@ struct ResolverObject { uint16 ResolveCallback() { const SpriteGroup *result = Resolve(); - return result != NULL ? result->GetCallbackResult() : CALLBACK_FAILED; + return result != nullptr ? result->GetCallbackResult() : CALLBACK_FAILED; } virtual const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index d9b79c55a1..8b6e87bca6 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -35,11 +35,11 @@ template /* Set up initial data */ classes[0].global_id = 'DFLT'; classes[0].name = STR_STATION_CLASS_DFLT; - classes[0].Insert(NULL); + classes[0].Insert(nullptr); classes[1].global_id = 'WAYP'; classes[1].name = STR_STATION_CLASS_WAYP; - classes[1].Insert(NULL); + classes[1].Insert(nullptr); } template @@ -225,13 +225,13 @@ static uint32 GetRailContinuationInfo(TileIndex tile) /* Station Resolver Functions */ /* virtual */ uint32 StationScopeResolver::GetRandomBits() const { - return (this->st == NULL ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16); + return (this->st == nullptr ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16); } /* virtual */ uint32 StationScopeResolver::GetTriggers() const { - return this->st == NULL ? 0 : this->st->waiting_triggers; + return this->st == nullptr ? 0 : this->st->waiting_triggers; } @@ -257,22 +257,22 @@ static struct { */ TownScopeResolver *StationResolverObject::GetTown() { - if (this->town_scope == NULL) { - Town *t = NULL; - if (this->station_scope.st != NULL) { + if (this->town_scope == nullptr) { + Town *t = nullptr; + if (this->station_scope.st != nullptr) { t = this->station_scope.st->town; } else if (this->station_scope.tile != INVALID_TILE) { t = ClosestTownFromTile(this->station_scope.tile, UINT_MAX); } - if (t == NULL) return NULL; - this->town_scope = new TownScopeResolver(*this, t, this->station_scope.st == NULL); + if (t == nullptr) return nullptr; + this->town_scope = new TownScopeResolver(*this, t, this->station_scope.st == nullptr); } return this->town_scope; } /* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { - if (this->st == NULL) { + if (this->st == nullptr) { /* Station does not exist, so we're in a purchase list or the land slope check callback. */ switch (variable) { case 0x40: @@ -396,8 +396,8 @@ uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, b case 0x8A: return this->had_vehicle_of_type; case 0xF1: return (this->airport.tile != INVALID_TILE) ? this->airport.GetSpec()->ttd_airport_type : ATP_TTDP_LARGE; - case 0xF2: return (this->truck_stops != NULL) ? this->truck_stops->status : 0; - case 0xF3: return (this->bus_stops != NULL) ? this->bus_stops->status : 0; + case 0xF2: return (this->truck_stops != nullptr) ? this->truck_stops->status : 0; + case 0xF3: return (this->bus_stops != nullptr) ? this->bus_stops->status : 0; case 0xF6: return this->airport.flags; case 0xF7: return GB(this->airport.flags, 8, 8); } @@ -486,7 +486,7 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject &object, byte variable, /* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (this->station_scope.st == NULL || this->station_scope.statspec->cls_id == STAT_CLASS_WAYP) { + if (this->station_scope.st == nullptr || this->station_scope.statspec->cls_id == STAT_CLASS_WAYP) { return group->loading[0]; } @@ -541,14 +541,14 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject &object, byte variable, StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseStation *st, TileIndex tile, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(statspec->grf_prop.grffile, callback, callback_param1, callback_param2), - station_scope(*this, statspec, st, tile), town_scope(NULL) + station_scope(*this, statspec, st, tile), town_scope(nullptr) { /* Invalidate all cached vars */ _svc.valid = 0; CargoID ctype = CT_DEFAULT_NA; - if (this->station_scope.st == NULL) { + if (this->station_scope.st == nullptr) { /* No station, so we are in a purchase list */ ctype = CT_PURCHASE; } else if (Station::IsExpected(this->station_scope.st)) { @@ -556,7 +556,7 @@ StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseSt /* Pick the first cargo that we have waiting */ const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { - if (this->station_scope.statspec->grf_prop.spritegroup[cs->Index()] != NULL && + if (this->station_scope.statspec->grf_prop.spritegroup[cs->Index()] != nullptr && st->goods[cs->Index()].cargo.TotalCount() > 0) { ctype = cs->Index(); break; @@ -564,7 +564,7 @@ StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseSt } } - if (this->station_scope.statspec->grf_prop.spritegroup[ctype] == NULL) { + if (this->station_scope.statspec->grf_prop.spritegroup[ctype] == nullptr) { ctype = CT_DEFAULT; } @@ -581,7 +581,7 @@ StationResolverObject::~StationResolverObject() /** * Resolve sprites for drawing a station tile. * @param statspec Station spec - * @param st Station (NULL in GUI) + * @param st Station (nullptr in GUI) * @param tile Station tile being drawn (INVALID_TILE in GUI) * @param var10 Value to put in variable 10; normally 0; 1 when resolving the groundsprite and SSF_SEPARATE_GROUND is set. * @return First sprite of the Action 1 spriteset to use, minus an offset of 0x42D to accommodate for weird NewGRF specs. @@ -590,7 +590,7 @@ SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st { StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, var10); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->type != SGT_RESULT) return 0; + if (group == nullptr || group->type != SGT_RESULT) return 0; return group->GetResult() - 0x42D; } @@ -609,7 +609,7 @@ SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseS StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, 2, layout | (edge_info << 16)); const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->type != SGT_RESULT) return 0; + if (group == nullptr || group->type != SGT_RESULT) return 0; /* Note: SpriteGroup::Resolve zeroes all registers, so register 0x100 is initialised to 0. (compatibility) */ return group->GetResult() + GetRegister(0x100); @@ -637,7 +637,7 @@ CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_til TileIndexDiff diff = cur_tile - north_tile; Slope slope = GetTileSlope(cur_tile); - StationResolverObject object(statspec, NULL, cur_tile, CBID_STATION_LAND_SLOPE_CHECK, + StationResolverObject object(statspec, nullptr, cur_tile, CBID_STATION_LAND_SLOPE_CHECK, (slope << 4) | (slope ^ (axis == AXIS_Y && HasBit(slope, CORNER_W) != HasBit(slope, CORNER_E) ? SLOPE_EW : 0)), (numtracks << 24) | (plat_len << 16) | (axis == AXIS_Y ? TileX(diff) << 8 | TileY(diff) : TileY(diff) << 8 | TileX(diff))); object.station_scope.axis = axis; @@ -664,10 +664,10 @@ int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exe { uint i; - if (statspec == NULL || st == NULL) return 0; + if (statspec == nullptr || st == nullptr) return 0; for (i = 1; i < st->num_specs && i < NUM_STATIONSSPECS_PER_STATION; i++) { - if (st->speclist[i].spec == NULL && st->speclist[i].grfid == 0) break; + if (st->speclist[i].spec == nullptr && st->speclist[i].grfid == 0) break; } if (i == NUM_STATIONSSPECS_PER_STATION) { @@ -690,7 +690,7 @@ int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exe if (st->num_specs == 2) { /* Initial allocation */ - st->speclist[0].spec = NULL; + st->speclist[0].spec = nullptr; st->speclist[0].grfid = 0; st->speclist[0].localidx = 0; } @@ -727,7 +727,7 @@ void DeallocateSpecFromStation(BaseStation *st, byte specindex) } /* This specindex is no longer in use, so deallocate it */ - st->speclist[specindex].spec = NULL; + st->speclist[specindex].spec = nullptr; st->speclist[specindex].grfid = 0; st->speclist[specindex].localidx = 0; @@ -740,7 +740,7 @@ void DeallocateSpecFromStation(BaseStation *st, byte specindex) } else { free(st->speclist); st->num_specs = 0; - st->speclist = NULL; + st->speclist = nullptr; st->cached_anim_triggers = 0; st->cached_cargo_triggers = 0; return; @@ -762,42 +762,42 @@ void DeallocateSpecFromStation(BaseStation *st, byte specindex) */ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station) { - const DrawTileSprites *sprites = NULL; + const DrawTileSprites *sprites = nullptr; const RailtypeInfo *rti = GetRailTypeInfo(railtype); PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); uint tile = 2; const StationSpec *statspec = StationClass::Get(sclass)->GetSpec(station); - if (statspec == NULL) return false; + if (statspec == nullptr) return false; if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) { - uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, statspec, NULL, INVALID_TILE); + uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, statspec, nullptr, INVALID_TILE); if (callback != CALLBACK_FAILED) tile = callback; } uint32 total_offset = rti->GetRailtypeSpriteOffset(); uint32 relocation = 0; uint32 ground_relocation = 0; - const NewGRFSpriteLayout *layout = NULL; + const NewGRFSpriteLayout *layout = nullptr; DrawTileSprites tmp_rail_layout; - if (statspec->renderdata == NULL) { + if (statspec->renderdata == nullptr) { sprites = GetStationTileLayout(STATION_RAIL, tile + axis); } else { layout = &statspec->renderdata[(tile < statspec->tiles) ? tile + axis : (uint)axis]; if (!layout->NeedsPreprocessing()) { sprites = layout; - layout = NULL; + layout = nullptr; } } - if (layout != NULL) { + if (layout != nullptr) { /* Sprite layout which needs preprocessing */ bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND); uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground); uint8 var10; FOR_EACH_SET_BIT(var10, var10_values) { - uint32 var10_relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE, var10); + uint32 var10_relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, var10); layout->ProcessRegisters(var10, var10_relocation, separate_ground); } @@ -806,9 +806,9 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID total_offset = 0; } else { /* Simple sprite layout */ - ground_relocation = relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE, 0); + ground_relocation = relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, 0); if (HasBit(sprites->ground.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) { - ground_relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE, 1); + ground_relocation = GetCustomStationRelocation(statspec, nullptr, INVALID_TILE, 1); } ground_relocation += rti->fallback_railtype; } @@ -816,7 +816,7 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID SpriteID image = sprites->ground.sprite; PaletteID pal = sprites->ground.pal; RailTrackOffset overlay_offset; - if (rti->UsesOverlay() && SplitGroundSpriteForOverlay(NULL, &image, &overlay_offset)) { + if (rti->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &image, &overlay_offset)) { SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND); DrawSprite(image, PAL_NONE, x, y); DrawSprite(ground + overlay_offset, PAL_NONE, x, y); @@ -834,11 +834,11 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID const StationSpec *GetStationSpec(TileIndex t) { - if (!IsCustomStationSpecIndex(t)) return NULL; + if (!IsCustomStationSpecIndex(t)) return nullptr; const BaseStation *st = BaseStation::GetByTile(t); uint specindex = GetCustomStationSpecIndex(t); - return specindex < st->num_specs ? st->speclist[specindex].spec : NULL; + return specindex < st->num_specs ? st->speclist[specindex].spec : nullptr; } @@ -852,7 +852,7 @@ bool IsStationTileBlocked(TileIndex tile) { const StationSpec *statspec = GetStationSpec(tile); - return statspec != NULL && HasBit(statspec->blocked, GetStationGfx(tile)); + return statspec != nullptr && HasBit(statspec->blocked, GetStationGfx(tile)); } /** @@ -866,7 +866,7 @@ bool CanStationTileHavePylons(TileIndex tile) const StationSpec *statspec = GetStationSpec(tile); uint gfx = GetStationGfx(tile); /* Default stations do not draw pylons under roofs (gfx >= 4) */ - return statspec != NULL ? HasBit(statspec->pylons, gfx) : gfx < 4; + return statspec != nullptr ? HasBit(statspec->pylons, gfx) : gfx < 4; } /** @@ -878,7 +878,7 @@ bool CanStationTileHavePylons(TileIndex tile) bool CanStationTileHaveWires(TileIndex tile) { const StationSpec *statspec = GetStationSpec(tile); - return statspec == NULL || !HasBit(statspec->wires, GetStationGfx(tile)); + return statspec == nullptr || !HasBit(statspec->wires, GetStationGfx(tile)); } /** Wrapper for animation control, see GetStationCallback. */ @@ -899,7 +899,7 @@ struct StationAnimationBase : public AnimationBaseflags, SSF_CB141_RANDOM_BITS)); } @@ -912,7 +912,7 @@ void TriggerStationAnimation(BaseStation *st, TileIndex tile, StationAnimationTr }; /* Get Station if it wasn't supplied */ - if (st == NULL) st = BaseStation::GetByTile(tile); + if (st == nullptr) st = BaseStation::GetByTile(tile); /* Check the cached animation trigger bitmask to see if we need * to bother with any further processing. */ @@ -925,7 +925,7 @@ void TriggerStationAnimation(BaseStation *st, TileIndex tile, StationAnimationTr TILE_AREA_LOOP(tile, area) { if (st->TileBelongsToRailStation(tile)) { const StationSpec *ss = GetStationSpec(tile); - if (ss != NULL && HasBit(ss->animation.triggers, trigger)) { + if (ss != nullptr && HasBit(ss->animation.triggers, trigger)) { CargoID cargo; if (cargo_type == CT_INVALID) { cargo = CT_INVALID; @@ -953,7 +953,7 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg }; /* Get Station if it wasn't supplied */ - if (st == NULL) st = Station::GetByTile(tile); + if (st == nullptr) st = Station::GetByTile(tile); /* Check the cached cargo trigger bitmask to see if we need * to bother with any further processing. */ @@ -981,7 +981,7 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg TILE_AREA_LOOP(tile, area) { if (st->TileBelongsToRailStation(tile)) { const StationSpec *ss = GetStationSpec(tile); - if (ss == NULL) continue; + if (ss == nullptr) continue; /* Cargo taken "will only be triggered if all of those * cargo types have no more cargo waiting." */ @@ -994,7 +994,7 @@ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigg object.waiting_triggers = st->waiting_triggers; const SpriteGroup *group = object.Resolve(); - if (group == NULL) continue; + if (group == nullptr) continue; used_triggers |= object.used_triggers; @@ -1036,7 +1036,7 @@ void StationUpdateCachedTriggers(BaseStation *st) * of this station. */ for (uint i = 0; i < st->num_specs; i++) { const StationSpec *ss = st->speclist[i].spec; - if (ss != NULL) { + if (ss != nullptr) { st->cached_anim_triggers |= ss->animation.triggers; st->cached_cargo_triggers |= ss->cargo_triggers; } diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 123330d0ad..eff76e57df 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -42,10 +42,10 @@ struct StationScopeResolver : public ScopeResolver { { } - /* virtual */ uint32 GetRandomBits() const; - /* virtual */ uint32 GetTriggers() const; + uint32 GetRandomBits() const override; + uint32 GetTriggers() const override; - /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; + uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override; }; /** Station resolver. */ @@ -59,7 +59,7 @@ struct StationResolverObject : public ResolverObject { TownScopeResolver *GetTown(); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: @@ -67,7 +67,7 @@ struct StationResolverObject : public ResolverObject { case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); - if (tsr != NULL) return tsr; + if (tsr != nullptr) return tsr; FALLTHROUGH; } @@ -76,16 +76,15 @@ struct StationResolverObject : public ResolverObject { } } - /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; + const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const override; }; -enum StationClassID { +enum StationClassID : byte { STAT_CLASS_BEGIN = 0, ///< the lowest valid value STAT_CLASS_DFLT = 0, ///< Default station class. STAT_CLASS_WAYP, ///< Waypoint class. - STAT_CLASS_MAX = 256, ///< Maximum number of classes. + STAT_CLASS_MAX = 255, ///< Maximum number of classes. }; -typedef SimpleTinyEnumT StationClassIDByte; template <> struct EnumPropsT : MakeEnumPropsT {}; /** Allow incrementing of StationClassID variables */ diff --git a/src/newgrf_storage.h b/src/newgrf_storage.h index a0c1558f8e..e9155dc5cb 100644 --- a/src/newgrf_storage.h +++ b/src/newgrf_storage.h @@ -70,7 +70,7 @@ struct PersistentStorageArray : BasePersistentStorageArray { TYPE *prev_storage; ///< Memory to store "old" states so we can revert them on the performance of test cases for commands etc. /** Simply construct the array */ - PersistentStorageArray() : prev_storage(NULL) + PersistentStorageArray() : prev_storage(nullptr) { memset(this->storage, 0, sizeof(this->storage)); } @@ -105,8 +105,8 @@ struct PersistentStorageArray : BasePersistentStorageArray { /* We do not have made a backup; lets do so */ if (AreChangesPersistent()) { - assert(this->prev_storage == NULL); - } else if (this->prev_storage == NULL) { + assert(this->prev_storage == nullptr); + } else if (this->prev_storage == nullptr) { this->prev_storage = MallocT(SIZE); memcpy(this->prev_storage, this->storage, sizeof(this->storage)); @@ -133,10 +133,10 @@ struct PersistentStorageArray : BasePersistentStorageArray { void ClearChanges() { - if (this->prev_storage != NULL) { + if (this->prev_storage != nullptr) { memcpy(this->storage, this->prev_storage, sizeof(this->storage)); free(this->prev_storage); - this->prev_storage = NULL; + this->prev_storage = nullptr; } } }; diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index b92b84355a..0a6cfd4a83 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -14,10 +14,14 @@ * holding everything that the newgrf action 04 will send over to OpenTTD. * One of the biggest problems is that Dynamic lang Array uses ISO codes * as way to identifying current user lang, while newgrf uses bit shift codes - * not related to ISO. So equivalence functionnality had to be set. + * not related to ISO. So equivalence functionality had to be set. */ #include "stdafx.h" + +#include +#include + #include "newgrf.h" #include "strings_func.h" #include "newgrf_storage.h" @@ -115,7 +119,7 @@ private: * @param text_ The text to store in this GRFText. * @param len_ The length of the text to store. */ - GRFText(byte langid_, const char *text_, size_t len_) : next(NULL), len(len_), langid(langid_) + GRFText(byte langid_, const char *text_, size_t len_) : next(nullptr), len(len_), langid(langid_) { /* We need to use memcpy instead of strcpy due to * the possibility of "choice lists" and therefore @@ -167,9 +171,9 @@ static byte _currentLangID = GRFLX_ENGLISH; ///< by default, english is used. */ int LanguageMap::GetMapping(int newgrf_id, bool gender) const { - const SmallVector &map = gender ? this->gender_map : this->case_map; - for (const Mapping *m = map.Begin(); m != map.End(); m++) { - if (m->newgrf_id == newgrf_id) return m->openttd_id; + const std::vector &map = gender ? this->gender_map : this->case_map; + for (const Mapping &m : map) { + if (m.newgrf_id == newgrf_id) return m.openttd_id; } return -1; } @@ -182,9 +186,9 @@ int LanguageMap::GetMapping(int newgrf_id, bool gender) const */ int LanguageMap::GetReverseMapping(int openttd_id, bool gender) const { - const SmallVector &map = gender ? this->gender_map : this->case_map; - for (const Mapping *m = map.Begin(); m != map.End(); m++) { - if (m->openttd_id == openttd_id) return m->newgrf_id; + const std::vector &map = gender ? this->gender_map : this->case_map; + for (const Mapping &m : map) { + if (m.openttd_id == openttd_id) return m.newgrf_id; } return -1; } @@ -194,8 +198,8 @@ struct UnmappedChoiceList : ZeroedMemoryAllocator { /** Clean everything up. */ ~UnmappedChoiceList() { - for (SmallPair *p = this->strings.Begin(); p < this->strings.End(); p++) { - free(p->second); + for (SmallPair p : this->strings) { + free(p.second); } } @@ -232,7 +236,7 @@ struct UnmappedChoiceList : ZeroedMemoryAllocator { } char *d = old_d; - if (lm == NULL) { + if (lm == nullptr) { /* In case there is no mapping, just ignore everything but the default. * A probable cause for this happening is when the language file has * been removed by the user and as such no mapping could be made. */ @@ -342,7 +346,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline size_t len = Utf8Decode(&c, str); /* Helper variable for a possible (string) mapping. */ - UnmappedChoiceList *mapping = NULL; + UnmappedChoiceList *mapping = nullptr; if (c == NFO_UTF8_IDENTIFIER) { unicode = true; @@ -461,7 +465,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline if (str[0] == '\0') goto string_end; const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id); int index = *str++; - int mapped = lm != NULL ? lm->GetMapping(index, code == 0x0E) : -1; + int mapped = lm != nullptr ? lm->GetMapping(index, code == 0x0E) : -1; if (mapped >= 0) { d += Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE); d += Utf8Encode(d, code == 0x0E ? mapped : mapped + 1); @@ -472,7 +476,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline case 0x10: case 0x11: if (str[0] == '\0') goto string_end; - if (mapping == NULL) { + if (mapping == nullptr) { if (code == 0x10) str++; // Skip the index grfmsg(1, "choice list %s marker found when not expected", code == 0x10 ? "next" : "default"); break; @@ -490,7 +494,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline break; case 0x12: - if (mapping == NULL) { + if (mapping == nullptr) { grfmsg(1, "choice list end marker found when not expected"); } else { /* Terminate the previous string. */ @@ -499,7 +503,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline /* Now we can start flushing everything and clean everything up. */ d = mapping->Flush(LanguageMap::GetLanguageMap(grfid, language_id)); delete mapping; - mapping = NULL; + mapping = nullptr; } break; @@ -507,7 +511,7 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline case 0x14: case 0x15: if (str[0] == '\0') goto string_end; - if (mapping != NULL) { + if (mapping != nullptr) { grfmsg(1, "choice lists can't be stacked, it's going to get messy now..."); if (code != 0x14) str++; } else { @@ -528,6 +532,9 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16); break; + case 0x1F: d += Utf8Encode(d, SCC_PUSH_COLOUR); break; + case 0x20: d += Utf8Encode(d, SCC_POP_COLOUR); break; + default: grfmsg(1, "missing handler for extended format code"); break; @@ -559,13 +566,13 @@ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newline } string_end: - if (mapping != NULL) { + if (mapping != nullptr) { grfmsg(1, "choice list was incomplete, the whole list is ignored"); delete mapping; } *d = '\0'; - if (olen != NULL) *olen = d - tmp + 1; + if (olen != nullptr) *olen = d - tmp + 1; tmp = ReallocT(tmp, d - tmp + 1); return tmp; } @@ -580,7 +587,7 @@ void AddGRFTextToList(GRFText **list, GRFText *text_to_add) GRFText **ptext, *text; /* Loop through all languages and see if we can replace a string */ - for (ptext = list; (text = *ptext) != NULL; ptext = &text->next) { + for (ptext = list; (text = *ptext) != nullptr; ptext = &text->next) { if (text->langid == text_to_add->langid) { text_to_add->next = text->next; *ptext = text_to_add; @@ -630,9 +637,9 @@ void AddGRFTextToList(struct GRFText **list, const char *text_to_add) */ GRFText *DuplicateGRFText(GRFText *orig) { - GRFText *newtext = NULL; + GRFText *newtext = nullptr; GRFText **ptext = &newtext; - for (; orig != NULL; orig = orig->next) { + for (; orig != nullptr; orig = orig->next) { *ptext = GRFText::Copy(orig); ptext = &(*ptext)->next; } @@ -684,7 +691,7 @@ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool ne /* If we didn't find our stringid and grfid in the list, allocate a new id */ if (id == _num_grf_texts) _num_grf_texts++; - if (_grf_text[id].textholder == NULL) { + if (_grf_text[id].textholder == nullptr) { _grf_text[id].grfid = grfid; _grf_text[id].stringid = stringid; _grf_text[id].def_string = def_string; @@ -715,20 +722,20 @@ StringID GetGRFStringID(uint32 grfid, StringID stringid) * Get a C-string from a GRFText-list. If there is a translation for the * current language it is returned, otherwise the default translation * is returned. If there is neither a default nor a translation for the - * current language NULL is returned. + * current language nullptr is returned. * @param text The GRFText to get the string from. */ const char *GetGRFStringFromGRFText(const GRFText *text) { - const char *default_text = NULL; + const char *default_text = nullptr; /* Search the list of lang-strings of this stringid for current lang */ - for (; text != NULL; text = text->next) { + for (; text != nullptr; text = text->next) { if (text->langid == _currentLangID) return text->text; /* If the current string is English or American, set it as the * fallback language if the specific language isn't available. */ - if (text->langid == GRFLX_UNSPECIFIED || (default_text == NULL && (text->langid == GRFLX_ENGLISH || text->langid == GRFLX_AMERICAN))) { + if (text->langid == GRFLX_UNSPECIFIED || (default_text == nullptr && (text->langid == GRFLX_ENGLISH || text->langid == GRFLX_AMERICAN))) { default_text = text->text; } } @@ -744,7 +751,7 @@ const char *GetGRFStringPtr(uint16 stringid) assert(_grf_text[stringid].grfid != 0); const char *str = GetGRFStringFromGRFText(_grf_text[stringid].textholder); - if (str != NULL) return str; + if (str != nullptr) return str; /* Use the default string ID if the fallback string isn't available */ return GetStringPtr(_grf_text[stringid].def_string); @@ -783,7 +790,7 @@ bool CheckGrfLangID(byte lang_id, byte grf_version) */ void CleanUpGRFText(GRFText *grftext) { - while (grftext != NULL) { + while (grftext != nullptr) { GRFText *grftext2 = grftext->next; delete grftext; grftext = grftext2; @@ -802,29 +809,21 @@ void CleanUpStrings() CleanUpGRFText(_grf_text[id].textholder); _grf_text[id].grfid = 0; _grf_text[id].stringid = 0; - _grf_text[id].textholder = NULL; + _grf_text[id].textholder = nullptr; } _num_grf_texts = 0; } struct TextRefStack { - byte stack[0x30]; + std::array stack; byte position; const GRFFile *grffile; bool used; - TextRefStack() : position(0), grffile(NULL), used(false) {} + TextRefStack() : position(0), grffile(nullptr), used(false) {} - TextRefStack(const TextRefStack &stack) : - position(stack.position), - grffile(stack.grffile), - used(stack.used) - { - memcpy(this->stack, stack.stack, sizeof(this->stack)); - } - - uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; } + uint8 PopUnsignedByte() { assert(this->position < this->stack.size()); return this->stack[this->position++]; } int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); } uint16 PopUnsignedWord() @@ -862,9 +861,8 @@ struct TextRefStack { if (this->position >= 2) { this->position -= 2; } else { - for (int i = lengthof(stack) - 1; i >= this->position + 2; i--) { - this->stack[i] = this->stack[i - 2]; - } + // Rotate right 2 positions + std::rotate(this->stack.rbegin(), this->stack.rbegin() + 2, this->stack.rend()); } this->stack[this->position] = GB(word, 0, 8); this->stack[this->position + 1] = GB(word, 8, 8); @@ -872,7 +870,7 @@ struct TextRefStack { void ResetStack(const GRFFile *grffile) { - assert(grffile != NULL); + assert(grffile != nullptr); this->position = 0; this->grffile = grffile; this->used = true; @@ -928,7 +926,7 @@ void RestoreTextRefStackBackup(struct TextRefStack *backup) * * @param grffile the NewGRF providing the stack data * @param numEntries number of entries to copy from the registers - * @param values values to copy onto the stack; if NULL the temporary NewGRF registers will be used instead + * @param values values to copy onto the stack; if nullptr the temporary NewGRF registers will be used instead */ void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values) { @@ -936,12 +934,12 @@ void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint3 _newgrf_textrefstack.ResetStack(grffile); - byte *p = _newgrf_textrefstack.stack; + auto stack_it = _newgrf_textrefstack.stack.begin(); for (uint i = 0; i < numEntries; i++) { - uint32 value = values != NULL ? values[i] : _temp_store.GetValue(0x100 + i); + uint32 value = values != nullptr ? values[i] : _temp_store.GetValue(0x100 + i); for (uint j = 0; j < 32; j += 8) { - *p = GB(value, j, 8); - p++; + *stack_it = GB(value, j, 8); + stack_it++; } } } diff --git a/src/newgrf_text.h b/src/newgrf_text.h index 033967d307..69ea6bd402 100644 --- a/src/newgrf_text.h +++ b/src/newgrf_text.h @@ -26,7 +26,7 @@ const char *GetGRFStringFromGRFText(const struct GRFText *text); const char *GetGRFStringPtr(uint16 stringid); void CleanUpStrings(); void SetCurrentGrfLangID(byte language_id); -char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen = NULL, StringControlCode byte80 = SCC_NEWGRF_PRINT_WORD_STRING_ID); +char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen = nullptr, StringControlCode byte80 = SCC_NEWGRF_PRINT_WORD_STRING_ID); struct GRFText *DuplicateGRFText(struct GRFText *orig); void AddGRFTextToList(struct GRFText **list, struct GRFText *text_to_add); void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); @@ -35,7 +35,7 @@ void CleanUpGRFText(struct GRFText *grftext); bool CheckGrfLangID(byte lang_id, byte grf_version); -void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values = NULL); +void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values = nullptr); void StopTextRefStackUsage(); void RewindTextRefStack(); bool UsingNewGRFTextStack(); @@ -57,9 +57,9 @@ struct LanguageMap { * the genders/cases/plural OpenTTD IDs to the NewGRF's internal IDs. In this * case a NewGRF developer/translator might want a different translation for * both cases. Thus we are basically implementing a multi-map. */ - SmallVector gender_map; ///< Mapping of NewGRF and OpenTTD IDs for genders. - SmallVector case_map; ///< Mapping of NewGRF and OpenTTD IDs for cases. - int plural_form; ///< The plural form used for this language. + std::vector gender_map; ///< Mapping of NewGRF and OpenTTD IDs for genders. + std::vector case_map; ///< Mapping of NewGRF and OpenTTD IDs for cases. + int plural_form; ///< The plural form used for this language. int GetMapping(int newgrf_id, bool gender) const; int GetReverseMapping(int openttd_id, bool gender) const; diff --git a/src/newgrf_town.cpp b/src/newgrf_town.cpp index 00fcf76b63..d124eaab5d 100644 --- a/src/newgrf_town.cpp +++ b/src/newgrf_town.cpp @@ -33,7 +33,7 @@ /* Check the persistent storage for the GrfID stored in register 100h. */ uint32 grfid = GetRegister(0x100); if (grfid == 0xFFFFFFFF) { - if (this->ro.grffile == NULL) return 0; + if (this->ro.grffile == nullptr) return 0; grfid = this->ro.grffile->grfid; } @@ -123,9 +123,9 @@ { if (this->readonly) return; - assert(this->t != NULL); + assert(this->t != nullptr); /* We can't store anything if the caller has no #GRFFile. */ - if (this->ro.grffile == NULL) return; + if (this->ro.grffile == nullptr) return; /* Check the persistent storage for the GrfID stored in register 100h. */ uint32 grfid = GetRegister(0x100); diff --git a/src/newgrf_town.h b/src/newgrf_town.h index 7c4fb5395c..a55f71f369 100644 --- a/src/newgrf_town.h +++ b/src/newgrf_town.h @@ -46,7 +46,7 @@ struct TownResolverObject : public ResolverObject { TownResolverObject(const struct GRFFile *grffile, Town *t, bool readonly); - /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) + ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) override { switch (scope) { case VSG_SCOPE_SELF: return &town_scope; diff --git a/src/newgrf_townname.cpp b/src/newgrf_townname.cpp index 42aae3f147..df99dd7384 100644 --- a/src/newgrf_townname.cpp +++ b/src/newgrf_townname.cpp @@ -21,21 +21,21 @@ #include "safeguards.h" -static GRFTownName *_grf_townnames = NULL; +static GRFTownName *_grf_townnames = nullptr; GRFTownName *GetGRFTownName(uint32 grfid) { GRFTownName *t = _grf_townnames; - for (; t != NULL; t = t->next) { + for (; t != nullptr; t = t->next) { if (t->grfid == grfid) return t; } - return NULL; + return nullptr; } GRFTownName *AddGRFTownName(uint32 grfid) { GRFTownName *t = GetGRFTownName(grfid); - if (t == NULL) { + if (t == nullptr) { t = CallocT(1); t->grfid = grfid; t->next = _grf_townnames; @@ -47,9 +47,9 @@ GRFTownName *AddGRFTownName(uint32 grfid) void DelGRFTownName(uint32 grfid) { GRFTownName *t = _grf_townnames; - GRFTownName *p = NULL; - for (;t != NULL; p = t, t = t->next) if (t->grfid == grfid) break; - if (t != NULL) { + GRFTownName *p = nullptr; + for (;t != nullptr; p = t, t = t->next) if (t->grfid == grfid) break; + if (t != nullptr) { for (int i = 0; i < 128; i++) { for (int j = 0; j < t->nbparts[i]; j++) { for (int k = 0; k < t->partlist[i][j].partcount; k++) { @@ -59,7 +59,7 @@ void DelGRFTownName(uint32 grfid) } free(t->partlist[i]); } - if (p != NULL) { + if (p != nullptr) { p->next = t->next; } else { _grf_townnames = t->next; @@ -70,7 +70,7 @@ void DelGRFTownName(uint32 grfid) static char *RandomPart(char *buf, GRFTownName *t, uint32 seed, byte id, const char *last) { - assert(t != NULL); + assert(t != nullptr); for (int i = 0; i < t->nbparts[id]; i++) { byte count = t->partlist[id][i].bitcount; uint16 maxprob = t->partlist[id][i].maxprob; @@ -93,7 +93,7 @@ static char *RandomPart(char *buf, GRFTownName *t, uint32 seed, byte id, const c char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last) { strecpy(buf, "", last); - for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) { if (t->grfid == grfid) { assert(gen < t->nb_gen); buf = RandomPart(buf, t, seed, t->id[gen], last); @@ -106,9 +106,9 @@ char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, cons StringID *GetGRFTownNameList() { int nb_names = 0, n = 0; - for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) nb_names += t->nb_gen; + for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) nb_names += t->nb_gen; StringID *list = MallocT(nb_names + 1); - for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) { for (int j = 0; j < t->nb_gen; j++) list[n++] = t->name[j]; } list[n] = INVALID_STRING_ID; @@ -117,12 +117,12 @@ StringID *GetGRFTownNameList() void CleanUpGRFTownNames() { - while (_grf_townnames != NULL) DelGRFTownName(_grf_townnames->grfid); + while (_grf_townnames != nullptr) DelGRFTownName(_grf_townnames->grfid); } uint32 GetGRFTownNameId(int gen) { - for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) { if (gen < t->nb_gen) return t->grfid; gen -= t->nb_gen; } @@ -132,7 +132,7 @@ uint32 GetGRFTownNameId(int gen) uint16 GetGRFTownNameType(int gen) { - for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { + for (GRFTownName *t = _grf_townnames; t != nullptr; t = t->next) { if (gen < t->nb_gen) return gen; gen -= t->nb_gen; } diff --git a/src/news_func.h b/src/news_func.h index cd0862f348..bfd38a724d 100644 --- a/src/news_func.h +++ b/src/news_func.h @@ -17,7 +17,7 @@ #include "station_type.h" #include "industry_type.h" -void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, void *free_data = NULL); +void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, void *free_data = nullptr); static inline void AddCompanyNewsItem(StringID string, CompanyNewsInformation *cni) { @@ -44,7 +44,7 @@ static inline void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle) AddNewsItem(string, NT_ADVICE, NF_INCOLOUR | NF_SMALL | NF_VEHICLE_PARAM0, NR_VEHICLE, vehicle); } -static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, void *free_data = NULL) +static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, void *free_data = nullptr) { AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, tile, NR_NONE, UINT32_MAX, free_data); } diff --git a/src/news_gui.cpp b/src/news_gui.cpp index f466c96852..0cf9e9e2a8 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -41,23 +41,23 @@ #include "safeguards.h" -const NewsItem *_statusbar_news_item = NULL; +const NewsItem *_statusbar_news_item = nullptr; -static uint MIN_NEWS_AMOUNT = 30; ///< preferred minimum amount of news messages -static uint _total_news = 0; ///< current number of news items -static NewsItem *_oldest_news = NULL; ///< head of news items queue -NewsItem *_latest_news = NULL; ///< tail of news items queue +static uint MIN_NEWS_AMOUNT = 30; ///< preferred minimum amount of news messages +static uint _total_news = 0; ///< current number of news items +static NewsItem *_oldest_news = nullptr; ///< head of news items queue +NewsItem *_latest_news = nullptr; ///< tail of news items queue /** * Forced news item. * Users can force an item by accessing the history or "last message". * If the message being shown was forced by the user, a pointer is stored - * in _forced_news. Otherwise, \a _forced_news variable is NULL. + * in _forced_news. Otherwise, \a _forced_news variable is nullptr. */ -static const NewsItem *_forced_news = NULL; +static const NewsItem *_forced_news = nullptr; /** Current news item (last item shown regularly). */ -static const NewsItem *_current_news = NULL; +static const NewsItem *_current_news = nullptr; /** @@ -93,7 +93,7 @@ static const NWidgetPart _nested_normal_news_widgets[] = { }; static WindowDesc _normal_news_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_normal_news_widgets, lengthof(_nested_normal_news_widgets) @@ -120,7 +120,7 @@ static const NWidgetPart _nested_vehicle_news_widgets[] = { }; static WindowDesc _vehicle_news_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_vehicle_news_widgets, lengthof(_nested_vehicle_news_widgets) @@ -148,7 +148,7 @@ static const NWidgetPart _nested_company_news_widgets[] = { }; static WindowDesc _company_news_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_company_news_widgets, lengthof(_nested_company_news_widgets) @@ -171,7 +171,7 @@ static const NWidgetPart _nested_thin_news_widgets[] = { }; static WindowDesc _thin_news_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_thin_news_widgets, lengthof(_nested_thin_news_widgets) @@ -195,7 +195,7 @@ static const NWidgetPart _nested_small_news_widgets[] = { }; static WindowDesc _small_news_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_small_news_widgets, lengthof(_nested_small_news_widgets) @@ -251,8 +251,8 @@ NewsDisplay NewsTypeData::GetDisplay() const { uint index; const SettingDesc *sd = GetSettingFromName(this->name, &index); - assert(sd != NULL); - void *ptr = GetVariableAddress(NULL, &sd->save); + assert(sd != nullptr); + void *ptr = GetVariableAddress(nullptr, &sd->save); return (NewsDisplay)ReadValue(ptr, sd->save.conv); } @@ -269,7 +269,7 @@ struct NewsWindow : Window { { NewsWindow::duration = 16650; const Window *w = FindWindowByClass(WC_SEND_NETWORK_MSG); - this->chat_height = (w != NULL) ? w->height : 0; + this->chat_height = (w != nullptr) ? w->height : 0; this->status_height = FindWindowById(WC_STATUS_BAR, 0)->height; this->flags |= WF_DISABLE_VP_SCROLL; @@ -285,7 +285,7 @@ struct NewsWindow : Window { /* Initialize viewport if it exists. */ NWidgetViewport *nvp = this->GetWidget(WID_N_VIEWPORT); - if (nvp != NULL) { + if (nvp != nullptr) { nvp->InitializeViewport(this, ni->reftype1 == NR_VEHICLE ? 0x80000000 | ni->ref1 : GetReferenceTile(ni->reftype1, ni->ref1), ZOOM_LVL_NEWS); if (this->ni->flags & NF_NO_TRANSPARENT) nvp->disp_flags |= ND_NO_TRANSPARENCY; if ((this->ni->flags & NF_INCOLOUR) == 0) { @@ -308,13 +308,13 @@ struct NewsWindow : Window { GfxFillRect(r.left, r.bottom, r.right, r.bottom, PC_BLACK); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt = { 0, _screen.height }; return pt; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { StringID str = STR_NULL; switch (widget) { @@ -370,12 +370,12 @@ struct NewsWindow : Window { *size = maxdim(*size, d); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_N_DATE) SetDParam(0, this->ni->date); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_N_CAPTION: @@ -432,13 +432,13 @@ struct NewsWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_N_CLOSEBOX: NewsWindow::duration = 0; delete this; - _forced_news = NULL; + _forced_news = nullptr; break; case WID_N_CAPTION: @@ -471,7 +471,7 @@ struct NewsWindow : Window { } } - virtual EventState OnKeyPress(WChar key, uint16 keycode) + EventState OnKeyPress(WChar key, uint16 keycode) override { if (keycode == WKC_SPACE) { /* Don't continue. */ @@ -486,7 +486,7 @@ struct NewsWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* The chatbar has notified us that is was either created or closed */ @@ -495,7 +495,7 @@ struct NewsWindow : Window { this->SetWindowTop(newtop); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { int count = this->timer.CountElapsed(delta_ms); if (count > 0) { @@ -520,7 +520,7 @@ private: int mintop = min(newtop, this->top); int maxtop = max(newtop, this->top); - if (this->viewport != NULL) this->viewport->top += newtop - this->top; + if (this->viewport != nullptr) this->viewport->top += newtop - this->top; this->top = newtop; SetDirtyBlocks(this->left, mintop, this->left + this->width, maxtop + this->height); @@ -577,54 +577,62 @@ static void ShowTicker(const NewsItem *ni) /** Initialize the news-items data structures */ void InitNewsItemStructs() { - for (NewsItem *ni = _oldest_news; ni != NULL; ) { + for (NewsItem *ni = _oldest_news; ni != nullptr; ) { NewsItem *next = ni->next; delete ni; ni = next; } _total_news = 0; - _oldest_news = NULL; - _latest_news = NULL; - _forced_news = NULL; - _current_news = NULL; - _statusbar_news_item = NULL; + _oldest_news = nullptr; + _latest_news = nullptr; + _forced_news = nullptr; + _current_news = nullptr; + _statusbar_news_item = nullptr; NewsWindow::duration = 0; } /** - * Are we ready to show another news item? - * Only if nothing is in the newsticker and no newspaper is displayed + * Are we ready to show another ticker item? + * Only if nothing is in the newsticker is displayed */ -static bool ReadyForNextItem() +static bool ReadyForNextTickerItem() { - const NewsItem *ni = _forced_news == NULL ? _current_news : _forced_news; - if (ni == NULL) return true; + const NewsItem *ni = _statusbar_news_item; + if (ni == nullptr) return true; /* Ticker message * Check if the status bar message is still being displayed? */ if (IsNewsTickerShown()) return false; - - /* neither newsticker nor newspaper are running */ - return (NewsWindow::duration <= 0 || FindWindowById(WC_NEWS_WINDOW, 0) == NULL); + return true; } -/** Move to the next news item */ -static void MoveToNextItem() +/** + * Are we ready to show another news item? + * Only if no newspaper is displayed + */ +static bool ReadyForNextNewsItem() +{ + const NewsItem *ni = _forced_news == nullptr ? _current_news : _forced_news; + if (ni == nullptr) return true; + + /* neither newsticker nor newspaper are running */ + return (NewsWindow::duration <= 0 || FindWindowById(WC_NEWS_WINDOW, 0) == nullptr); +} + +/** Move to the next ticker item */ +static void MoveToNextTickerItem() { InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); // invalidate the statusbar - DeleteWindowById(WC_NEWS_WINDOW, 0); // close the newspapers window if shown - _forced_news = NULL; - _statusbar_news_item = NULL; /* if we're not at the last item, then move on */ - if (_current_news != _latest_news) { - _current_news = (_current_news == NULL) ? _oldest_news : _current_news->next; - const NewsItem *ni = _current_news; + while (_statusbar_news_item != _latest_news) { + _statusbar_news_item = (_statusbar_news_item == nullptr) ? _oldest_news : _statusbar_news_item->next; + const NewsItem *ni = _statusbar_news_item; const NewsType type = ni->type; /* check the date, don't show too old items */ - if (_date - _news_type_data[type].age > ni->date) return; + if (_date - _news_type_data[type].age > ni->date) continue; switch (_news_type_data[type].GetDisplay()) { default: NOT_REACHED(); @@ -636,10 +644,41 @@ static void MoveToNextItem() ShowTicker(ni); break; + case ND_FULL: // Full - show newspaper, skipped here + continue; + } + return; + } +} + +/** Move to the next news item */ +static void MoveToNextNewsItem() +{ + DeleteWindowById(WC_NEWS_WINDOW, 0); // close the newspapers window if shown + _forced_news = nullptr; + + /* if we're not at the last item, then move on */ + while (_current_news != _latest_news) { + _current_news = (_current_news == nullptr) ? _oldest_news : _current_news->next; + const NewsItem *ni = _current_news; + const NewsType type = ni->type; + + /* check the date, don't show too old items */ + if (_date - _news_type_data[type].age > ni->date) continue; + + switch (_news_type_data[type].GetDisplay()) { + default: NOT_REACHED(); + case ND_OFF: // Off - show nothing only a small reminder in the status bar, skipped here + continue; + + case ND_SUMMARY: // Summary - show ticker, skipped here + continue; + case ND_FULL: // Full - show newspaper ShowNewspaper(ni); break; } + return; } } @@ -649,9 +688,9 @@ static void MoveToNextItem() * @param type news category * @param flags display flags for the news * @param reftype1 Type of ref1 - * @param ref1 Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleteing the news when the object is deleted. + * @param ref1 Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleting the news when the object is deleted. * @param reftype2 Type of ref2 - * @param ref2 Reference 2 to some object: Used for scrolling after clicking on the news, and for deleteing the news when the object is deleted. + * @param ref2 Reference 2 to some object: Used for scrolling after clicking on the news, and for deleting the news when the object is deleted. * @param free_data Pointer to data that must be freed once the news message is cleared * * @see NewsSubtype @@ -679,16 +718,16 @@ void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceTy CopyOutDParam(ni->params, 0, lengthof(ni->params)); if (_total_news++ == 0) { - assert(_oldest_news == NULL); + assert(_oldest_news == nullptr); _oldest_news = ni; - ni->prev = NULL; + ni->prev = nullptr; } else { - assert(_latest_news->next == NULL); + assert(_latest_news->next == nullptr); _latest_news->next = ni; ni->prev = _latest_news; } - ni->next = NULL; + ni->next = nullptr; _latest_news = ni; SetWindowDirty(WC_MESSAGE_HISTORY, 0); @@ -762,14 +801,14 @@ CommandCost CmdCustomNewsItem(TileIndex tile, DoCommandFlag flags, uint32 p1, ui static void DeleteNewsItem(NewsItem *ni) { /* Delete the news from the news queue. */ - if (ni->prev != NULL) { + if (ni->prev != nullptr) { ni->prev->next = ni->next; } else { assert(_oldest_news == ni); _oldest_news = ni->next; } - if (ni->next != NULL) { + if (ni->next != nullptr) { ni->next->prev = ni->prev; } else { assert(_latest_news == ni); @@ -778,14 +817,23 @@ static void DeleteNewsItem(NewsItem *ni) _total_news--; - if (_forced_news == ni || _current_news == ni || _statusbar_news_item == ni) { + if (_forced_news == ni || _current_news == ni) { /* When we're the current news, go to the previous item first; * we just possibly made that the last news item. */ if (_current_news == ni) _current_news = ni->prev; /* About to remove the currently forced item (shown as newspapers) || - * about to remove the currently displayed item (newspapers, ticker, or just a reminder) */ - MoveToNextItem(); + * about to remove the currently displayed item (newspapers) */ + MoveToNextNewsItem(); + } + + if (_statusbar_news_item == ni) { + /* When we're the current news, go to the previous item first; + * we just possibly made that the last news item. */ + _statusbar_news_item = ni->prev; + + /* About to remove the currently displayed item (ticker, or just a reminder) */ + MoveToNextTickerItem(); } delete ni; @@ -803,7 +851,7 @@ void DeleteVehicleNews(VehicleID vid, StringID news) { NewsItem *ni = _oldest_news; - while (ni != NULL) { + while (ni != nullptr) { NewsItem *next = ni->next; if (((ni->reftype1 == NR_VEHICLE && ni->ref1 == vid) || (ni->reftype2 == NR_VEHICLE && ni->ref2 == vid)) && (news == INVALID_STRING_ID || ni->string_id == news)) { @@ -822,7 +870,7 @@ void DeleteStationNews(StationID sid) { NewsItem *ni = _oldest_news; - while (ni != NULL) { + while (ni != nullptr) { NewsItem *next = ni->next; if ((ni->reftype1 == NR_STATION && ni->ref1 == sid) || (ni->reftype2 == NR_STATION && ni->ref2 == sid)) { DeleteNewsItem(ni); @@ -839,7 +887,7 @@ void DeleteIndustryNews(IndustryID iid) { NewsItem *ni = _oldest_news; - while (ni != NULL) { + while (ni != nullptr) { NewsItem *next = ni->next; if ((ni->reftype1 == NR_INDUSTRY && ni->ref1 == iid) || (ni->reftype2 == NR_INDUSTRY && ni->ref2 == iid)) { DeleteNewsItem(ni); @@ -855,7 +903,7 @@ void DeleteInvalidEngineNews() { NewsItem *ni = _oldest_news; - while (ni != NULL) { + while (ni != nullptr) { NewsItem *next = ni->next; if ((ni->reftype1 == NR_ENGINE && (!Engine::IsValidID(ni->ref1) || !Engine::Get(ni->ref1)->IsEnabled())) || (ni->reftype2 == NR_ENGINE && (!Engine::IsValidID(ni->ref2) || !Engine::Get(ni->ref2)->IsEnabled()))) { @@ -868,7 +916,7 @@ void DeleteInvalidEngineNews() static void RemoveOldNewsItems() { NewsItem *next; - for (NewsItem *cur = _oldest_news; _total_news > MIN_NEWS_AMOUNT && cur != NULL; cur = next) { + for (NewsItem *cur = _oldest_news; _total_news > MIN_NEWS_AMOUNT && cur != nullptr; cur = next) { next = cur->next; if (_date - _news_type_data[cur->type].age * _settings_client.gui.news_message_timeout > cur->date) DeleteNewsItem(cur); } @@ -882,7 +930,7 @@ static void RemoveOldNewsItems() */ void ChangeVehicleNews(VehicleID from_index, VehicleID to_index) { - for (NewsItem *ni = _oldest_news; ni != NULL; ni = ni->next) { + for (NewsItem *ni = _oldest_news; ni != nullptr; ni = ni->next) { if (ni->reftype1 == NR_VEHICLE && ni->ref1 == from_index) ni->ref1 = to_index; if (ni->reftype2 == NR_VEHICLE && ni->ref2 == from_index) ni->ref2 = to_index; if (ni->flags & NF_VEHICLE_PARAM0 && ni->params[0] == from_index) ni->params[0] = to_index; @@ -897,7 +945,7 @@ void NewsLoop() /* There is no status bar, so no reason to show news; * especially important with the end game screen when * there is no status bar but possible news. */ - if (FindWindowById(WC_STATUS_BAR, 0) == NULL) return; + if (FindWindowById(WC_STATUS_BAR, 0) == nullptr) return; static byte _last_clean_month = 0; @@ -906,7 +954,8 @@ void NewsLoop() _last_clean_month = _cur_month; } - if (ReadyForNextItem()) MoveToNextItem(); + if (ReadyForNextTickerItem()) MoveToNextTickerItem(); + if (ReadyForNextNewsItem()) MoveToNextNewsItem(); } /** Do a forced show of a specific message */ @@ -920,7 +969,7 @@ static void ShowNewsMessage(const NewsItem *ni) /* setup forced news item */ _forced_news = ni; - if (_forced_news != NULL) { + if (_forced_news != nullptr) { DeleteWindowById(WC_NEWS_WINDOW, 0); ShowNewspaper(ni); } @@ -929,19 +978,19 @@ static void ShowNewsMessage(const NewsItem *ni) /** Show previous news item */ void ShowLastNewsMessage() { - const NewsItem *ni = NULL; + const NewsItem *ni = nullptr; if (_total_news == 0) { return; - } else if (_forced_news == NULL) { + } else if (_forced_news == nullptr) { /* Not forced any news yet, show the current one, unless a news window is * open (which can only be the current one), then show the previous item */ - if (_current_news == NULL) { + if (_current_news == nullptr) { /* No news were shown yet resp. the last shown one was already deleted. * Threat this as if _forced_news reached _oldest_news; so, wrap around and start anew with the latest. */ ni = _latest_news; } else { const Window *w = FindWindowById(WC_NEWS_WINDOW, 0); - ni = (w == NULL || (_current_news == _oldest_news)) ? _current_news : _current_news->prev; + ni = (w == nullptr || (_current_news == _oldest_news)) ? _current_news : _current_news->prev; } } else if (_forced_news == _oldest_news) { /* We have reached the oldest news, start anew with the latest */ @@ -958,7 +1007,7 @@ void ShowLastNewsMessage() } ni = ni->prev; - if (ni == NULL) { + if (ni == nullptr) { if (wrap) break; /* We have reached the oldest news, start anew with the latest */ ni = _latest_news; @@ -1029,7 +1078,7 @@ struct MessageHistoryWindow : Window { this->OnInvalidateData(0); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_MH_BACKGROUND) { this->line_height = FONT_HEIGHT_NORMAL + 2; @@ -1045,13 +1094,13 @@ struct MessageHistoryWindow : Window { } } - virtual void OnPaint() + void OnPaint() override { this->OnInvalidateData(0); this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_MH_BACKGROUND || _total_news == 0) return; @@ -1059,7 +1108,7 @@ struct MessageHistoryWindow : Window { NewsItem *ni = _latest_news; for (int n = this->vscroll->GetPosition(); n > 0; n--) { ni = ni->prev; - if (ni == NULL) return; + if (ni == nullptr) return; } /* Fill the widget with news items. */ @@ -1077,7 +1126,7 @@ struct MessageHistoryWindow : Window { y += this->line_height; ni = ni->prev; - if (ni == NULL) return; + if (ni == nullptr) return; } } @@ -1086,28 +1135,28 @@ struct MessageHistoryWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->vscroll->SetCount(_total_news); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget == WID_MH_BACKGROUND) { NewsItem *ni = _latest_news; - if (ni == NULL) return; + if (ni == nullptr) return; for (int n = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_MH_BACKGROUND, WD_FRAMERECT_TOP, this->line_height); n > 0; n--) { ni = ni->prev; - if (ni == NULL) return; + if (ni == nullptr) return; } ShowNewsMessage(ni); } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_MH_BACKGROUND); } diff --git a/src/news_type.h b/src/news_type.h index cad15ecbef..0038d0f903 100644 --- a/src/news_type.h +++ b/src/news_type.h @@ -128,8 +128,8 @@ struct NewsItem { NewsReferenceType reftype1; ///< Type of ref1 NewsReferenceType reftype2; ///< Type of ref2 - uint32 ref1; ///< Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleteing the news when the object is deleted. - uint32 ref2; ///< Reference 2 to some object: Used for scrolling after clicking on the news, and for deleteing the news when the object is deleted. + uint32 ref1; ///< Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleting the news when the object is deleted. + uint32 ref2; ///< Reference 2 to some object: Used for scrolling after clicking on the news, and for deleting the news when the object is deleted. void *free_data; ///< Data to be freed when the news item has reached its end. @@ -155,7 +155,7 @@ struct CompanyNewsInformation { uint32 face; ///< The face of the president byte colour; ///< The colour related to the company - void FillData(const struct Company *c, const struct Company *other = NULL); + void FillData(const struct Company *c, const struct Company *other = nullptr); }; #endif /* NEWS_TYPE_H */ diff --git a/src/object.h b/src/object.h index 0ab92d3769..7375aad155 100644 --- a/src/object.h +++ b/src/object.h @@ -18,7 +18,7 @@ void UpdateCompanyHQ(TileIndex tile, uint score); -void BuildObject(ObjectType type, TileIndex tile, CompanyID owner = OWNER_NONE, struct Town *town = NULL, uint8 view = 0); +void BuildObject(ObjectType type, TileIndex tile, CompanyID owner = OWNER_NONE, struct Town *town = nullptr, uint8 view = 0); void ShowBuildObjectPicker(); diff --git a/src/object_base.h b/src/object_base.h index 47e5a7f94c..228eeaa2dc 100644 --- a/src/object_base.h +++ b/src/object_base.h @@ -92,6 +92,6 @@ struct ClearedObjectArea { }; ClearedObjectArea *FindClearedObject(TileIndex tile); -extern SmallVector _cleared_object_areas; +extern std::vector _cleared_object_areas; #endif /* OBJECT_BASE_H */ diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 88aa645dd3..48b6f1f254 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -90,7 +90,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u Object *o = new Object(); o->type = type; o->location = ta; - o->town = town == NULL ? CalcClosestTownFromTile(tile) : town; + o->town = town == nullptr ? CalcClosestTownFromTile(tile) : town; o->build_date = _date; o->view = view; @@ -114,7 +114,7 @@ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, u } } - assert(o->town != NULL); + assert(o->town != nullptr); TILE_AREA_LOOP(t, ta) { WaterClass wc = (IsWaterTile(t) ? GetWaterClass(t) : WATER_CLASS_INVALID); @@ -158,12 +158,11 @@ void UpdateCompanyHQ(TileIndex tile, uint score) { if (tile == INVALID_TILE) return; - byte val; - (val = 0, score < 170) || - (val++, score < 350) || - (val++, score < 520) || - (val++, score < 720) || - (val++, true); + byte val = 0; + if (score >= 170) val++; + if (score >= 350) val++; + if (score >= 520) val++; + if (score >= 720) val++; while (GetCompanyHQSize(tile) < val) { IncreaseCompanyHQSize(tile); @@ -264,7 +263,7 @@ CommandCost CmdBuildObject(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 uint16 callback = CALLBACK_FAILED; if (HasBit(spec->callback_mask, CBM_OBJ_SLOPE_CHECK)) { TileIndex diff = t - tile; - callback = GetObjectCallback(CBID_OBJECT_LAND_SLOPE_CHECK, GetTileSlope(t), TileY(diff) << 4 | TileX(diff), spec, NULL, t, view); + callback = GetObjectCallback(CBID_OBJECT_LAND_SLOPE_CHECK, GetTileSlope(t), TileY(diff) << 4 | TileX(diff), spec, nullptr, t, view); } if (callback == CALLBACK_FAILED) { @@ -343,7 +342,7 @@ CommandCost CmdBuildObject(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } if (flags & DC_EXEC) { - BuildObject(type, tile, _current_company, NULL, view); + BuildObject(type, tile, _current_company, nullptr, view); /* Make sure the HQ starts at the right size. */ if (type == OBJECT_HQ) UpdateCompanyHQ(tile, hq_score); @@ -367,7 +366,7 @@ static void DrawTile_Object(TileInfo *ti) if ((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); if (type < NEW_OBJECT_OFFSET) { - const DrawTileSprites *dts = NULL; + const DrawTileSprites *dts = nullptr; Owner to = GetTileOwner(ti->tile); PaletteID palette = to == OWNER_NONE ? PAL_NONE : COMPANY_SPRITE_COLOUR(to); @@ -443,23 +442,22 @@ static void ReallyClearObjectTile(Object *o) delete o; } -SmallVector _cleared_object_areas; +std::vector _cleared_object_areas; /** * Find the entry in _cleared_object_areas which occupies a certain tile. * @param tile Tile of interest - * @return Occupying entry, or NULL if none + * @return Occupying entry, or nullptr if none */ ClearedObjectArea *FindClearedObject(TileIndex tile) { TileArea ta = TileArea(tile, 1, 1); - const ClearedObjectArea *end = _cleared_object_areas.End(); - for (ClearedObjectArea *coa = _cleared_object_areas.Begin(); coa != end; coa++) { - if (coa->area.Intersects(ta)) return coa; + for (ClearedObjectArea &coa : _cleared_object_areas) { + if (coa.area.Intersects(ta)) return &coa; } - return NULL; + return nullptr; } static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags) @@ -531,9 +529,7 @@ static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags) break; } - ClearedObjectArea *cleared_area = _cleared_object_areas.Append(); - cleared_area->first_tile = tile; - cleared_area->area = ta; + _cleared_object_areas.push_back({tile, ta}); if (flags & DC_EXEC) ReallyClearObjectTile(o); @@ -571,7 +567,7 @@ static void GetTileDesc_Object(TileIndex tile, TileDesc *td) td->owner[0] = GetTileOwner(tile); td->build_date = Object::GetByTile(tile)->build_date; - if (spec->grf_prop.grffile != NULL) { + if (spec->grf_prop.grffile != nullptr) { td->grf = GetGRFConfig(spec->grf_prop.grffile->grfid)->GetName(); } } @@ -698,7 +694,7 @@ static bool TryBuildTransmitter() int h; if (IsTileType(tile, MP_CLEAR) && IsTileFlat(tile, &h) && h >= 4 && !IsBridgeAbove(tile)) { TileIndex t = tile; - if (CircularTileSearch(&t, 9, HasTransmitter, NULL)) return false; + if (CircularTileSearch(&t, 9, HasTransmitter, nullptr)) return false; BuildObject(OBJECT_TRANSMITTER, tile); return true; @@ -758,7 +754,7 @@ void GenerateObjects() default: uint8 view = RandomRange(spec->views); - if (CmdBuildObject(RandomTile(), DC_EXEC | DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, i, view, NULL).Succeeded()) amount--; + if (CmdBuildObject(RandomTile(), DC_EXEC | DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, i, view, nullptr).Succeeded()) amount--; break; } } @@ -793,7 +789,7 @@ static void ChangeTileOwner_Object(TileIndex tile, Owner old_owner, Owner new_ow if (do_clear) { ReallyClearObjectTile(Object::GetByTile(tile)); - /* When clearing objects, they may turn into canal, which may require transfering ownership. */ + /* When clearing objects, they may turn into canal, which may require transferring ownership. */ ChangeTileOwner(tile, old_owner, new_owner); } } @@ -844,8 +840,8 @@ extern const TileTypeProcs _tile_type_object_procs = { AnimateTile_Object, // animate_tile_proc TileLoop_Object, // tile_loop_proc ChangeTileOwner_Object, // change_tile_owner_proc - NULL, // add_produced_cargo_proc - NULL, // vehicle_enter_tile_proc + nullptr, // add_produced_cargo_proc + nullptr, // vehicle_enter_tile_proc GetFoundation_Object, // get_foundation_proc TerraformTile_Object, // terraform_tile_proc }; diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 8aabcfdc46..a84be26e63 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -99,18 +99,18 @@ public: this->GetWidget(WID_BO_OBJECT_MATRIX)->SetCount(4); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_BO_OBJECT_NAME: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); - SetDParam(0, spec != NULL ? spec->name : STR_EMPTY); + SetDParam(0, spec != nullptr ? spec->name : STR_EMPTY); break; } case WID_BO_OBJECT_SIZE: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); - int size = spec == NULL ? 0 : spec->size; + int size = spec == nullptr ? 0 : spec->size; SetDParam(0, GB(size, HasBit(_selected_object_view, 0) ? 4 : 0, 4)); SetDParam(1, GB(size, HasBit(_selected_object_view, 0) ? 0 : 4, 4)); break; @@ -120,7 +120,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BO_CLASS_LIST: { @@ -145,7 +145,7 @@ public: case WID_BO_OBJECT_MATRIX: { /* Get the right amount of buttons based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); - if (spec != NULL) { + if (spec != nullptr) { if (spec->views >= 2) size->width += resize->width; if (spec->views >= 4) size->height += resize->height; } @@ -185,7 +185,7 @@ public: /* Get the right size for the single widget based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); - if (spec != NULL) { + if (spec != nullptr) { if (spec->views >= 2) size->width = size->width / 2 - 1; if (spec->views >= 4) size->height = size->height / 2 - 1; } @@ -210,7 +210,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { @@ -229,7 +229,7 @@ public: case WID_BO_OBJECT_SPRITE: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); - if (spec == NULL) break; + if (spec == nullptr) break; /* Height of the selection matrix. * Depending on the number of views, the matrix has a 1x1, 1x2, 2x1 or 2x2 layout. To make the previews @@ -243,7 +243,7 @@ public: if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; - if (spec->grf_prop.grffile == NULL) { + if (spec->grf_prop.grffile == nullptr) { extern const DrawTileSprites _objects[]; const DrawTileSprites *dts = &_objects[spec->grf_prop.local_id]; DrawOrigTileSeqInGUI((r.right - r.left) / 2 - 1, (r.bottom - r.top + matrix_height / 2) / 2 - OBJECT_MARGIN - ScaleGUITrad(TILE_PIXELS), dts, PAL_NONE); @@ -260,7 +260,7 @@ public: int obj_index = objclass->GetIndexFromUI(GB(widget, 16, 16)); if (obj_index < 0) break; const ObjectSpec *spec = objclass->GetSpec(obj_index); - if (spec == NULL) break; + if (spec == nullptr) break; if (!spec->IsAvailable()) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); @@ -270,7 +270,7 @@ public: if (FillDrawPixelInfo(&tmp_dpi, r.left + 1, r.top, (r.right - 1) - (r.left + 1) + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; - if (spec->grf_prop.grffile == NULL) { + if (spec->grf_prop.grffile == nullptr) { extern const DrawTileSprites _objects[]; const DrawTileSprites *dts = &_objects[spec->grf_prop.local_id]; DrawOrigTileSeqInGUI((r.right - r.left) / 2 - 1, r.bottom - r.top - OBJECT_MARGIN - ScaleGUITrad(TILE_PIXELS), dts, PAL_NONE); @@ -285,11 +285,11 @@ public: case WID_BO_INFO: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); - if (spec == NULL) break; + if (spec == nullptr) break; /* Get the extra message for the GUI */ if (HasBit(spec->callback_mask, CBM_OBJ_FUND_MORE_TEXT)) { - uint16 callback_res = GetObjectCallback(CBID_OBJECT_FUND_MORE_TEXT, 0, 0, spec, NULL, INVALID_TILE, _selected_object_view); + uint16 callback_res = GetObjectCallback(CBID_OBJECT_FUND_MORE_TEXT, 0, 0, spec, nullptr, INVALID_TILE, _selected_object_view); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { if (callback_res > 0x400) { ErrorUnknownCallbackResult(spec->grf_prop.grffile->grfid, CBID_OBJECT_FUND_MORE_TEXT, callback_res); @@ -382,12 +382,12 @@ public: this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_BO_CLASS_LIST); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { @@ -415,13 +415,13 @@ public: } } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { DoCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->UpdateButtons(_selected_object_class, -1, _selected_object_view); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 077838cafd..8ca080989f 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -53,6 +53,7 @@ #include "engine_func.h" #include "core/random_func.hpp" #include "rail_gui.h" +#include "road_gui.h" #include "core/backup_type.hpp" #include "hotkeys.h" #include "newgrf.h" @@ -69,6 +70,7 @@ #include "linkgraph/linkgraphschedule.h" #include +#include #include "safeguards.h" @@ -99,7 +101,7 @@ void CDECL usererror(const char *s, ...) va_end(va); ShowOSErrorBox(buf, false); - if (VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop(); + if (VideoDriver::GetInstance() != nullptr) VideoDriver::GetInstance()->Stop(); exit(1); } @@ -118,7 +120,7 @@ void CDECL error(const char *s, ...) vseprintf(buf, lastof(buf), s, va); va_end(va); - if (VideoDriver::GetInstance() == NULL || VideoDriver::GetInstance()->HasGUI()) { + if (VideoDriver::GetInstance() == nullptr || VideoDriver::GetInstance()->HasGUI()) { ShowOSErrorBox(buf, true); } @@ -165,16 +167,14 @@ static void ShowHelp() " -e = Start Editor\n" " -g [savegame] = Start new/save game immediately\n" " -G seed = Set random seed\n" -#if defined(ENABLE_NETWORK) " -n [ip:port#company]= Join network game\n" " -p password = Password to join server\n" " -P password = Password to join company\n" " -D [ip][:port] = Start dedicated server\n" " -l ip[:port] = Redirect DEBUG()\n" -#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(_WIN32) +#if !defined(_WIN32) " -f = Fork into the background (dedicated only)\n" #endif -#endif /* ENABLE_NETWORK */ " -I graphics_set = Force the graphics set (see below)\n" " -S sounds_set = Force the sounds set (see below)\n" " -M music_set = Force the music set (see below)\n" @@ -244,7 +244,7 @@ static void WriteSavegameInfo(const char *name) p = strecpy(p, "NewGRFs:\n", lastof(buf)); if (_load_check_data.HasNewGrfs()) { - for (GRFConfig *c = _load_check_data.grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _load_check_data.grfconfig; c != nullptr; c = c->next) { char md5sum[33]; md5sumToString(md5sum, lastof(md5sum), HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum); p += seprintf(p, lastof(buf), "%08X %s %s\n", c->ident.grfid, md5sum, c->filename); @@ -270,13 +270,13 @@ static void WriteSavegameInfo(const char *name) static void ParseResolution(Dimension *res, const char *s) { const char *t = strchr(s, 'x'); - if (t == NULL) { + if (t == nullptr) { ShowInfoF("Invalid resolution '%s'", s); return; } - res->width = max(strtoul(s, NULL, 0), 64UL); - res->height = max(strtoul(t + 1, NULL, 0), 64UL); + res->width = max(strtoul(s, nullptr, 0), 64UL); + res->height = max(strtoul(t + 1, nullptr, 0), 64UL); } @@ -301,9 +301,7 @@ static void ShutdownGame() /* Uninitialize variables that are allocated dynamically */ GamelogReset(); -#ifdef ENABLE_NETWORK free(_config_file); -#endif LinkGraphSchedule::Clear(); PoolBase::Clean(PT_ALL); @@ -352,11 +350,11 @@ static void LoadIntroGame(bool load_newgrfs = true) void MakeNewgameSettingsLive() { for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - if (_settings_game.ai_config[c] != NULL) { + if (_settings_game.ai_config[c] != nullptr) { delete _settings_game.ai_config[c]; } } - if (_settings_game.game_config != NULL) { + if (_settings_game.game_config != nullptr) { delete _settings_game.game_config; } @@ -366,16 +364,16 @@ void MakeNewgameSettingsLive() _old_vds = _settings_client.company.vehicle; for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - _settings_game.ai_config[c] = NULL; - if (_settings_newgame.ai_config[c] != NULL) { + _settings_game.ai_config[c] = nullptr; + if (_settings_newgame.ai_config[c] != nullptr) { _settings_game.ai_config[c] = new AIConfig(_settings_newgame.ai_config[c]); if (!AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->HasScript()) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(NULL); + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr); } } } - _settings_game.game_config = NULL; - if (_settings_newgame.game_config != NULL) { + _settings_game.game_config = nullptr; + if (_settings_newgame.game_config != nullptr) { _settings_game.game_config = new GameConfig(_settings_newgame.game_config); } } @@ -395,7 +393,7 @@ struct AfterNewGRFScan : NewGRFScanCallback { uint32 generation_seed; ///< Seed for the new game. char *dedicated_host; ///< Hostname for the dedicated server. uint16 dedicated_port; ///< Port for the dedicated server. - char *network_conn; ///< Information about the server to connect to, or NULL. + char *network_conn; ///< Information about the server to connect to, or nullptr. const char *join_server_password; ///< The password to join the server with. const char *join_company_password; ///< The password to join the company with. bool *save_config_ptr; ///< The pointer to the save config setting. @@ -408,8 +406,8 @@ struct AfterNewGRFScan : NewGRFScanCallback { */ AfterNewGRFScan(bool *save_config_ptr) : startyear(INVALID_YEAR), generation_seed(GENERATE_NEW_SEED), - dedicated_host(NULL), dedicated_port(0), network_conn(NULL), - join_server_password(NULL), join_company_password(NULL), + dedicated_host(nullptr), dedicated_port(0), network_conn(nullptr), + join_server_password(nullptr), join_company_password(nullptr), save_config_ptr(save_config_ptr), save_config(true) { /* Visual C++ 2015 fails compiling this line (AfterNewGRFScan::generation_seed undefined symbol) @@ -436,7 +434,6 @@ struct AfterNewGRFScan : NewGRFScanCallback { Game::Uninitialize(true); AI::Uninitialize(true); - CheckConfig(); LoadFromHighScore(); LoadHotkeysFromConfig(); WindowDesc::LoadFromConfig(); @@ -450,13 +447,11 @@ struct AfterNewGRFScan : NewGRFScanCallback { if (startyear != INVALID_YEAR) _settings_newgame.game_creation.starting_year = startyear; if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed; -#if defined(ENABLE_NETWORK) - if (dedicated_host != NULL) { - _network_bind_list.Clear(); - *_network_bind_list.Append() = stredup(dedicated_host); + if (dedicated_host != nullptr) { + _network_bind_list.clear(); + _network_bind_list.emplace_back(dedicated_host); } if (dedicated_port != 0) _settings_client.network.server_port = dedicated_port; -#endif /* ENABLE_NETWORK */ /* initialize the ingame console */ IConsoleInit(); @@ -466,16 +461,15 @@ struct AfterNewGRFScan : NewGRFScanCallback { /* Make sure _settings is filled with _settings_newgame if we switch to a game directly */ if (_switch_mode != SM_NONE) MakeNewgameSettingsLive(); -#ifdef ENABLE_NETWORK - if (_network_available && network_conn != NULL) { - const char *port = NULL; - const char *company = NULL; + if (_network_available && network_conn != nullptr) { + const char *port = nullptr; + const char *company = nullptr; uint16 rport = NETWORK_DEFAULT_PORT; CompanyID join_as = COMPANY_NEW_COMPANY; ParseConnectionString(&company, &port, network_conn); - if (company != NULL) { + if (company != nullptr) { join_as = (CompanyID)atoi(company); if (join_as != COMPANY_SPECTATOR) { @@ -486,20 +480,19 @@ struct AfterNewGRFScan : NewGRFScanCallback { } } } - if (port != NULL) rport = atoi(port); + if (port != nullptr) rport = atoi(port); LoadIntroGame(); _switch_mode = SM_NONE; NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password); } -#endif /* ENABLE_NETWORK */ /* After the scan we're not used anymore. */ delete this; } }; -#if defined(UNIX) && !defined(__MORPHOS__) +#if defined(UNIX) extern void DedicatedFork(); #endif @@ -512,16 +505,14 @@ static const OptionData _options[] = { GETOPT_SHORT_VALUE('s'), GETOPT_SHORT_VALUE('v'), GETOPT_SHORT_VALUE('b'), -#if defined(ENABLE_NETWORK) GETOPT_SHORT_OPTVAL('D'), GETOPT_SHORT_OPTVAL('n'), GETOPT_SHORT_VALUE('l'), GETOPT_SHORT_VALUE('p'), GETOPT_SHORT_VALUE('P'), -#if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(_WIN32) +#if !defined(_WIN32) GETOPT_SHORT_NOVAL('f'), #endif -#endif /* ENABLE_NETWORK */ GETOPT_SHORT_VALUE('r'), GETOPT_SHORT_VALUE('t'), GETOPT_SHORT_OPTVAL('d'), @@ -543,28 +534,29 @@ static const OptionData _options[] = { */ int openttd_main(int argc, char *argv[]) { - char *musicdriver = NULL; - char *sounddriver = NULL; - char *videodriver = NULL; - char *blitter = NULL; - char *graphics_set = NULL; - char *sounds_set = NULL; - char *music_set = NULL; + char *musicdriver = nullptr; + char *sounddriver = nullptr; + char *videodriver = nullptr; + char *blitter = nullptr; + char *graphics_set = nullptr; + char *sounds_set = nullptr; + char *music_set = nullptr; Dimension resolution = {0, 0}; /* AfterNewGRFScan sets save_config to true after scanning completed. */ bool save_config = false; AfterNewGRFScan *scanner = new AfterNewGRFScan(&save_config); -#if defined(ENABLE_NETWORK) bool dedicated = false; - char *debuglog_conn = NULL; + char *debuglog_conn = nullptr; extern bool _dedicated_forks; _dedicated_forks = false; -#endif /* ENABLE_NETWORK */ + + std::unique_lock modal_work_lock(_modal_progress_work_mutex, std::defer_lock); + std::unique_lock modal_paint_lock(_modal_progress_paint_mutex, std::defer_lock); _game_mode = GM_MENU; _switch_mode = SM_MENU; - _config_file = NULL; + _config_file = nullptr; GetOptData mgo(argc - 1, argv + 1, _options); int ret = 0; @@ -579,7 +571,6 @@ int openttd_main(int argc, char *argv[]) case 's': free(sounddriver); sounddriver = stredup(mgo.opt); break; case 'v': free(videodriver); videodriver = stredup(mgo.opt); break; case 'b': free(blitter); blitter = stredup(mgo.opt); break; -#if defined(ENABLE_NETWORK) case 'D': free(musicdriver); free(sounddriver); @@ -591,19 +582,19 @@ int openttd_main(int argc, char *argv[]) blitter = stredup("null"); dedicated = true; SetDebugString("net=6"); - if (mgo.opt != NULL) { + if (mgo.opt != nullptr) { /* Use the existing method for parsing (openttd -n). * However, we do ignore the #company part. */ - const char *temp = NULL; - const char *port = NULL; + const char *temp = nullptr; + const char *port = nullptr; ParseConnectionString(&temp, &port, mgo.opt); if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt; - if (port != NULL) scanner->dedicated_port = atoi(port); + if (port != nullptr) scanner->dedicated_port = atoi(port); } break; case 'f': _dedicated_forks = true; break; case 'n': - scanner->network_conn = mgo.opt; // optional IP parameter, NULL if unset + scanner->network_conn = mgo.opt; // optional IP parameter, nullptr if unset break; case 'l': debuglog_conn = mgo.opt; @@ -614,19 +605,18 @@ int openttd_main(int argc, char *argv[]) case 'P': scanner->join_company_password = mgo.opt; break; -#endif /* ENABLE_NETWORK */ case 'r': ParseResolution(&resolution, mgo.opt); break; case 't': scanner->startyear = atoi(mgo.opt); break; case 'd': { #if defined(_WIN32) CreateConsole(); #endif - if (mgo.opt != NULL) SetDebugString(mgo.opt); + if (mgo.opt != nullptr) SetDebugString(mgo.opt); break; } case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break; case 'g': - if (mgo.opt != NULL) { + if (mgo.opt != nullptr) { _file_to_saveload.SetName(mgo.opt); bool is_scenario = _switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO; _switch_mode = is_scenario ? SM_LOAD_SCENARIO : SM_LOAD_GAME; @@ -634,8 +624,8 @@ int openttd_main(int argc, char *argv[]) /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ const char *t = strrchr(_file_to_saveload.name, '.'); - if (t != NULL) { - FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, t, NULL, NULL); + if (t != nullptr) { + FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, t, nullptr, nullptr); if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft); } @@ -676,7 +666,7 @@ int openttd_main(int argc, char *argv[]) goto exit_noshutdown; } - case 'G': scanner->generation_seed = strtoul(mgo.opt, NULL, 10); break; + case 'G': scanner->generation_seed = strtoul(mgo.opt, nullptr, 10); break; case 'c': free(_config_file); _config_file = stredup(mgo.opt); break; case 'x': scanner->save_config = false; break; case 'h': @@ -705,14 +695,12 @@ int openttd_main(int argc, char *argv[]) DeterminePaths(argv[0]); TarScanner::DoScan(TarScanner::BASESET); -#if defined(ENABLE_NETWORK) if (dedicated) DEBUG(net, 0, "Starting dedicated version %s", _openttd_revision); if (_dedicated_forks && !dedicated) _dedicated_forks = false; -#if defined(UNIX) && !defined(__MORPHOS__) +#if defined(UNIX) /* We must fork here, or we'll end up without some resources we need (like sockets) */ if (_dedicated_forks) DedicatedFork(); -#endif #endif LoadFromConfig(true); @@ -744,10 +732,10 @@ int openttd_main(int argc, char *argv[]) InitWindowSystem(); BaseGraphics::FindSets(); - if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = stredup(BaseGraphics::ini_set); + if (graphics_set == nullptr && BaseGraphics::ini_set != nullptr) graphics_set = stredup(BaseGraphics::ini_set); if (!BaseGraphics::SetSet(graphics_set)) { if (!StrEmpty(graphics_set)) { - BaseGraphics::SetSet(NULL); + BaseGraphics::SetSet(nullptr); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); msg.SetDParamStr(0, graphics_set); @@ -760,7 +748,7 @@ int openttd_main(int argc, char *argv[]) GfxInitPalettes(); DEBUG(misc, 1, "Loading blitter..."); - if (blitter == NULL && _ini_blitter != NULL) blitter = stredup(_ini_blitter); + if (blitter == nullptr && _ini_blitter != nullptr) blitter = stredup(_ini_blitter); _blitter_autodetected = StrEmpty(blitter); /* Activate the initial blitter. * This is only some initial guess, after NewGRFs have been loaded SwitchNewGRFBlitter may switch to a different one. @@ -769,9 +757,9 @@ int openttd_main(int argc, char *argv[]) * - Use 8bpp blitter otherwise. */ if (!_blitter_autodetected || - (_support8bpp != S8BPP_NONE && (BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP)) || - BlitterFactory::SelectBlitter("32bpp-anim") == NULL) { - if (BlitterFactory::SelectBlitter(blitter) == NULL) { + (_support8bpp != S8BPP_NONE && (BaseGraphics::GetUsedSet() == nullptr || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP)) || + BlitterFactory::SelectBlitter("32bpp-anim") == nullptr) { + if (BlitterFactory::SelectBlitter(blitter) == nullptr) { StrEmpty(blitter) ? usererror("Failed to autoprobe blitter") : usererror("Failed to select requested blitter '%s'; does it exist?", blitter); @@ -779,7 +767,7 @@ int openttd_main(int argc, char *argv[]) } free(blitter); - if (videodriver == NULL && _ini_videodriver != NULL) videodriver = stredup(_ini_videodriver); + if (videodriver == nullptr && _ini_videodriver != nullptr) videodriver = stredup(_ini_videodriver); DriverFactoryBase::SelectDriver(videodriver, Driver::DT_VIDEO); free(videodriver); @@ -790,20 +778,18 @@ int openttd_main(int argc, char *argv[]) NetworkStartUp(); // initialize network-core -#if defined(ENABLE_NETWORK) - if (debuglog_conn != NULL && _network_available) { - const char *not_used = NULL; - const char *port = NULL; + if (debuglog_conn != nullptr && _network_available) { + const char *not_used = nullptr; + const char *port = nullptr; uint16 rport; rport = NETWORK_DEFAULT_DEBUGLOG_PORT; ParseConnectionString(¬_used, &port, debuglog_conn); - if (port != NULL) rport = atoi(port); + if (port != nullptr) rport = atoi(port); NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); } -#endif /* ENABLE_NETWORK */ if (!HandleBootstrap()) { ShutdownGame(); @@ -817,9 +803,9 @@ int openttd_main(int argc, char *argv[]) InitializeScreenshotFormats(); BaseSounds::FindSets(); - if (sounds_set == NULL && BaseSounds::ini_set != NULL) sounds_set = stredup(BaseSounds::ini_set); + if (sounds_set == nullptr && BaseSounds::ini_set != nullptr) sounds_set = stredup(BaseSounds::ini_set); if (!BaseSounds::SetSet(sounds_set)) { - if (StrEmpty(sounds_set) || !BaseSounds::SetSet(NULL)) { + if (StrEmpty(sounds_set) || !BaseSounds::SetSet(nullptr)) { usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND); @@ -830,9 +816,9 @@ int openttd_main(int argc, char *argv[]) free(sounds_set); BaseMusic::FindSets(); - if (music_set == NULL && BaseMusic::ini_set != NULL) music_set = stredup(BaseMusic::ini_set); + if (music_set == nullptr && BaseMusic::ini_set != nullptr) music_set = stredup(BaseMusic::ini_set); if (!BaseMusic::SetSet(music_set)) { - if (StrEmpty(music_set) || !BaseMusic::SetSet(NULL)) { + if (StrEmpty(music_set) || !BaseMusic::SetSet(nullptr)) { usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of README.md."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND); @@ -842,17 +828,23 @@ int openttd_main(int argc, char *argv[]) } free(music_set); - if (sounddriver == NULL && _ini_sounddriver != NULL) sounddriver = stredup(_ini_sounddriver); + if (sounddriver == nullptr && _ini_sounddriver != nullptr) sounddriver = stredup(_ini_sounddriver); DriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND); free(sounddriver); - if (musicdriver == NULL && _ini_musicdriver != NULL) musicdriver = stredup(_ini_musicdriver); + if (musicdriver == nullptr && _ini_musicdriver != nullptr) musicdriver = stredup(_ini_musicdriver); DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC); free(musicdriver); /* Take our initial lock on whatever we might want to do! */ - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); + try { + modal_work_lock.lock(); + modal_paint_lock.lock(); + } catch (const std::system_error&) { + /* If there is some error we assume that threads aren't usable on the system we run. */ + extern bool _use_threaded_modal_progress; // From progress.cpp + _use_threaded_modal_progress = false; + } GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy WaitTillGeneratedWorld(); @@ -863,11 +855,12 @@ int openttd_main(int argc, char *argv[]) /* ScanNewGRFFiles now has control over the scanner. */ ScanNewGRFFiles(scanner); - scanner = NULL; + scanner = nullptr; VideoDriver::GetInstance()->MainLoop(); WaitTillSaved(); + WaitTillGeneratedWorld(); // Make sure any generate world threads have been joined. /* only save config if we have to */ if (save_config) { @@ -906,12 +899,10 @@ exit_normal: delete scanner; -#ifdef ENABLE_NETWORK extern FILE *_log_fd; - if (_log_fd != NULL) { + if (_log_fd != nullptr) { fclose(_log_fd); } -#endif /* ENABLE_NETWORK */ return ret; } @@ -959,14 +950,13 @@ static void MakeNewGameDone() SetLocalCompany(COMPANY_FIRST); InitializeRailGUI(); + InitializeRoadGUI(); -#ifdef ENABLE_NETWORK /* We are the server, we start a new company (not dedicated), * so set the default password *if* needed. */ if (_network_server && !StrEmpty(_settings_client.network.default_company_pass)) { NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass); } -#endif /* ENABLE_NETWORK */ if (_settings_client.gui.pause_on_newgame) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); @@ -1008,21 +998,20 @@ static void MakeNewEditorWorld() * @param fop mode of loading, always SLO_LOAD * @param newgm switch to this mode of loading fails due to some unknown error * @param subdir default directory to look for filename, set to 0 if not needed - * @param lf Load filter to use, if NULL: use filename + subdir. + * @param lf Load filter to use, if nullptr: use filename + subdir. */ -bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL) +bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr) { assert(fop == SLO_LOAD); - assert(dft == DFT_GAME_FILE || (lf == NULL && dft == DFT_OLD_GAME_FILE)); + assert(dft == DFT_GAME_FILE || (lf == nullptr && dft == DFT_OLD_GAME_FILE)); GameMode ogm = _game_mode; _game_mode = newgm; - switch (lf == NULL ? SaveOrLoad(filename, fop, dft, subdir) : LoadWithFilter(lf)) { + switch (lf == nullptr ? SaveOrLoad(filename, fop, dft, subdir) : LoadWithFilter(lf)) { case SL_OK: return true; case SL_REINIT: -#ifdef ENABLE_NETWORK if (_network_dedicated) { /* * We need to reinit a network map... @@ -1038,7 +1027,6 @@ bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, /* We can't load the intro game as server, so disconnect first. */ NetworkDisconnect(); } -#endif /* ENABLE_NETWORK */ switch (ogm) { default: @@ -1055,7 +1043,6 @@ bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, void SwitchToMode(SwitchMode new_mode) { -#ifdef ENABLE_NETWORK /* If we are saving something, the network stays in his current state */ if (new_mode != SM_SAVE_GAME) { /* If the network is active, make it not-active */ @@ -1084,7 +1071,7 @@ void SwitchToMode(SwitchMode new_mode) } } } -#endif /* ENABLE_NETWORK */ + /* Make sure all AI controllers are gone at quitting game */ if (new_mode != SM_SAVE_GAME) AI::KillAll(); @@ -1095,11 +1082,9 @@ void SwitchToMode(SwitchMode new_mode) case SM_RESTARTGAME: // Restart --> 'Random game' with current settings case SM_NEWGAME: // New Game --> 'Random game' -#ifdef ENABLE_NETWORK if (_network_server) { seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "Random Map"); } -#endif /* ENABLE_NETWORK */ MakeNewGame(false, new_mode == SM_NEWGAME); break; @@ -1122,21 +1107,17 @@ void SwitchToMode(SwitchMode new_mode) IConsoleCmdExec("exec scripts/game_start.scr 0"); /* Decrease pause counter (was increased from opening load dialog) */ DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE); -#ifdef ENABLE_NETWORK if (_network_server) { seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title); } -#endif /* ENABLE_NETWORK */ } break; } case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it -#ifdef ENABLE_NETWORK if (_network_server) { seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title); } -#endif /* ENABLE_NETWORK */ MakeNewGame(true, true); break; @@ -1162,7 +1143,7 @@ void SwitchToMode(SwitchMode new_mode) case SM_MENU: // Switch to game intro menu LoadIntroGame(); - if (BaseSounds::ini_set == NULL && BaseSounds::GetUsedSet()->fallback) { + if (BaseSounds::ini_set == nullptr && BaseSounds::GetUsedSet()->fallback) { ShowErrorMessage(STR_WARNING_FALLBACK_SOUNDSET, INVALID_STRING_ID, WL_CRITICAL); BaseSounds::ini_set = stredup(BaseSounds::GetUsedSet()->name); } @@ -1208,10 +1189,10 @@ static void CheckCaches() if (_debug_desync_level <= 1) return; /* Check the town caches. */ - SmallVector old_town_caches; + std::vector old_town_caches; Town *t; FOR_ALL_TOWNS(t) { - MemCpyT(old_town_caches.Append(), &t->cache); + old_town_caches.push_back(t->cache); } extern void RebuildTownCaches(); @@ -1220,23 +1201,23 @@ static void CheckCaches() uint i = 0; FOR_ALL_TOWNS(t) { - if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) { + if (MemCmpT(old_town_caches.data() + i, &t->cache) != 0) { DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index); } i++; } /* Check company infrastructure cache. */ - SmallVector old_infrastructure; + std::vector old_infrastructure; Company *c; - FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); + FOR_ALL_COMPANIES(c) old_infrastructure.push_back(c->infrastructure); extern void AfterLoadCompanyStats(); AfterLoadCompanyStats(); i = 0; FOR_ALL_COMPANIES(c) { - if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { + if (MemCmpT(old_infrastructure.data() + i, &c->infrastructure) != 0) { DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index); } i++; @@ -1258,7 +1239,7 @@ static void CheckCaches() if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; uint length = 0; - for (const Vehicle *u = v; u != NULL; u = u->Next()) length++; + for (const Vehicle *u = v; u != nullptr; u = u->Next()) length++; NewGRFCache *grf_cache = CallocT(length); VehicleCache *veh_cache = CallocT(length); @@ -1266,7 +1247,7 @@ static void CheckCaches() TrainCache *tra_cache = CallocT(length); length = 0; - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { FillNewGRFVehicleCache(u); grf_cache[length] = u->grf_cache; veh_cache[length] = u->vcache; @@ -1293,7 +1274,7 @@ static void CheckCaches() } length = 0; - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); @@ -1398,7 +1379,7 @@ void StateGameLoop() /* All these actions has to be done from OWNER_NONE * for multiplayer compatibility */ - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP); AnimateAnimatedTiles(); @@ -1454,10 +1435,8 @@ static void DoAutosave() void GameLoop() { if (_game_mode == GM_BOOTSTRAP) { -#ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkBackgroundLoop(); -#endif InputLoop(); return; } @@ -1480,7 +1459,6 @@ void GameLoop() IncreaseSpriteLRU(); InteractiveRandom(); -#ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkBackgroundLoop(); @@ -1496,9 +1474,6 @@ void GameLoop() /* Singleplayer */ StateGameLoop(); } -#else - StateGameLoop(); -#endif /* ENABLE_NETWORK */ if (!_pause_mode && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations(); diff --git a/src/openttd.h b/src/openttd.h index 5e360d6fcd..539b7e14f1 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -54,7 +54,7 @@ extern SwitchMode _switch_mode; extern bool _exit_game; /** Modes of pausing we've got */ -enum PauseMode { +enum PauseMode : byte { PM_UNPAUSED = 0, ///< A normal unpaused game PM_PAUSED_NORMAL = 1 << 0, ///< A game normally paused PM_PAUSED_SAVELOAD = 1 << 1, ///< A game paused for saving/loading @@ -67,10 +67,9 @@ enum PauseMode { PMB_PAUSED_NETWORK = PM_PAUSED_ACTIVE_CLIENTS | PM_PAUSED_JOIN, }; DECLARE_ENUM_AS_BIT_SET(PauseMode) -typedef SimpleTinyEnumT PauseModeByte; /** The current pause mode */ -extern PauseModeByte _pause_mode; +extern PauseMode _pause_mode; void AskExitGame(); void AskExitToGameMenu(); diff --git a/src/order_backup.cpp b/src/order_backup.cpp index 58d1b40606..4f8b13fa00 100644 --- a/src/order_backup.cpp +++ b/src/order_backup.cpp @@ -30,7 +30,7 @@ OrderBackup::~OrderBackup() if (CleaningPool()) return; Order *o = this->orders; - while (o != NULL) { + while (o != nullptr) { Order *next = o->next; delete o; o = next; @@ -75,11 +75,11 @@ OrderBackup::OrderBackup(const Vehicle *v, uint32 user) void OrderBackup::DoRestore(Vehicle *v) { /* If we had shared orders, recover that */ - if (this->clone != NULL) { + if (this->clone != nullptr) { DoCommand(0, v->index | CO_SHARE << 30, this->clone->index, DC_EXEC, CMD_CLONE_ORDER); - } else if (this->orders != NULL && OrderList::CanAllocateItem()) { + } else if (this->orders != nullptr && OrderList::CanAllocateItem()) { v->orders.list = new OrderList(this->orders, v); - this->orders = NULL; + this->orders = nullptr; /* Make sure buoys/oil rigs are updated in the station list. */ InvalidateWindowClassesData(WC_STATION_LIST, 0); } @@ -193,11 +193,7 @@ CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, * but compiled it. A network client has its own variable for the unique * client/user identifier. Finally if networking isn't compiled in the * default is just plain and simple: 0. */ -#ifdef ENABLE_NETWORK uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER; -#else - uint32 user = 0; -#endif OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { @@ -210,7 +206,7 @@ CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, /* We need to circumvent the "prevention" from this command being executed * while the game is paused, so use the internal method. Nor do we want * this command to get its cost estimated when shift is pressed. */ - DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false); + DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, nullptr, nullptr, true, false); } else { /* The command came from the game logic, i.e. the clearing of a tile. * In that case we have no need to actually sync this, just do it. */ @@ -234,20 +230,20 @@ CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, /** * Clear/update the (clone) vehicle from an order backup. * @param v The vehicle to clear. - * @pre v != NULL + * @pre v != nullptr * @note If it is not possible to set another vehicle as clone * "example", then this backed up order will be removed. */ /* static */ void OrderBackup::ClearVehicle(const Vehicle *v) { - assert(v != NULL); + assert(v != nullptr); OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { if (ob->clone == v) { /* Get another item in the shared list. */ ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared(); /* But if that isn't there, remove it. */ - if (ob->clone == NULL) delete ob; + if (ob->clone == nullptr) delete ob; } } } @@ -264,7 +260,7 @@ CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { - for (Order *order = ob->orders; order != NULL; order = order->next) { + for (Order *order = ob->orders; order != nullptr; order = order->next) { OrderType ot = order->GetType(); if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue; if (ot == OT_GOTO_DEPOT && hangar && !IsHangarTile(ob->tile)) continue; // Not an aircraft? Can't have a hangar order. diff --git a/src/order_base.h b/src/order_base.h index 0def7b0bcd..5164a4d6ef 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -48,9 +48,9 @@ private: uint16 max_speed; ///< How fast the vehicle may go on the way to the destination. public: - Order *next; ///< Pointer to next order. If NULL, end of list + Order *next; ///< Pointer to next order. If nullptr, end of list - Order() : refit_cargo(CT_NO_REFIT), max_speed(UINT16_MAX) {} + Order() : flags(0), refit_cargo(CT_NO_REFIT), max_speed(UINT16_MAX) {} ~Order(); Order(uint32 packed); @@ -268,7 +268,7 @@ private: public: /** Default constructor producing an invalid order list. */ OrderList(VehicleOrderID num_orders = INVALID_VEH_ORDER_ID) - : first(NULL), num_orders(num_orders), num_manual_orders(0), num_vehicles(0), first_shared(NULL), + : first(nullptr), num_orders(num_orders), num_manual_orders(0), num_vehicles(0), first_shared(nullptr), timetable_duration(0), total_duration(0) { } /** @@ -303,7 +303,7 @@ public: * @param curr Order to find the next one for. * @return Next order. */ - inline const Order *GetNext(const Order *curr) const { return (curr->next == NULL) ? this->GetFirstOrder() : curr->next; } + inline const Order *GetNext(const Order *curr) const { return (curr->next == nullptr) ? this->GetFirstOrder() : curr->next; } /** * Get number of orders in the order list. @@ -317,7 +317,7 @@ public: */ inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; } - StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first = NULL, uint hops = 0) const; + StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first = nullptr, uint hops = 0) const; const Order *GetNextDecisionNode(const Order *next, uint hops) const; void InsertOrderAt(Order *new_order, int index); @@ -396,7 +396,7 @@ public: #define FOR_ALL_ORDERS(var) FOR_ALL_ORDERS_FROM(var, 0) -#define FOR_VEHICLE_ORDERS(v, order) for (order = (v->orders.list == NULL) ? NULL : v->orders.list->GetFirstOrder(); order != NULL; order = order->next) +#define FOR_VEHICLE_ORDERS(v, order) for (order = (v->orders.list == nullptr) ? nullptr : v->orders.list->GetFirstOrder(); order != nullptr; order = order->next) #define FOR_ALL_ORDER_LISTS_FROM(var, start) FOR_ALL_ITEMS_FROM(OrderList, orderlist_index, var, start) diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 853eb81ec5..d560954294 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -23,7 +23,6 @@ #include "core/random_func.hpp" #include "aircraft.h" #include "roadveh.h" -#include "ship.h" #include "station_base.h" #include "waypoint_base.h" #include "company_base.h" @@ -54,7 +53,7 @@ Order::~Order() * the list of stations. So, we need to invalidate that window if needed. */ if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) { BaseStation *bs = BaseStation::GetIfValid(this->GetDestination()); - if (bs != NULL && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0); + if (bs != nullptr && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0); } } @@ -67,7 +66,7 @@ void Order::Free() this->type = OT_NOTHING; this->flags = 0; this->dest = 0; - this->next = NULL; + this->next = nullptr; } /** @@ -238,7 +237,7 @@ Order::Order(uint32 packed) this->type = (OrderType)GB(packed, 0, 8); this->flags = GB(packed, 8, 8); this->dest = GB(packed, 16, 16); - this->next = NULL; + this->next = nullptr; this->refit_cargo = CT_NO_REFIT; this->wait_time = 0; this->travel_time = 0; @@ -301,19 +300,19 @@ void OrderList::Initialize(Order *chain, Vehicle *v) this->timetable_duration = 0; this->total_duration = 0; - for (Order *o = this->first; o != NULL; o = o->next) { + for (Order *o = this->first; o != nullptr; o = o->next) { ++this->num_orders; if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders; this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel(); this->total_duration += o->GetWaitTime() + o->GetTravelTime(); } - for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) { + for (Vehicle *u = this->first_shared->PreviousShared(); u != nullptr; u = u->PreviousShared()) { ++this->num_vehicles; this->first_shared = u; } - for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles; + for (const Vehicle *u = v->NextShared(); u != nullptr; u = u->NextShared()) ++this->num_vehicles; } /** @@ -324,13 +323,13 @@ void OrderList::Initialize(Order *chain, Vehicle *v) void OrderList::FreeChain(bool keep_orderlist) { Order *next; - for (Order *o = this->first; o != NULL; o = next) { + for (Order *o = this->first; o != nullptr; o = next) { next = o->next; delete o; } if (keep_orderlist) { - this->first = NULL; + this->first = nullptr; this->num_orders = 0; this->num_manual_orders = 0; this->timetable_duration = 0; @@ -346,11 +345,11 @@ void OrderList::FreeChain(bool keep_orderlist) */ Order *OrderList::GetOrderAt(int index) const { - if (index < 0) return NULL; + if (index < 0) return nullptr; Order *order = this->first; - while (order != NULL && index-- > 0) { + while (order != nullptr && index-- > 0) { order = order->next; } return order; @@ -365,11 +364,11 @@ Order *OrderList::GetOrderAt(int index) const * \li a station order * \li a refitting depot order * \li a non-trivial conditional order - * \li NULL if the vehicle won't stop anymore. + * \li nullptr if the vehicle won't stop anymore. */ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const { - if (hops > this->GetNumOrders() || next == NULL) return NULL; + if (hops > this->GetNumOrders() || next == nullptr) return nullptr; if (next->IsType(OT_CONDITIONAL)) { if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next; @@ -382,7 +381,7 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const } if (next->IsType(OT_GOTO_DEPOT)) { - if (next->GetDepotActionType() == ODATFB_HALT) return NULL; + if (next->GetDepotActionType() == ODATFB_HALT) return nullptr; if (next->IsRefit()) return next; } @@ -396,9 +395,9 @@ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const /** * Recursively determine the next deterministic station to stop at. * @param v The vehicle we're looking at. - * @param first Order to start searching at or NULL to start at cur_implicit_order_index + 1. + * @param first Order to start searching at or nullptr to start at cur_implicit_order_index + 1. * @param hops Number of orders we have already looked at. - * @return Next stoppping station or INVALID_STATION. + * @return Next stopping station or INVALID_STATION. * @pre The vehicle is currently loading and v->last_station_visited is meaningful. * @note This function may draw a random number. Don't use it from the GUI. */ @@ -406,17 +405,17 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order * { const Order *next = first; - if (first == NULL) { + if (first == nullptr) { next = this->GetOrderAt(v->cur_implicit_order_index); - if (next == NULL) { + if (next == nullptr) { next = this->GetFirstOrder(); - if (next == NULL) return INVALID_STATION; + if (next == nullptr) return INVALID_STATION; } else { - /* GetNext never returns NULL if there is a valid station in the list. + /* GetNext never returns nullptr if there is a valid station in the list. * As the given "next" is already valid and a station in the list, we - * don't have to check for NULL here. */ + * don't have to check for nullptr here. */ next = this->GetNext(next); - assert(next != NULL); + assert(next != nullptr); } } @@ -424,16 +423,16 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order * next = this->GetNextDecisionNode(next, ++hops); /* Resolve possibly nested conditionals by estimation. */ - while (next != NULL && next->IsType(OT_CONDITIONAL)) { + while (next != nullptr && next->IsType(OT_CONDITIONAL)) { /* We return both options of conditional orders. */ const Order *skip_to = this->GetNextDecisionNode( this->GetOrderAt(next->GetConditionSkipToOrder()), hops); const Order *advance = this->GetNextDecisionNode( this->GetNext(next), hops); - if (advance == NULL || advance == first || skip_to == advance) { - next = (skip_to == first) ? NULL : skip_to; - } else if (skip_to == NULL || skip_to == first) { - next = (advance == first) ? NULL : advance; + if (advance == nullptr || advance == first || skip_to == advance) { + next = (skip_to == first) ? nullptr : skip_to; + } else if (skip_to == nullptr || skip_to == first) { + next = (advance == first) ? nullptr : advance; } else { StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops); StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops); @@ -444,7 +443,7 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order * } /* Don't return a next stop if the vehicle has to unload everything. */ - if (next == NULL || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) && + if (next == nullptr || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) && next->GetDestination() == v->last_station_visited && (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) { return INVALID_STATION; @@ -461,7 +460,7 @@ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order * */ void OrderList::InsertOrderAt(Order *new_order, int index) { - if (this->first == NULL) { + if (this->first == nullptr) { this->first = new_order; } else { if (index == 0) { @@ -567,7 +566,7 @@ void OrderList::RemoveVehicle(Vehicle *v) */ bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const { - for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) { + for (const Vehicle *v_shared = this->first_shared; v_shared != nullptr; v_shared = v_shared->NextShared()) { if (v_shared == v) return true; } @@ -582,7 +581,7 @@ bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const { int count = 0; - for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++; + for (const Vehicle *v_shared = v->PreviousShared(); v_shared != nullptr; v_shared = v_shared->PreviousShared()) count++; return count; } @@ -592,7 +591,7 @@ int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const */ bool OrderList::IsCompleteTimetable() const { - for (Order *o = this->first; o != NULL; o = o->next) { + for (Order *o = this->first; o != nullptr; o = o->next) { /* Implicit orders are, by definition, not timetabled. */ if (o->IsType(OT_IMPLICIT)) continue; if (!o->IsCompletelyTimetabled()) return false; @@ -613,7 +612,7 @@ void OrderList::DebugCheckSanity() const DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index); - for (const Order *o = this->first; o != NULL; o = o->next) { + for (const Order *o = this->first; o != nullptr; o = o->next) { ++check_num_orders; if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders; check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel(); @@ -624,7 +623,7 @@ void OrderList::DebugCheckSanity() const assert(this->timetable_duration == check_timetable_duration); assert(this->total_duration == check_total_duration); - for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) { + for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) { ++check_num_vehicles; assert(v->orders.list == this); } @@ -703,7 +702,7 @@ uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth++; int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth); - int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth); + int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth); return max(dist1, dist2); } @@ -733,7 +732,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Order new_order(p2); Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -743,7 +742,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 switch (new_order.GetType()) { case OT_GOTO_STATION: { const Station *st = Station::GetIfValid(new_order.GetDestination()); - if (st == NULL) return CMD_ERROR; + if (st == nullptr) return CMD_ERROR; if (st->owner != OWNER_NONE) { CommandCost ret = CheckOwnership(st->owner); @@ -751,7 +750,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER); - for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) { + for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) { if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED); } @@ -790,7 +789,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (v->type == VEH_AIRCRAFT) { const Station *st = Station::GetIfValid(new_order.GetDestination()); - if (st == NULL) return CMD_ERROR; + if (st == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; @@ -801,7 +800,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 } else { const Depot *dp = Depot::GetIfValid(new_order.GetDestination()); - if (dp == NULL) return CMD_ERROR; + if (dp == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(GetTileOwner(dp->xy)); if (ret.Failed()) return ret; @@ -833,7 +832,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case OT_GOTO_WAYPOINT: { const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination()); - if (wp == NULL) return CMD_ERROR; + if (wp == nullptr) return CMD_ERROR; switch (v->type) { default: return CMD_ERROR; @@ -898,43 +897,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS); if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); - if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); - - if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) { - /* Make sure the new destination is not too far away from the previous */ - const Order *prev = NULL; - uint n = 0; - - /* Find the last goto station or depot order before the insert location. - * If the order is to be inserted at the beginning of the order list this - * finds the last order in the list. */ - const Order *o; - FOR_VEHICLE_ORDERS(v, o) { - switch (o->GetType()) { - case OT_GOTO_STATION: - case OT_GOTO_DEPOT: - case OT_GOTO_WAYPOINT: - prev = o; - break; - - default: break; - } - if (++n == sel_ord && prev != NULL) break; - } - if (prev != NULL) { - uint dist; - if (new_order.IsType(OT_CONDITIONAL)) { - /* The order is not yet inserted, so we have to do the first iteration here. */ - dist = GetOrderDistance(prev, v->GetOrder(new_order.GetConditionSkipToOrder()), v); - } else { - dist = GetOrderDistance(prev, &new_order, v); - } - - if (dist >= SHIP_MAX_ORDER_DISTANCE) { - return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION); - } - } - } + if (v->orders.list == nullptr && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); if (flags & DC_EXEC) { Order *new_o = new Order(); @@ -954,7 +917,7 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord) { /* Create new order and link in list */ - if (v->orders.list == NULL) { + if (v->orders.list == nullptr) { v->orders.list = new OrderList(new_o, v); } else { v->orders.list->InsertOrderAt(new_o, sel_ord); @@ -962,7 +925,7 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord) Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); - for (; u != NULL; u = u->NextShared()) { + for (; u != nullptr; u = u->NextShared()) { assert(v->orders.list == u->orders.list); /* If there is added an order before the current one, we need @@ -1045,7 +1008,7 @@ CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Vehicle *v = Vehicle::GetIfValid(veh_id); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1053,7 +1016,7 @@ CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /* If we did not select an order, we maybe want to de-clone the orders */ if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags); - if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR; + if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR; if (flags & DC_EXEC) DeleteOrder(v, sel_ord); return CommandCost(); @@ -1085,7 +1048,7 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord) Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); - for (; u != NULL; u = u->NextShared()) { + for (; u != nullptr; u = u->NextShared()) { assert(v->orders.list == u->orders.list); if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) { @@ -1117,7 +1080,7 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord) /* As we delete an order, the order to skip to will be 'wrong'. */ VehicleOrderID cur_order_id = 0; - Order *order = NULL; + Order *order = nullptr; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); @@ -1151,7 +1114,7 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Vehicle *v = Vehicle::GetIfValid(veh_id); - if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1192,7 +1155,7 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 VehicleOrderID target_order = GB(p2, 16, 16); Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1203,7 +1166,7 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Order *moving_one = v->GetOrder(moving_order); /* Don't move an empty order */ - if (moving_one == NULL) return CMD_ERROR; + if (moving_one == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { v->orders.list->MoveOrder(moving_order, target_order); @@ -1213,7 +1176,7 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 DeleteOrderWarnings(u); - for (; u != NULL; u = u->NextShared()) { + for (; u != nullptr; u = u->NextShared()) { /* Update the current order. * There are multiple ways to move orders, which result in cur_implicit_order_index * and cur_real_order_index to not longer make any sense. E.g. moving another @@ -1299,7 +1262,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (mof >= MOF_END) return CMD_ERROR; Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1496,13 +1459,13 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /* Update the windows and full load flags, also for vehicles that share the same order list */ Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); - for (; u != NULL; u = u->NextShared()) { + for (; u != nullptr; u = u->NextShared()) { /* Toggle u->current_order "Full load" flag if it changed. * However, as the same flag is used for depot orders, check * whether we are not going to a depot as there are three * cases where the full load flag can be active and only * one case where the flag is used for depot orders. In the - * other cases for the OrderTypeByte the flags are not used, + * other cases for the OrderType the flags are not used, * so do not care and those orders should not be active * when this function is called. */ @@ -1527,17 +1490,17 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 */ static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first) { - if (first == NULL || v_new->acache.cached_max_range == 0) return true; + if (first == nullptr || v_new->acache.cached_max_range == 0) return true; /* Iterate over all orders to check the distance between all * 'goto' orders and their respective next order (of any type). */ - for (const Order *o = first; o != NULL; o = o->next) { + for (const Order *o = first; o != nullptr; o = o->next) { switch (o->GetType()) { case OT_GOTO_STATION: case OT_GOTO_DEPOT: case OT_GOTO_WAYPOINT: /* If we don't have a next order, we've reached the end and must check the first order instead. */ - if (GetOrderDistance(o, o->next != NULL ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false; + if (GetOrderDistance(o, o->next != nullptr ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false; break; default: break; @@ -1564,7 +1527,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 VehicleID veh_dst = GB(p1, 0, 20); Vehicle *dst = Vehicle::GetIfValid(veh_dst); - if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR; + if (dst == nullptr || !dst->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(dst->owner); if (ret.Failed()) return ret; @@ -1574,7 +1537,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Vehicle *src = Vehicle::GetIfValid(veh_src); /* Sanity checks */ - if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR; + if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR; CommandCost ret = CheckOwnership(src->owner); if (ret.Failed()) return ret; @@ -1606,7 +1569,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE); } - if (src->orders.list == NULL && !OrderList::CanAllocateItem()) { + if (src->orders.list == nullptr && !OrderList::CanAllocateItem()) { return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); } @@ -1633,7 +1596,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Vehicle *src = Vehicle::GetIfValid(veh_src); /* Sanity checks */ - if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR; + if (src == nullptr || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR; CommandCost ret = CheckOwnership(src->owner); if (ret.Failed()) return ret; @@ -1660,7 +1623,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (flags & DC_EXEC) { const Order *order; - Order *first = NULL; + Order *first = nullptr; Order **order_dst; /* If the destination vehicle had an order list, destroy the chain but keep the OrderList. @@ -1674,10 +1637,10 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 (*order_dst)->AssignOrder(*order); order_dst = &(*order_dst)->next; } - if (dst->orders.list == NULL) { + if (dst->orders.list == nullptr) { dst->orders.list = new OrderList(first, dst); } else { - assert(dst->orders.list->GetFirstOrder() == NULL); + assert(dst->orders.list->GetFirstOrder() == nullptr); assert(!dst->orders.list->IsShared()); delete dst->orders.list; assert(OrderList::CanAllocateItem()); @@ -1718,13 +1681,13 @@ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR; const Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; Order *order = v->GetOrder(order_number); - if (order == NULL) return CMD_ERROR; + if (order == nullptr) return CMD_ERROR; /* Automatic refit cargo is only supported for goto station orders. */ if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR; @@ -1740,7 +1703,7 @@ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT)); } - for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) { + for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) { /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS); @@ -1819,7 +1782,7 @@ void CheckOrders(const Vehicle *v) if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS; #ifndef NDEBUG - if (v->orders.list != NULL) v->orders.list->DebugCheckSanity(); + if (v->orders.list != nullptr) v->orders.list->DebugCheckSanity(); #endif /* We don't have a problem */ @@ -1874,7 +1837,7 @@ restart: if (order->IsType(OT_IMPLICIT)) { order = order->next; // DeleteOrder() invalidates current order DeleteOrder(v, id); - if (order != NULL) goto restart; + if (order != nullptr) goto restart; break; } @@ -1891,7 +1854,7 @@ restart: order->MakeDummy(); order->SetTravelTimetabled(travel_timetabled); - for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) { + for (const Vehicle *w = v->FirstShared(); w != nullptr; w = w->NextShared()) { /* In GUI, simulate by removing the order and adding it back */ InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8)); InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id); @@ -1934,11 +1897,11 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indic if (v->IsOrderListShared()) { /* Remove ourself from the shared order list. */ v->RemoveFromShared(); - v->orders.list = NULL; - } else if (v->orders.list != NULL) { + v->orders.list = nullptr; + } else if (v->orders.list != nullptr) { /* Remove the orders */ v->orders.list->FreeChain(keep_orderlist); - if (!keep_orderlist) v->orders.list = NULL; + if (!keep_orderlist) v->orders.list = nullptr; } if (reset_order_indices) { @@ -2020,7 +1983,7 @@ VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v) uint16 value = order->GetConditionValue(); switch (order->GetConditionVariable()) { - case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break; + case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break; case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break; case OCV_MAX_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability), value); break; case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break; @@ -2147,12 +2110,12 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool /* Get the current order */ order = v->GetOrder(v->cur_real_order_index); - if (order != NULL && order->IsType(OT_IMPLICIT)) { + if (order != nullptr && order->IsType(OT_IMPLICIT)) { assert(v->GetNumManualOrders() == 0); - order = NULL; + order = nullptr; } - if (order == NULL) { + if (order == nullptr) { v->current_order.Free(); v->SetDestTile(0); return false; @@ -2215,13 +2178,13 @@ bool ProcessOrders(Vehicle *v) v->UpdateRealOrderIndex(); const Order *order = v->GetOrder(v->cur_real_order_index); - if (order != NULL && order->IsType(OT_IMPLICIT)) { + if (order != nullptr && order->IsType(OT_IMPLICIT)) { assert(v->GetNumManualOrders() == 0); - order = NULL; + order = nullptr; } /* If no order, do nothing. */ - if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) { + if (order == nullptr || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) { if (v->type == VEH_AIRCRAFT) { /* Aircraft do something vastly different here, so handle separately */ extern void HandleMissingAircraftOrders(Aircraft *v); @@ -2236,7 +2199,7 @@ bool ProcessOrders(Vehicle *v) /* If it is unchanged, keep it. */ if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) && - (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) { + (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->ship_station.tile != INVALID_TILE)) { return false; } diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 1584c75508..8b08b4af8f 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -24,6 +24,7 @@ #include "tilehighlight_func.h" #include "network/network.h" #include "station_base.h" +#include "industry.h" #include "waypoint_base.h" #include "core/geometry_func.hpp" #include "hotkeys.h" @@ -311,7 +312,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int /* Check range for aircraft. */ if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0 && order->IsGotoOrder()) { - const Order *next = order->next != NULL ? order->next : v->GetFirstOrder(); + const Order *next = order->next != nullptr ? order->next : v->GetFirstOrder(); if (GetOrderDistance(order, next, v) > Aircraft::From(v)->acache.cached_max_range_sqr) SetDParam(8, STR_ORDER_OUT_OF_RANGE); } @@ -474,20 +475,29 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile) return order; } - if (IsTileType(tile, MP_STATION)) { - StationID st_index = GetStationIndex(tile); - const Station *st = Station::Get(st_index); + /* check for station or industry with neutral station */ + if (IsTileType(tile, MP_STATION) || IsTileType(tile, MP_INDUSTRY)) { + const Station *st = nullptr; - if (st->owner == _local_company || st->owner == OWNER_NONE) { + if (IsTileType(tile, MP_STATION)) { + st = Station::GetByTile(tile); + } else { + const Industry *in = Industry::GetByTile(tile); + st = in->neutral_station; + } + if (st != nullptr && (st->owner == _local_company || st->owner == OWNER_NONE)) { byte facil; - (facil = FACIL_DOCK, v->type == VEH_SHIP) || - (facil = FACIL_TRAIN, v->type == VEH_TRAIN) || - (facil = FACIL_AIRPORT, v->type == VEH_AIRCRAFT) || - (facil = FACIL_BUS_STOP, v->type == VEH_ROAD && RoadVehicle::From(v)->IsBus()) || - (facil = FACIL_TRUCK_STOP, 1); + switch (v->type) { + case VEH_SHIP: facil = FACIL_DOCK; break; + case VEH_TRAIN: facil = FACIL_TRAIN; break; + case VEH_AIRCRAFT: facil = FACIL_AIRPORT; break; + case VEH_ROAD: facil = FACIL_BUS_STOP | FACIL_TRUCK_STOP; break; + default: NOT_REACHED(); + } if (st->facilities & facil) { + order.MakeGoToStation(st->index); + uint8 os = 0xff; - order.MakeGoToStation(st_index); if (_ctrl_pressed) { if (_shift_pressed) os = _settings_client.gui.goto_shortcuts_ctrlshift_lclick; @@ -686,7 +696,7 @@ private: VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); - if (order == NULL || order->GetLoadType() == load_type) return; + if (order == nullptr || order->GetLoadType() == load_type) return; if (load_type < 0) { load_type = order->GetLoadType() == OLF_LOAD_IF_POSSIBLE ? OLF_FULL_LOAD_ANY : OLF_LOAD_IF_POSSIBLE; @@ -711,7 +721,7 @@ private: if (i < 0) { const Order *order = this->vehicle->GetOrder(sel_ord); - if (order == NULL) return; + if (order == nullptr) return; i = (order->GetDepotOrderType() & ODTFB_SERVICE) ? DA_ALWAYS_GO : DA_SERVICE; } DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_DEPOT_ACTION | (i << 4), CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); @@ -723,7 +733,7 @@ private: void OrderClick_NearestDepot() { Order order; - order.next = NULL; + order.next = nullptr; order.index = 0; order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS, _settings_client.gui.new_nonstop && this->vehicle->IsGroundVehicle() ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); @@ -740,7 +750,7 @@ private: VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); - if (order == NULL || order->GetUnloadType() == unload_type) return; + if (order == nullptr || order->GetUnloadType() == unload_type) return; if (unload_type < 0) { unload_type = order->GetUnloadType() == OUF_UNLOAD_IF_POSSIBLE ? OUFB_UNLOAD : OUF_UNLOAD_IF_POSSIBLE; @@ -789,7 +799,7 @@ private: VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); - if (order == NULL || order->GetNonStopType() == non_stop) return; + if (order == nullptr || order->GetNonStopType() == non_stop) return; /* Keypress if negative, so 'toggle' to the next */ if (non_stop < 0) { @@ -877,7 +887,7 @@ private: { this->can_do_refit = false; this->can_do_autorefit = false; - for (const Vehicle *w = this->vehicle; w != NULL; w = w->IsGroundVehicle() ? w->Next() : NULL) { + for (const Vehicle *w = this->vehicle; w != nullptr; w = w->IsGroundVehicle() ? w->Next() : nullptr) { if (IsEngineRefittable(w->engine_type)) this->can_do_refit = true; if (HasBit(Engine::Get(w->engine_type)->info.misc_flags, EF_AUTO_REFIT)) this->can_do_autorefit = true; } @@ -915,7 +925,7 @@ public: this->OnInvalidateData(VIWD_MODIFY_ORDERS); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_O_ORDER_LIST: @@ -952,7 +962,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { VehicleOrderID from = INVALID_VEH_ORDER_ID; VehicleOrderID to = INVALID_VEH_ORDER_ID; @@ -1070,11 +1080,11 @@ public: NWidgetStacked *right_sel = this->GetWidget(WID_O_SEL_TOP_RIGHT); /* Ship or airplane. */ NWidgetStacked *row_sel = this->GetWidget(WID_O_SEL_TOP_ROW); - assert(row_sel != NULL || (train_row_sel != NULL && left_sel != NULL && middle_sel != NULL && right_sel != NULL)); + assert(row_sel != nullptr || (train_row_sel != nullptr && left_sel != nullptr && middle_sel != nullptr && right_sel != nullptr)); - if (order == NULL) { - if (row_sel != NULL) { + if (order == nullptr) { + if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); @@ -1093,7 +1103,7 @@ public: switch (order->GetType()) { case OT_GOTO_STATION: - if (row_sel != NULL) { + if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); @@ -1115,7 +1125,7 @@ public: break; case OT_GOTO_WAYPOINT: - if (row_sel != NULL) { + if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); @@ -1131,7 +1141,7 @@ public: break; case OT_GOTO_DEPOT: - if (row_sel != NULL) { + if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_DEPOT); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); @@ -1150,7 +1160,7 @@ public: break; case OT_CONDITIONAL: { - if (row_sel != NULL) { + if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_CONDITIONAL); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_CONDITIONAL); @@ -1165,7 +1175,7 @@ public: } default: // every other order - if (row_sel != NULL) { + if (row_sel != nullptr) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); @@ -1187,7 +1197,7 @@ public: this->SetDirty(); } - virtual void OnPaint() + void OnPaint() override { if (this->vehicle->owner != _local_company) { this->selected_order = -1; // Disable selection any selected row at a competitor order window. @@ -1197,7 +1207,7 @@ public: this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_O_ORDER_LIST) return; @@ -1213,7 +1223,7 @@ public: const Order *order = this->vehicle->GetOrder(i); /* First draw the highlighting underground if it exists. */ if (this->order_over != INVALID_VEH_ORDER_ID) { - while (order != NULL) { + while (order != nullptr) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; @@ -1238,7 +1248,7 @@ public: } /* Draw the orders. */ - while (order != NULL) { + while (order != nullptr) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; @@ -1255,14 +1265,14 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_O_COND_VALUE: { VehicleOrderID sel = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel); - if (order != NULL && order->IsType(OT_CONDITIONAL)) { + if (order != nullptr && order->IsType(OT_CONDITIONAL)) { uint value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); SetDParam(0, value); @@ -1276,7 +1286,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_O_ORDER_LIST: { @@ -1284,7 +1294,7 @@ public: VehicleOrderID order_id = this->GetOrderFromPt(_cursor.pos.y - this->top); if (order_id != INVALID_VEH_ORDER_ID) { Order order; - order.next = NULL; + order.next = nullptr; order.index = 0; order.MakeConditional(order_id); @@ -1412,11 +1422,11 @@ public: break; case WID_O_COND_VARIABLE: { - DropDownList *list = new DropDownList(); + DropDownList list; for (uint i = 0; i < lengthof(_order_conditional_variable); i++) { - *list->Append() = new DropDownListStringItem(STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + _order_conditional_variable[i], _order_conditional_variable[i], false); + list.emplace_back(new DropDownListStringItem(STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + _order_conditional_variable[i], _order_conditional_variable[i], false)); } - ShowDropDownList(this, list, this->vehicle->GetOrder(this->OrderGetSel())->GetConditionVariable(), WID_O_COND_VARIABLE); + ShowDropDownList(this, std::move(list), this->vehicle->GetOrder(this->OrderGetSel())->GetConditionVariable(), WID_O_COND_VARIABLE); break; } @@ -1441,7 +1451,7 @@ public: } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { if (!StrEmpty(str)) { VehicleOrderID sel = this->OrderGetSel(); @@ -1464,7 +1474,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_O_NON_STOP: @@ -1507,7 +1517,7 @@ public: } } - virtual void OnDragDrop(Point pt, int widget) + void OnDragDrop(Point pt, int widget) override { switch (widget) { case WID_O_ORDER_LIST: { @@ -1540,7 +1550,7 @@ public: } } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { if (this->vehicle->owner != _local_company) return ES_NOT_HANDLED; if(hotkey == OHK_GOTO && this->goto_type != OPOS_NONE){ @@ -1567,7 +1577,7 @@ public: return ES_HANDLED; } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { if (this->goto_type == OPOS_GOTO) { const Order cmd = GetOrderCmdFromTile(this->vehicle, tile); @@ -1594,7 +1604,7 @@ public: } } - virtual bool OnVehicleSelect(const Vehicle *v) + bool OnVehicleSelect(const Vehicle *v) override { /* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet. * We disallow copying orders of other vehicles if we already have at least one order entry @@ -1612,7 +1622,7 @@ public: return true; } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->goto_type = OPOS_NONE; this->SetWidgetDirty(WID_O_GOTO); @@ -1624,7 +1634,7 @@ public: } } - virtual void OnMouseDrag(Point pt, int widget) + void OnMouseDrag(Point pt, int widget) override { if (this->selected_order != -1 && widget == WID_O_ORDER_LIST) { /* An order is dragged.. */ @@ -1644,7 +1654,7 @@ public: } } - virtual void OnResize() + void OnResize() override { /* Update the scroll bar */ this->vscroll->SetCapacityFromWidget(this, WID_O_ORDER_LIST); @@ -1852,7 +1862,7 @@ void ShowOrdersWindow(const Vehicle *v) { DeleteWindowById(WC_VEHICLE_DETAILS, v->index, false); DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false); - if (BringWindowToFrontById(WC_VEHICLE_ORDERS, v->index) != NULL) return; + if (BringWindowToFrontById(WC_VEHICLE_ORDERS, v->index) != nullptr) return; /* Using a different WindowDescs for _local_company causes problems. * Due to this we have to close order windows in ChangeWindowOwner/DeleteCompanyWindows, diff --git a/src/order_type.h b/src/order_type.h index b1e0fad539..c150bc273b 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -33,8 +33,8 @@ static const OrderID INVALID_ORDER = 0xFFFFFF; */ static const uint IMPLICIT_ORDER_ONLY_CAP = 32; -/** Order types */ -enum OrderType { +/** Order types. It needs to be 8bits, because we save and load it as such */ +enum OrderType : byte { OT_BEGIN = 0, OT_NOTHING = 0, OT_GOTO_STATION = 1, @@ -44,14 +44,10 @@ enum OrderType { OT_DUMMY = 5, OT_GOTO_WAYPOINT = 6, OT_CONDITIONAL = 7, - OT_IMPLICIT = 8, + OT_IMPLICIT = 8, OT_END }; -/** It needs to be 8bits, because we save and load it as such */ -typedef SimpleTinyEnumT OrderTypeByte; - - /** * Flags related to the unloading order. */ diff --git a/src/os/macosx/crashlog_osx.cpp b/src/os/macosx/crashlog_osx.cpp index 35e47cb061..25389d1ca7 100644 --- a/src/os/macosx/crashlog_osx.cpp +++ b/src/os/macosx/crashlog_osx.cpp @@ -52,7 +52,7 @@ class CrashLogOSX : public CrashLog { char filename_save[MAX_PATH]; ///< Path of crash.sav char filename_screenshot[MAX_PATH]; ///< Path of crash.(png|bmp|pcx) - /* virtual */ char *LogOSVersion(char *buffer, const char *last) const + char *LogOSVersion(char *buffer, const char *last) const override { int ver_maj, ver_min, ver_bug; GetMacOSVersion(&ver_maj, &ver_min, &ver_bug); @@ -66,12 +66,12 @@ class CrashLogOSX : public CrashLog { " Machine: %s\n" " Min Ver: %d\n", ver_maj, ver_min, ver_bug, - arch != NULL ? arch->description : "unknown", + arch != nullptr ? arch->description : "unknown", MAC_OS_X_VERSION_MIN_REQUIRED ); } - /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const + char *LogError(char *buffer, const char *last, const char *message) const override { return buffer + seprintf(buffer, last, "Crash reason:\n" @@ -79,11 +79,11 @@ class CrashLogOSX : public CrashLog { " Message: %s\n\n", strsignal(this->signum), this->signum, - message == NULL ? "" : message + message == nullptr ? "" : message ); } - /* virtual */ char *LogStacktrace(char *buffer, const char *last) const + char *LogStacktrace(char *buffer, const char *last) const override { /* As backtrace() is only implemented in 10.5 or later, * we're rolling our own here. Mostly based on @@ -99,14 +99,14 @@ class CrashLogOSX : public CrashLog { frame = (void **)__builtin_frame_address(0); #endif - for (int i = 0; frame != NULL && i < MAX_STACK_FRAMES; i++) { + for (int i = 0; frame != nullptr && i < MAX_STACK_FRAMES; i++) { /* Get IP for current stack frame. */ #if defined(__ppc__) || defined(__ppc64__) void *ip = frame[2]; #else void *ip = frame[1]; #endif - if (ip == NULL) break; + if (ip == nullptr) break; /* Print running index. */ buffer += seprintf(buffer, last, " [%02d]", i); @@ -118,7 +118,7 @@ class CrashLogOSX : public CrashLog { if (dl_valid && dli.dli_fname) { /* Valid image name? Extract filename from the complete path. */ const char *s = strrchr(dli.dli_fname, '/'); - if (s != NULL) { + if (s != nullptr) { fname = s + 1; } else { fname = dli.dli_fname; @@ -128,13 +128,13 @@ class CrashLogOSX : public CrashLog { buffer += seprintf(buffer, last, " %-20s " PRINTF_PTR, fname, (uintptr_t)ip); /* Print function offset if information is available. */ - if (dl_valid && dli.dli_sname != NULL && dli.dli_saddr != NULL) { + if (dl_valid && dli.dli_sname != nullptr && dli.dli_saddr != nullptr) { /* Try to demangle a possible C++ symbol. */ int status = -1; - char *func_name = abi::__cxa_demangle(dli.dli_sname, NULL, 0, &status); + char *func_name = abi::__cxa_demangle(dli.dli_sname, nullptr, 0, &status); long int offset = (intptr_t)ip - (intptr_t)dli.dli_saddr; - buffer += seprintf(buffer, last, " (%s + %ld)", func_name != NULL ? func_name : dli.dli_sname, offset); + buffer += seprintf(buffer, last, " (%s + %ld)", func_name != nullptr ? func_name : dli.dli_sname, offset); free(func_name); } diff --git a/src/os/macosx/macos.mm b/src/os/macosx/macos.mm index 7fb71fe9ee..ae9d86ee8b 100644 --- a/src/os/macosx/macos.mm +++ b/src/os/macosx/macos.mm @@ -206,23 +206,6 @@ bool GetClipboardContents(char *buffer, const char *last) } #endif -uint GetCPUCoreCount() -{ - uint count = 1; -#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) - if (MacOSVersionIsAtLeast(10, 5, 0)) { - count = (uint)[ [ NSProcessInfo processInfo ] activeProcessorCount ]; - } else -#endif - { -#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) - count = MPProcessorsScheduled(); -#endif - } - - return count; -} - /** * Check if a font is a monospace font. * @param name Name of the font. diff --git a/src/os/macosx/osx_stdafx.h b/src/os/macosx/osx_stdafx.h index 1481d01130..79ba015e51 100644 --- a/src/os/macosx/osx_stdafx.h +++ b/src/os/macosx/osx_stdafx.h @@ -24,7 +24,7 @@ #define HAVE_OSX_1011_SDK #endif -/* It would seem that to ensure backward compability we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */ +/* It would seem that to ensure backward compatibility we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */ #ifndef MAC_OS_X_VERSION_10_3 #define MAC_OS_X_VERSION_10_3 1030 #endif diff --git a/src/os/macosx/splash.cpp b/src/os/macosx/splash.cpp index eadb785101..1ddb165b32 100644 --- a/src/os/macosx/splash.cpp +++ b/src/os/macosx/splash.cpp @@ -54,7 +54,7 @@ static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message) void DisplaySplashImage() { FILE *f = FioFOpenFile(SPLASH_IMAGE_FILE, "r", BASESET_DIR); - if (f == NULL) return; + if (f == nullptr) return; png_byte header[8]; fread(header, sizeof(png_byte), 8, f); @@ -63,23 +63,23 @@ void DisplaySplashImage() return; } - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning); + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) nullptr, png_my_error, png_my_warning); - if (png_ptr == NULL) { + if (png_ptr == nullptr) { fclose(f); return; } png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + if (info_ptr == nullptr) { + png_destroy_read_struct(&png_ptr, (png_infopp)nullptr, (png_infopp)nullptr); fclose(f); return; } png_infop end_info = png_create_info_struct(png_ptr); - if (end_info == NULL) { - png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + if (end_info == nullptr) { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)nullptr); fclose(f); return; } @@ -93,7 +93,7 @@ void DisplaySplashImage() png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); - png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); diff --git a/src/os/macosx/string_osx.cpp b/src/os/macosx/string_osx.cpp index 3fe384b673..6e5916e7c7 100644 --- a/src/os/macosx/string_osx.cpp +++ b/src/os/macosx/string_osx.cpp @@ -22,7 +22,7 @@ #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) /** Cached current locale. */ -static CFLocaleRef _osx_locale = NULL; +static CFLocaleRef _osx_locale = nullptr; /** CoreText cache for font information, cleared when OTTD changes fonts. */ static CTFontRef _font_cache[FS_END]; @@ -53,19 +53,20 @@ public: public: CoreTextVisualRun(CTRunRef run, Font *font, const CoreTextParagraphLayoutFactory::CharType *buff); + CoreTextVisualRun(CoreTextVisualRun &&other) = default; - virtual const GlyphID *GetGlyphs() const { return &this->glyphs[0]; } - virtual const float *GetPositions() const { return &this->positions[0]; } - virtual const int *GetGlyphToCharMap() const { return &this->glyph_to_char[0]; } + const GlyphID *GetGlyphs() const override { return &this->glyphs[0]; } + const float *GetPositions() const override { return &this->positions[0]; } + const int *GetGlyphToCharMap() const override { return &this->glyph_to_char[0]; } - virtual const Font *GetFont() const { return this->font; } - virtual int GetLeading() const { return this->font->fc->GetHeight(); } - virtual int GetGlyphCount() const { return (int)this->glyphs.size(); } + const Font *GetFont() const override { return this->font; } + int GetLeading() const override { return this->font->fc->GetHeight(); } + int GetGlyphCount() const override { return (int)this->glyphs.size(); } int GetAdvance() const { return this->total_advance; } }; /** A single line worth of VisualRuns. */ - class CoreTextLine : public AutoDeleteSmallVector, public ParagraphLayouter::Line { + class CoreTextLine : public std::vector, public ParagraphLayouter::Line { public: CoreTextLine(CTLineRef line, const FontMap &fontMapping, const CoreTextParagraphLayoutFactory::CharType *buff) { @@ -75,20 +76,20 @@ public: /* Extract font information for this run. */ CFRange chars = CTRunGetStringRange(run); - FontMap::const_iterator map = fontMapping.Begin(); - while (map < fontMapping.End() - 1 && map->first <= chars.location) map++; + auto map = fontMapping.begin(); + while (map < fontMapping.end() - 1 && map->first <= chars.location) map++; - *this->Append() = new CoreTextVisualRun(run, map->second, buff); + this->emplace_back(run, map->second, buff); } CFRelease(line); } - virtual int GetLeading() const; - virtual int GetWidth() const; - virtual int CountRuns() const { return this->Length(); } - virtual const VisualRun *GetVisualRun(int run) const { return *this->Get(run); } + int GetLeading() const override; + int GetWidth() const override; + int CountRuns() const override { return this->size(); } + const VisualRun &GetVisualRun(int run) const override { return this->at(run); } - int GetInternalCharLength(WChar c) const + int GetInternalCharLength(WChar c) const override { /* CoreText uses UTF-16 internally which means we need to account for surrogate pairs. */ return c >= 0x010000U ? 2 : 1; @@ -100,17 +101,17 @@ public: this->Reflow(); } - virtual ~CoreTextParagraphLayout() + ~CoreTextParagraphLayout() override { CFRelease(this->typesetter); } - virtual void Reflow() + void Reflow() override { this->cur_offset = 0; } - virtual const Line *NextLine(int max_width); + std::unique_ptr NextLine(int max_width) override; }; @@ -124,21 +125,21 @@ static CGFloat SpriteFontGetWidth(void *ref_con) } static CTRunDelegateCallbacks _sprite_font_callback = { - kCTRunDelegateCurrentVersion, NULL, NULL, NULL, + kCTRunDelegateCurrentVersion, nullptr, nullptr, nullptr, &SpriteFontGetWidth }; /* static */ ParagraphLayouter *CoreTextParagraphLayoutFactory::GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping) { - if (!MacOSVersionIsAtLeast(10, 5, 0)) return NULL; + if (!MacOSVersionIsAtLeast(10, 5, 0)) return nullptr; /* Can't layout an empty string. */ ptrdiff_t length = buff_end - buff; - if (length == 0) return NULL; + if (length == 0) return nullptr; /* Can't layout our in-built sprite fonts. */ - for (FontMap::const_iterator i = fontMapping.Begin(); i != fontMapping.End(); i++) { - if (i->second->fc->IsBuiltInFont()) return NULL; + for (const auto &i : fontMapping) { + if (i.second->fc->IsBuiltInFont()) return nullptr; } /* Make attributed string with embedded font information. */ @@ -152,31 +153,31 @@ static CTRunDelegateCallbacks _sprite_font_callback = { /* Apply font and colour ranges to our string. This is important to make sure * that we get proper glyph boundaries on style changes. */ int last = 0; - for (FontMap::const_iterator i = fontMapping.Begin(); i != fontMapping.End(); i++) { - if (i->first - last == 0) continue; + for (const auto &i : fontMapping) { + if (i.first - last == 0) continue; - if (_font_cache[i->second->fc->GetSize()] == NULL) { + if (_font_cache[i.second->fc->GetSize()] == nullptr) { /* Cache font information. */ - CFStringRef font_name = CFStringCreateWithCString(kCFAllocatorDefault, i->second->fc->GetFontName(), kCFStringEncodingUTF8); - _font_cache[i->second->fc->GetSize()] = CTFontCreateWithName(font_name, i->second->fc->GetFontSize(), NULL); + CFStringRef font_name = CFStringCreateWithCString(kCFAllocatorDefault, i.second->fc->GetFontName(), kCFStringEncodingUTF8); + _font_cache[i.second->fc->GetSize()] = CTFontCreateWithName(font_name, i.second->fc->GetFontSize(), nullptr); CFRelease(font_name); } - CFAttributedStringSetAttribute(str, CFRangeMake(last, i->first - last), kCTFontAttributeName, _font_cache[i->second->fc->GetSize()]); + CFAttributedStringSetAttribute(str, CFRangeMake(last, i.first - last), kCTFontAttributeName, _font_cache[i.second->fc->GetSize()]); - CGColorRef color = CGColorCreateGenericGray((uint8)i->second->colour / 255.0f, 1.0f); // We don't care about the real colours, just that they are different. - CFAttributedStringSetAttribute(str, CFRangeMake(last, i->first - last), kCTForegroundColorAttributeName, color); + CGColorRef color = CGColorCreateGenericGray((uint8)i.second->colour / 255.0f, 1.0f); // We don't care about the real colours, just that they are different. + CFAttributedStringSetAttribute(str, CFRangeMake(last, i.first - last), kCTForegroundColorAttributeName, color); CGColorRelease(color); /* Install a size callback for our special sprite glyphs. */ - for (ssize_t c = last; c < i->first; c++) { + for (ssize_t c = last; c < i.first; c++) { if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END) { - CTRunDelegateRef del = CTRunDelegateCreate(&_sprite_font_callback, (void *)(size_t)(buff[c] | (i->second->fc->GetSize() << 24))); + CTRunDelegateRef del = CTRunDelegateCreate(&_sprite_font_callback, (void *)(size_t)(buff[c] | (i.second->fc->GetSize() << 24))); CFAttributedStringSetAttribute(str, CFRangeMake(c, 1), kCTRunDelegateAttributeName, del); CFRelease(del); } } - last = i->first; + last = i.first; } CFAttributedStringEndEditing(str); @@ -184,12 +185,12 @@ static CTRunDelegateCallbacks _sprite_font_callback = { CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedString(str); CFRelease(str); - return typesetter != NULL ? new CoreTextParagraphLayout(typesetter, buff, length, fontMapping) : NULL; + return typesetter != nullptr ? new CoreTextParagraphLayout(typesetter, buff, length, fontMapping) : nullptr; } -/* virtual */ const CoreTextParagraphLayout::Line *CoreTextParagraphLayout::NextLine(int max_width) +/* virtual */ std::unique_ptr CoreTextParagraphLayout::NextLine(int max_width) { - if (this->cur_offset >= this->length) return NULL; + if (this->cur_offset >= this->length) return nullptr; /* Get line break position, trying word breaking first and breaking somewhere if that doesn't work. */ CFIndex len = CTTypesetterSuggestLineBreak(this->typesetter, this->cur_offset, max_width); @@ -199,7 +200,7 @@ static CTRunDelegateCallbacks _sprite_font_callback = { CTLineRef line = CTTypesetterCreateLine(this->typesetter, CFRangeMake(this->cur_offset, len)); this->cur_offset += len; - return line != NULL ? new CoreTextLine(line, this->font_map, this->text_buffer) : NULL; + return std::unique_ptr(line != nullptr ? new CoreTextLine(line, this->font_map, this->text_buffer) : nullptr); } CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font *font, const CoreTextParagraphLayoutFactory::CharType *buff) : font(font) @@ -232,7 +233,7 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font this->positions[i * 2 + 1] = pts[i].y; } } - this->total_advance = (int)CTRunGetTypographicBounds(run, CFRangeMake(0, 0), NULL, NULL, NULL); + this->total_advance = (int)CTRunGetTypographicBounds(run, CFRangeMake(0, 0), nullptr, nullptr, nullptr); this->positions[this->glyphs.size() * 2] = this->positions[0] + this->total_advance; } @@ -243,8 +244,8 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font int CoreTextParagraphLayout::CoreTextLine::GetLeading() const { int leading = 0; - for (const CoreTextVisualRun * const *run = this->Begin(); run != this->End(); run++) { - leading = max(leading, (*run)->GetLeading()); + for (const auto &run : *this) { + leading = max(leading, run.GetLeading()); } return leading; @@ -256,11 +257,11 @@ int CoreTextParagraphLayout::CoreTextLine::GetLeading() const */ int CoreTextParagraphLayout::CoreTextLine::GetWidth() const { - if (this->Length() == 0) return 0; + if (this->size() == 0) return 0; int total_width = 0; - for (const CoreTextVisualRun * const *run = this->Begin(); run != this->End(); run++) { - total_width += (*run)->GetAdvance(); + for (const auto &run : *this) { + total_width += run.GetAdvance(); } return total_width; @@ -270,9 +271,9 @@ int CoreTextParagraphLayout::CoreTextLine::GetWidth() const /** Delete CoreText font reference for a specific font size. */ void MacOSResetScriptCache(FontSize size) { - if (_font_cache[size] != NULL) { + if (_font_cache[size] != nullptr) { CFRelease(_font_cache[size]); - _font_cache[size] = NULL; + _font_cache[size] = nullptr; } } @@ -281,9 +282,9 @@ void MacOSSetCurrentLocaleName(const char *iso_code) { if (!MacOSVersionIsAtLeast(10, 5, 0)) return; - if (_osx_locale != NULL) CFRelease(_osx_locale); + if (_osx_locale != nullptr) CFRelease(_osx_locale); - CFStringRef iso = CFStringCreateWithCString(kCFAllocatorNull, iso_code, kCFStringEncodingUTF8); + CFStringRef iso = CFStringCreateWithCString(kCFAllocatorDefault, iso_code, kCFStringEncodingUTF8); _osx_locale = CFLocaleCreate(kCFAllocatorDefault, iso); CFRelease(iso); } @@ -431,7 +432,7 @@ int MacOSStringCompare(const char *s1, const char *s2) /* static */ StringIterator *OSXStringIterator::Create() { - if (!MacOSVersionIsAtLeast(10, 5, 0)) return NULL; + if (!MacOSVersionIsAtLeast(10, 5, 0)) return nullptr; return new OSXStringIterator(); } @@ -447,11 +448,11 @@ int MacOSStringCompare(const char *s1, const char *s2) /* static */ StringIterator *OSXStringIterator::Create() { - return NULL; + return nullptr; } /* static */ ParagraphLayouter *CoreTextParagraphLayoutFactory::GetParagraphLayout(CharType *buff, CharType *buff_end, FontMap &fontMapping) { - return NULL; + return nullptr; } #endif /* (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) */ diff --git a/src/os/macosx/string_osx.h b/src/os/macosx/string_osx.h index d632b0a440..8c9b7058ab 100644 --- a/src/os/macosx/string_osx.h +++ b/src/os/macosx/string_osx.h @@ -30,10 +30,10 @@ class OSXStringIterator : public StringIterator { size_t cur_pos; ///< Current iteration position. public: - virtual void SetString(const char *s); - virtual size_t SetCurPosition(size_t pos); - virtual size_t Next(IterType what); - virtual size_t Prev(IterType what); + void SetString(const char *s) override; + size_t SetCurPosition(size_t pos) override; + size_t Next(IterType what) override; + size_t Prev(IterType what) override; static StringIterator *Create(); }; diff --git a/src/os/os2/os2.cpp b/src/os/os2/os2.cpp index 7b34f528a6..9ba6f8ef9e 100644 --- a/src/os/os2/os2.cpp +++ b/src/os/os2/os2.cpp @@ -18,6 +18,7 @@ #include "../../core/random_func.hpp" #include "../../string_func.h" #include "../../textbuf_gui.h" +#include "../../thread.h" #include "table/strings.h" @@ -101,7 +102,7 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) struct diskfree_t free; char drive = path[0] - 'A' + 1; - if (tot != NULL && _getdiskfree(drive, &free) == 0) { + if (tot != nullptr && _getdiskfree(drive, &free) == 0) { *tot = free.avail_clusters * free.sectors_per_cluster * free.bytes_per_sector; return true; } @@ -118,7 +119,7 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) free = (uint64)s.f_frsize * s.f_bavail; } #endif - if (tot != NULL) *tot = free; + if (tot != nullptr) *tot = free; return true; #endif } @@ -172,7 +173,7 @@ void ShowOSErrorBox(const char *buf, bool system) int CDECL main(int argc, char *argv[]) { - SetRandomSeed(time(NULL)); + SetRandomSeed(time(nullptr)); /* Make sure our arguments contain only valid UTF-8 characters. */ for (int i = 0; i < argc; i++) ValidateString(argv[i]); @@ -190,7 +191,7 @@ bool GetClipboardContents(char *buffer, const char *last) { const char *text = (const char*)WinQueryClipbrdData(hab, CF_TEXT); - if (text != NULL) + if (text != nullptr) { strecpy(buffer, text, last); WinCloseClipbrd(hab); @@ -204,25 +205,15 @@ bool GetClipboardContents(char *buffer, const char *last) } -void CSleep(int milliseconds) -{ -#ifndef __INNOTEK_LIBC__ - delay(milliseconds); -#else - usleep(milliseconds * 1000); -#endif -} - const char *FS2OTTD(const char *name) {return name;} const char *OTTD2FS(const char *name) {return name;} -uint GetCPUCoreCount() -{ - return 1; -} - void OSOpenBrowser(const char *url) { // stub only DEBUG(misc, 0, "Failed to open url: %s", url); } + +void SetCurrentThreadName(const char *) +{ +} diff --git a/src/os/unix/crashlog_unix.cpp b/src/os/unix/crashlog_unix.cpp index 47de057f7e..005babebd4 100644 --- a/src/os/unix/crashlog_unix.cpp +++ b/src/os/unix/crashlog_unix.cpp @@ -40,7 +40,7 @@ class CrashLogUnix : public CrashLog { /** Signal that has been thrown. */ int signum; - /* virtual */ char *LogOSVersion(char *buffer, const char *last) const + char *LogOSVersion(char *buffer, const char *last) const override { struct utsname name; if (uname(&name) < 0) { @@ -60,7 +60,7 @@ class CrashLogUnix : public CrashLog { ); } - /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const + char *LogError(char *buffer, const char *last, const char *message) const override { return buffer + seprintf(buffer, last, "Crash reason:\n" @@ -68,7 +68,7 @@ class CrashLogUnix : public CrashLog { " Message: %s\n\n", strsignal(this->signum), this->signum, - message == NULL ? "" : message + message == nullptr ? "" : message ); } @@ -105,7 +105,7 @@ class CrashLogUnix : public CrashLog { } #endif - /* virtual */ char *LogStacktrace(char *buffer, const char *last) const + char *LogStacktrace(char *buffer, const char *last) const override { buffer += seprintf(buffer, last, "Stacktrace:\n"); #if defined(__GLIBC__) diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index bea69ec931..430e3770f1 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -17,6 +17,7 @@ #include "../../debug.h" #include "../../string_func.h" #include "../../fios.h" +#include "../../thread.h" #include @@ -43,39 +44,24 @@ #include #endif - -#ifdef __MORPHOS__ -#include -ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;) - -/* The system supplied definition of SIG_IGN does not match */ -#undef SIG_IGN -#define SIG_IGN (void (*)(int))1 -#endif /* __MORPHOS__ */ - -#ifdef __AMIGA__ -#warning add stack symbol to avoid that user needs to set stack manually (tokai) -// ULONG __stack = +#ifndef NO_THREADS +#include #endif #if defined(__APPLE__) - #if defined(WITH_SDL) +# if defined(WITH_SDL) /* the mac implementation needs this file included in the same file as main() */ - #include - #endif +# include +# endif + +# include "../macosx/macos.h" #endif #include "../../safeguards.h" bool FiosIsRoot(const char *path) { -#if !defined(__MORPHOS__) && !defined(__AMIGAOS__) return path[1] == '\0'; -#else - /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ - const char *s = strchr(path, ':'); - return s != NULL && s[1] == '\0'; -#endif } void FiosGetDrives(FileList &file_list) @@ -98,7 +84,7 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) if (statvfs(path, &s) != 0) return false; free = (uint64)s.f_frsize * s.f_bavail; #endif - if (tot != NULL) *tot = free; + if (tot != nullptr) *tot = free; return true; } @@ -106,15 +92,8 @@ bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb { char filename[MAX_PATH]; int res; -#if defined(__MORPHOS__) || defined(__AMIGAOS__) - /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ - if (FiosIsRoot(path)) { - res = seprintf(filename, lastof(filename), "%s:%s", path, ent->d_name); - } else // XXX - only next line! -#else assert(path[strlen(path) - 1] == PATHSEPCHAR); if (strlen(path) > 2) assert(path[strlen(path) - 2] != PATHSEPCHAR); -#endif res = seprintf(filename, lastof(filename), "%s%s", path, ent->d_name); /* Could we fully concatenate the path and filename? */ @@ -151,9 +130,9 @@ static const char *GetLocalCode() #else /* Strip locale (eg en_US.UTF-8) to only have UTF-8 */ const char *locale = GetCurrentLocale("LC_CTYPE"); - if (locale != NULL) locale = strchr(locale, '.'); + if (locale != nullptr) locale = strchr(locale, '.'); - return (locale == NULL) ? "" : locale + 1; + return (locale == nullptr) ? "" : locale + 1; #endif } @@ -179,7 +158,7 @@ static const char *convert_tofrom_fs(iconv_t convd, const char *name) strecpy(outbuf, name, outbuf + outlen); - iconv(convd, NULL, NULL, NULL, NULL); + iconv(convd, nullptr, nullptr, nullptr, nullptr); if (iconv(convd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)(-1)) { DEBUG(misc, 0, "[iconv] error converting '%s'. Errno %d", name, errno); } @@ -267,13 +246,13 @@ int CDECL main(int argc, char *argv[]) cocoaSetupAutoreleasePool(); /* This is passed if we are launched by double-clicking */ if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) { - argv[1] = NULL; + argv[1] = nullptr; argc = 1; } #endif CrashLog::InitialiseCrashLog(); - SetRandomSeed(time(NULL)); + SetRandomSeed(time(nullptr)); signal(SIGPIPE, SIG_IGN); @@ -294,74 +273,7 @@ bool GetClipboardContents(char *buffer, const char *last) #endif -/* multi os compatible sleep function */ - -#ifdef __AMIGA__ -/* usleep() implementation */ -# include -# include - - extern struct Device *TimerBase = NULL; - extern struct MsgPort *TimerPort = NULL; - extern struct timerequest *TimerRequest = NULL; -#endif /* __AMIGA__ */ - -void CSleep(int milliseconds) -{ - #if defined(__BEOS__) - snooze(milliseconds * 1000); - #elif defined(__AMIGA__) - { - ULONG signals; - ULONG TimerSigBit = 1 << TimerPort->mp_SigBit; - - /* send IORequest */ - TimerRequest->tr_node.io_Command = TR_ADDREQUEST; - TimerRequest->tr_time.tv_secs = (milliseconds * 1000) / 1000000; - TimerRequest->tr_time.tv_micro = (milliseconds * 1000) % 1000000; - SendIO((struct IORequest *)TimerRequest); - - if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) { - AbortIO((struct IORequest *)TimerRequest); - } - WaitIO((struct IORequest *)TimerRequest); - } - #else - usleep(milliseconds * 1000); - #endif -} - - #ifndef __APPLE__ -uint GetCPUCoreCount() -{ - uint count = 1; -#ifdef HAS_SYSCTL - int ncpu = 0; - size_t len = sizeof(ncpu); - -#ifdef OPENBSD - int name[2]; - name[0] = CTL_HW; - name[1] = HW_NCPU; - if (sysctl(name, 2, &ncpu, &len, NULL, 0) < 0) { - ncpu = 0; - } -#else - if (sysctlbyname("hw.availcpu", &ncpu, &len, NULL, 0) < 0) { - sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0); - } -#endif /* #ifdef OPENBSD */ - - if (ncpu > 0) count = ncpu; -#elif defined(_SC_NPROCESSORS_ONLN) - long res = sysconf(_SC_NPROCESSORS_ONLN); - if (res > 0) count = res; -#endif - - return count; -} - void OSOpenBrowser(const char *url) { pid_t child_pid = fork(); @@ -370,9 +282,20 @@ void OSOpenBrowser(const char *url) const char *args[3]; args[0] = "xdg-open"; args[1] = url; - args[2] = NULL; + args[2] = nullptr; execvp(args[0], const_cast(args)); DEBUG(misc, 0, "Failed to open url: %s", url); exit(0); } -#endif +#endif /* __APPLE__ */ + +void SetCurrentThreadName(const char *threadName) { +#if !defined(NO_THREADS) && defined(__GLIBC__) +#if __GLIBC_PREREQ(2, 12) + if (threadName) pthread_setname_np(pthread_self(), threadName); +#endif /* __GLIBC_PREREQ(2, 12) */ +#endif /* !defined(NO_THREADS) && defined(__GLIBC__) */ +#if defined(__APPLE__) + MacOSSetThreadName(threadName); +#endif /* defined(__APPLE__) */ +} diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index ded4020d99..a64228bfb4 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -26,9 +26,6 @@ #include "../../safeguards.h" -static const uint MAX_SYMBOL_LEN = 512; -static const uint MAX_FRAMES = 64; - /* printf format specification for 32/64-bit addresses. */ #ifdef _M_AMD64 #define PRINTF_PTR "0x%016IX" @@ -43,14 +40,14 @@ class CrashLogWindows : public CrashLog { /** Information about the encountered exception */ EXCEPTION_POINTERS *ep; - /* virtual */ char *LogOSVersion(char *buffer, const char *last) const; - /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const; - /* virtual */ char *LogStacktrace(char *buffer, const char *last) const; - /* virtual */ char *LogRegisters(char *buffer, const char *last) const; - /* virtual */ char *LogModules(char *buffer, const char *last) const; + char *LogOSVersion(char *buffer, const char *last) const override; + char *LogError(char *buffer, const char *last, const char *message) const override; + char *LogStacktrace(char *buffer, const char *last) const override; + char *LogRegisters(char *buffer, const char *last) const override; + char *LogModules(char *buffer, const char *last) const override; public: #if defined(_MSC_VER) - /* virtual */ int WriteCrashDump(char *filename, const char *filename_last) const; + int WriteCrashDump(char *filename, const char *filename_last) const override; char *AppendDecodedStacktrace(char *buffer, const char *last) const; #else char *AppendDecodedStacktrace(char *buffer, const char *last) const { return buffer; } @@ -69,7 +66,7 @@ public: * A crash log is always generated when it's generated. * @param ep the data related to the exception. */ - CrashLogWindows(EXCEPTION_POINTERS *ep = NULL) : + CrashLogWindows(EXCEPTION_POINTERS *ep = nullptr) : ep(ep) { this->crashlog[0] = '\0'; @@ -84,7 +81,7 @@ public: static CrashLogWindows *current; }; -/* static */ CrashLogWindows *CrashLogWindows::current = NULL; +/* static */ CrashLogWindows *CrashLogWindows::current = nullptr; /* virtual */ char *CrashLogWindows::LogOSVersion(char *buffer, const char *last) const { @@ -117,7 +114,7 @@ public: " Message: %s\n\n", (int)ep->ExceptionRecord->ExceptionCode, (size_t)ep->ExceptionRecord->ExceptionAddress, - message == NULL ? "" : message + message == nullptr ? "" : message ); } @@ -159,7 +156,7 @@ static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename) HANDLE file; memset(dfi, 0, sizeof(*dfi)); - file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); + file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, 0); if (file != INVALID_HANDLE_VALUE) { byte buffer[1024]; DWORD numread; @@ -168,7 +165,7 @@ static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename) uint32 crc = (uint32)-1; for (;;) { - if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 || numread == 0) { + if (ReadFile(file, buffer, sizeof(buffer), &numread, nullptr) == 0 || numread == 0) { break; } filesize += numread; @@ -177,7 +174,7 @@ static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename) dfi->size = filesize; dfi->crc32 = crc ^ (uint32)-1; - if (GetFileTime(file, NULL, NULL, &write_time)) { + if (GetFileTime(file, nullptr, nullptr, &write_time)) { FileTimeToSystemTime(&write_time, &dfi->file_time); } CloseHandle(file); @@ -220,7 +217,7 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) BOOL res; HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); - if (proc != NULL) { + if (proc != nullptr) { res = EnumProcessModules(proc, modules, sizeof(modules), &needed); CloseHandle(proc); if (res) { @@ -231,7 +228,7 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) } } } - output = PrintModuleInfo(output, last, NULL); + output = PrintModuleInfo(output, last, nullptr); return output + seprintf(output, last, "\n"); } @@ -322,6 +319,9 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) } #if defined(_MSC_VER) +static const uint MAX_SYMBOL_LEN = 512; +static const uint MAX_FRAMES = 64; + #pragma warning(disable:4091) #include #pragma warning(default:4091) @@ -362,7 +362,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c if (LoadLibraryList((Function*)&proc, dbg_import)) { /* Initialize symbol handler. */ HANDLE hCur = GetCurrentProcess(); - proc.pSymInitialize(hCur, NULL, TRUE); + proc.pSymInitialize(hCur, nullptr, TRUE); /* Load symbols only when needed, fail silently on errors, demangle symbol names. */ proc.pSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_UNDNAME); @@ -399,7 +399,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c #else IMAGE_FILE_MACHINE_I386, #endif - hCur, GetCurrentThread(), &frame, &ctx, NULL, proc.pSymFunctionTableAccess64, proc.pSymGetModuleBase64, NULL)) break; + hCur, GetCurrentThread(), &frame, &ctx, nullptr, proc.pSymFunctionTableAccess64, proc.pSymGetModuleBase64, nullptr)) break; if (frame.AddrPC.Offset == frame.AddrReturn.Offset) { buffer += seprintf(buffer, last, " \n"); @@ -443,16 +443,16 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c { int ret = 0; HMODULE dbghelp = LoadLibrary(_T("dbghelp.dll")); - if (dbghelp != NULL) { + if (dbghelp != nullptr) { typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, CONST PMINIDUMP_EXCEPTION_INFORMATION, CONST PMINIDUMP_USER_STREAM_INFORMATION, CONST PMINIDUMP_CALLBACK_INFORMATION); MiniDumpWriteDump_t funcMiniDumpWriteDump = (MiniDumpWriteDump_t)GetProcAddress(dbghelp, "MiniDumpWriteDump"); - if (funcMiniDumpWriteDump != NULL) { + if (funcMiniDumpWriteDump != nullptr) { seprintf(filename, filename_last, "%scrash.dmp", _personal_dir); - HANDLE file = CreateFile(OTTD2FS(filename), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + HANDLE file = CreateFile(OTTD2FS(filename), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); HANDLE proc = GetCurrentProcess(); DWORD procid = GetCurrentProcessId(); MINIDUMP_EXCEPTION_INFORMATION mdei; @@ -470,7 +470,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c mdei.ExceptionPointers = ep; mdei.ClientPointers = false; - funcMiniDumpWriteDump(proc, procid, file, MiniDumpWithDataSegs, &mdei, &musi, NULL); + funcMiniDumpWriteDump(proc, procid, file, MiniDumpWithDataSegs, &mdei, &musi, nullptr); ret = 1; } else { ret = -1; @@ -488,11 +488,11 @@ static void ShowCrashlogWindow(); * Stack pointer for use when 'starting' the crash handler. * Not static as gcc's inline assembly needs it that way. */ -void *_safe_esp = NULL; +void *_safe_esp = nullptr; static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) { - if (CrashLogWindows::current != NULL) { + if (CrashLogWindows::current != nullptr) { CrashLog::AfterCrashLogCleanup(); ExitProcess(2); } @@ -501,7 +501,7 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) static const TCHAR _emergency_crash[] = _T("A serious fault condition occurred in the game. The game will shut down.\n") _T("As you loaded an emergency savegame no crash information will be generated.\n"); - MessageBox(NULL, _emergency_crash, _T("Fatal Application Failure"), MB_ICONERROR); + MessageBox(nullptr, _emergency_crash, _T("Fatal Application Failure"), MB_ICONERROR); ExitProcess(3); } @@ -510,7 +510,7 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) _T("A serious fault condition occurred in the game. The game will shut down.\n") _T("As you loaded an savegame for which you do not have the required NewGRFs\n") _T("no crash information will be generated.\n"); - MessageBox(NULL, _saveload_crash, _T("Fatal Application Failure"), MB_ICONERROR); + MessageBox(nullptr, _saveload_crash, _T("Fatal Application Failure"), MB_ICONERROR); ExitProcess(3); } @@ -525,7 +525,7 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) /* Close any possible log files */ CloseConsoleLogIfActive(); - if ((VideoDriver::GetInstance() == NULL || VideoDriver::GetInstance()->HasGUI()) && _safe_esp != NULL) { + if ((VideoDriver::GetInstance() == nullptr || VideoDriver::GetInstance()->HasGUI()) && _safe_esp != nullptr) { #ifdef _M_AMD64 ep->ContextRecord->Rip = (DWORD64)ShowCrashlogWindow; ep->ContextRecord->Rsp = (DWORD64)_safe_esp; @@ -542,7 +542,7 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) static void CDECL CustomAbort(int signal) { - RaiseException(0xE1212012, 0, 0, NULL); + RaiseException(0xE1212012, 0, 0, nullptr); } /* static */ void CrashLog::InitialiseCrashLog() @@ -693,5 +693,5 @@ static void ShowCrashlogWindow() { ShowCursor(TRUE); ShowWindow(GetActiveWindow(), FALSE); - DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(100), NULL, CrashDialogFunc); + DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(100), nullptr, CrashDialogFunc); } diff --git a/src/os/windows/ottdres.rc.in b/src/os/windows/ottdres.rc.in index b7208bc729..88cf64f666 100644 --- a/src/os/windows/ottdres.rc.in +++ b/src/os/windows/ottdres.rc.in @@ -79,8 +79,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,9,3,!!ISODATE!! - PRODUCTVERSION 1,9,3,!!ISODATE!! + FILEVERSION 1,10,0,!!ISODATE!! + PRODUCTVERSION 1,10,0,!!ISODATE!! FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L diff --git a/src/os/windows/string_uniscribe.cpp b/src/os/windows/string_uniscribe.cpp index ce61537b2b..c91803089e 100644 --- a/src/os/windows/string_uniscribe.cpp +++ b/src/os/windows/string_uniscribe.cpp @@ -86,34 +86,35 @@ public: int num_glyphs; Font *font; - mutable int *glyph_to_char = NULL; + mutable int *glyph_to_char = nullptr; public: UniscribeVisualRun(const UniscribeRun &range, int x); - virtual ~UniscribeVisualRun() + UniscribeVisualRun(UniscribeVisualRun &&other) noexcept; + ~UniscribeVisualRun() override { free(this->glyph_to_char); } - virtual const GlyphID *GetGlyphs() const { return &this->glyphs[0]; } - virtual const float *GetPositions() const { return &this->positions[0]; } - virtual const int *GetGlyphToCharMap() const; + const GlyphID *GetGlyphs() const override { return &this->glyphs[0]; } + const float *GetPositions() const override { return &this->positions[0]; } + const int *GetGlyphToCharMap() const override; - virtual const Font *GetFont() const { return this->font; } - virtual int GetLeading() const { return this->font->fc->GetHeight(); } - virtual int GetGlyphCount() const { return this->num_glyphs; } + const Font *GetFont() const override { return this->font; } + int GetLeading() const override { return this->font->fc->GetHeight(); } + int GetGlyphCount() const override { return this->num_glyphs; } int GetAdvance() const { return this->total_advance; } }; /** A single line worth of VisualRuns. */ - class UniscribeLine : public AutoDeleteSmallVector, public ParagraphLayouter::Line { + class UniscribeLine : public std::vector, public ParagraphLayouter::Line { public: - virtual int GetLeading() const; - virtual int GetWidth() const; - virtual int CountRuns() const { return this->Length(); } - virtual const VisualRun *GetVisualRun(int run) const { return *this->Get(run); } + int GetLeading() const override; + int GetWidth() const override; + int CountRuns() const override { return (uint)this->size(); } + const VisualRun &GetVisualRun(int run) const override { return this->at(run); } - int GetInternalCharLength(WChar c) const + int GetInternalCharLength(WChar c) const override { /* Uniscribe uses UTF-16 internally which means we need to account for surrogate pairs. */ return c >= 0x010000U ? 2 : 1; @@ -125,28 +126,30 @@ public: this->Reflow(); } - virtual ~UniscribeParagraphLayout() {} + ~UniscribeParagraphLayout() override {} - virtual void Reflow() + void Reflow() override { this->cur_range = this->ranges.begin(); this->cur_range_offset = 0; } - virtual const Line *NextLine(int max_width); + std::unique_ptr NextLine(int max_width) override; }; void UniscribeResetScriptCache(FontSize size) { - if (_script_cache[size] != NULL) { + if (_script_cache[size] != nullptr) { ScriptFreeCache(&_script_cache[size]); - _script_cache[size] = NULL; + _script_cache[size] = nullptr; } } /** Load the matching native Windows font. */ static HFONT HFontFromFont(Font *font) { + if (font->fc->GetOSHandle() != nullptr) return CreateFontIndirect((PLOGFONT)font->fc->GetOSHandle()); + LOGFONT logfont; ZeroMemory(&logfont, sizeof(LOGFONT)); logfont.lfHeight = font->fc->GetHeight(); @@ -167,9 +170,9 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b /* The char-to-glyph array is the same size as the input. */ range.char_to_glyph.resize(range.len); - HDC temp_dc = NULL; - HFONT old_font = NULL; - HFONT cur_font = NULL; + HDC temp_dc = nullptr; + HFONT old_font = nullptr; + HFONT cur_font = nullptr; while (true) { /* Shape the text run by determining the glyphs needed for display. */ @@ -194,15 +197,19 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b } for (int i = 0; i < range.len; i++) { if (buff[range.pos + i] >= SCC_SPRITE_START && buff[range.pos + i] <= SCC_SPRITE_END) { - range.ft_glyphs[range.char_to_glyph[i]] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); - range.offsets[range.char_to_glyph[i]].dv = range.font->fc->GetAscender() - range.font->fc->GetGlyph(range.ft_glyphs[range.char_to_glyph[i]])->height - 1; // Align sprite glyphs to font baseline. + auto pos = range.char_to_glyph[i]; + range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); + range.offsets[pos].dv = range.font->fc->GetAscender() - range.font->fc->GetGlyph(range.ft_glyphs[pos])->height - 1; // Align sprite glyphs to font baseline. + range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]); } } - /* FreeType and GDI/Uniscribe seems to occasionally disagree over the width of a glyph. */ range.total_advance = 0; for (size_t i = 0; i < range.advances.size(); i++) { +#ifdef WITH_FREETYPE + /* FreeType and GDI/Uniscribe seems to occasionally disagree over the width of a glyph. */ if (range.advances[i] > 0 && range.ft_glyphs[i] != 0xFFFF) range.advances[i] = range.font->fc->GetGlyphWidth(range.ft_glyphs[i]); +#endif range.total_advance += range.advances[i]; } break; @@ -216,9 +223,9 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b } else if (hr == E_PENDING) { /* Glyph data is not in cache, load native font. */ cur_font = HFontFromFont(range.font); - if (cur_font == NULL) return false; // Sorry, no dice. + if (cur_font == nullptr) return false; // Sorry, no dice. - temp_dc = CreateCompatibleDC(NULL); + temp_dc = CreateCompatibleDC(nullptr); SetMapMode(temp_dc, MM_TEXT); old_font = (HFONT)SelectObject(temp_dc, cur_font); } else if (hr == USP_E_SCRIPT_NOT_IN_FONT && range.sa.eScript != SCRIPT_UNDEFINED) { @@ -226,19 +233,19 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b range.sa.eScript = SCRIPT_UNDEFINED; } else { /* Some unknown other error. */ - if (temp_dc != NULL) { + if (temp_dc != nullptr) { SelectObject(temp_dc, old_font); DeleteObject(cur_font); - ReleaseDC(NULL, temp_dc); + ReleaseDC(nullptr, temp_dc); } return false; } } - if (temp_dc != NULL) { + if (temp_dc != nullptr) { SelectObject(temp_dc, old_font); DeleteObject(cur_font); - ReleaseDC(NULL, temp_dc); + ReleaseDC(nullptr, temp_dc); } return true; @@ -279,16 +286,16 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF { int32 length = buff_end - buff; /* Can't layout an empty string. */ - if (length == 0) return NULL; + if (length == 0) return nullptr; /* Can't layout our in-built sprite fonts. */ - for (FontMap::const_iterator i = fontMapping.Begin(); i != fontMapping.End(); i++) { - if (i->second->fc->IsBuiltInFont()) return NULL; + for (auto const &pair : fontMapping) { + if (pair.second->fc->IsBuiltInFont()) return nullptr; } /* Itemize text. */ std::vector items = UniscribeItemizeString(buff, length); - if (items.size() == 0) return NULL; + if (items.size() == 0) return nullptr; /* Build ranges from the items and the font map. A range is a run of text * that is part of a single item and formatted using a single font style. */ @@ -296,16 +303,16 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF int cur_pos = 0; std::vector::iterator cur_item = items.begin(); - for (FontMap::const_iterator i = fontMapping.Begin(); i != fontMapping.End(); i++) { - while (cur_pos < i->first && cur_item != items.end() - 1) { + for (auto const &i : fontMapping) { + while (cur_pos < i.first && cur_item != items.end() - 1) { /* Add a range that spans the intersection of the remaining item and font run. */ - int stop_pos = min(i->first, (cur_item + 1)->iCharPos); + int stop_pos = min(i.first, (cur_item + 1)->iCharPos); assert(stop_pos - cur_pos > 0); - ranges.push_back(UniscribeRun(cur_pos, stop_pos - cur_pos, i->second, cur_item->a)); + ranges.push_back(UniscribeRun(cur_pos, stop_pos - cur_pos, i.second, cur_item->a)); /* Shape the range. */ if (!UniscribeShapeRun(buff, ranges.back())) { - return NULL; + return nullptr; } /* If we are at the end of the current item, advance to the next item. */ @@ -317,12 +324,12 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF return new UniscribeParagraphLayout(ranges, buff); } -/* virtual */ const ParagraphLayouter::Line *UniscribeParagraphLayout::NextLine(int max_width) +/* virtual */ std::unique_ptr UniscribeParagraphLayout::NextLine(int max_width) { std::vector::iterator start_run = this->cur_range; std::vector::iterator last_run = this->cur_range; - if (start_run == this->ranges.end()) return NULL; + if (start_run == this->ranges.end()) return nullptr; /* Add remaining width of the first run if it is a broken run. */ int cur_width = 0; @@ -354,7 +361,7 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF int last_cluster = this->cur_range_offset + 1; for (std::vector::iterator r = start_run; r != last_run; r++) { log_attribs.resize(r->pos - start_run->pos + r->len); - if (FAILED(ScriptBreak(this->text_buffer + r->pos + start_offs, r->len - start_offs, &r->sa, &log_attribs[r->pos - start_run->pos + start_offs]))) return NULL; + if (FAILED(ScriptBreak(this->text_buffer + r->pos + start_offs, r->len - start_offs, &r->sa, &log_attribs[r->pos - start_run->pos + start_offs]))) return nullptr; std::vector dx(r->len); ScriptGetLogicalWidths(&r->sa, r->len, (int)r->glyphs.size(), &r->advances[0], &r->char_to_glyph[0], &r->vis_attribs[0], &dx[0]); @@ -400,10 +407,10 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF bidi_level.push_back(r->sa.s.uBidiLevel); } std::vector vis_to_log(bidi_level.size()); - if (FAILED(ScriptLayout((int)bidi_level.size(), &bidi_level[0], &vis_to_log[0], NULL))) return NULL; + if (FAILED(ScriptLayout((int)bidi_level.size(), &bidi_level[0], &vis_to_log[0], nullptr))) return nullptr; /* Create line. */ - UniscribeLine *line = new UniscribeLine(); + std::unique_ptr line(new UniscribeLine()); int cur_pos = 0; for (std::vector::iterator l = vis_to_log.begin(); l != vis_to_log.end(); l++) { @@ -414,17 +421,17 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF if (i_run == last_run - 1 && remaing_offset < (last_run - 1)->len) { run.len = remaing_offset - 1; - if (!UniscribeShapeRun(this->text_buffer, run)) return NULL; + if (!UniscribeShapeRun(this->text_buffer, run)) return nullptr; } if (i_run == start_run && this->cur_range_offset > 0) { assert(run.len - this->cur_range_offset > 0); run.pos += this->cur_range_offset; run.len -= this->cur_range_offset; - if (!UniscribeShapeRun(this->text_buffer, run)) return NULL; + if (!UniscribeShapeRun(this->text_buffer, run)) return nullptr; } - *line->Append() = new UniscribeVisualRun(run, cur_pos); + line->emplace_back(run, cur_pos); cur_pos += run.total_advance; } @@ -448,8 +455,8 @@ static std::vector UniscribeItemizeString(UniscribeParagraphLayoutF int UniscribeParagraphLayout::UniscribeLine::GetLeading() const { int leading = 0; - for (const UniscribeVisualRun * const *run = this->Begin(); run != this->End(); run++) { - leading = max(leading, (*run)->GetLeading()); + for (const auto &run : *this) { + leading = max(leading, run.GetLeading()); } return leading; @@ -462,8 +469,8 @@ int UniscribeParagraphLayout::UniscribeLine::GetLeading() const int UniscribeParagraphLayout::UniscribeLine::GetWidth() const { int length = 0; - for (const UniscribeVisualRun * const *run = this->Begin(); run != this->End(); run++) { - length += (*run)->GetAdvance(); + for (const auto &run : *this) { + length += run.GetAdvance(); } return length; @@ -484,9 +491,17 @@ UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(const Uniscribe this->positions[this->num_glyphs * 2] = advance + x; } +UniscribeParagraphLayout::UniscribeVisualRun::UniscribeVisualRun(UniscribeVisualRun&& other) noexcept + : glyphs(std::move(other.glyphs)), positions(std::move(other.positions)), char_to_glyph(std::move(other.char_to_glyph)), + start_pos(other.start_pos), total_advance(other.total_advance), num_glyphs(other.num_glyphs), font(other.font) +{ + this->glyph_to_char = other.glyph_to_char; + other.glyph_to_char = nullptr; +} + const int *UniscribeParagraphLayout::UniscribeVisualRun::GetGlyphToCharMap() const { - if (this->glyph_to_char == NULL) { + if (this->glyph_to_char == nullptr) { this->glyph_to_char = CallocT(this->GetGlyphCount()); /* The char to glyph array contains the first glyph index of the cluster that is associated diff --git a/src/os/windows/string_uniscribe.h b/src/os/windows/string_uniscribe.h index 6af858a88f..49e1123a99 100644 --- a/src/os/windows/string_uniscribe.h +++ b/src/os/windows/string_uniscribe.h @@ -81,10 +81,10 @@ class UniscribeStringIterator : public StringIterator { size_t cur_pos; ///< Current iteration position. public: - virtual void SetString(const char *s); - virtual size_t SetCurPosition(size_t pos); - virtual size_t Next(IterType what); - virtual size_t Prev(IterType what); + void SetString(const char *s) override; + size_t SetCurPosition(size_t pos) override; + size_t Next(IterType what) override; + size_t Prev(IterType what) override; }; #endif /* defined(WITH_UNISCRIBE) */ diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index e0a29b67ee..b0495d64db 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -30,6 +30,7 @@ #include #include #include "../../language.h" +#include "../../thread.h" #include "../../safeguards.h" @@ -60,14 +61,14 @@ bool LoadLibraryList(Function proc[], const char *dll) HMODULE lib; lib = LoadLibrary(MB_TO_WIDE(dll)); - if (lib == NULL) return false; + if (lib == nullptr) return false; for (;;) { FARPROC p; while (*dll++ != '\0') { /* Nothing */ } if (*dll == '\0') break; p = GetProcAddress(lib, dll); - if (p == NULL) return false; + if (p == nullptr) return false; *proc++ = (Function)p; } dll++; @@ -83,7 +84,7 @@ void ShowOSErrorBox(const char *buf, bool system) void OSOpenBrowser(const char *url) { - ShellExecute(GetActiveWindow(), _T("open"), OTTD2FS(url), NULL, NULL, SW_SHOWNORMAL); + ShellExecute(GetActiveWindow(), _T("open"), OTTD2FS(url), nullptr, nullptr, SW_SHOWNORMAL); } /* Code below for windows version of opendir/readdir/closedir copied and @@ -141,7 +142,7 @@ DIR *opendir(const TCHAR *path) if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { d = dir_calloc(); - if (d != NULL) { + if (d != nullptr) { TCHAR search_path[MAX_PATH]; bool slash = path[_tcslen(path) - 1] == '\\'; @@ -157,14 +158,14 @@ DIR *opendir(const TCHAR *path) d->at_first_entry = true; } else { dir_free(d); - d = NULL; + d = nullptr; } } else { errno = ENOMEM; } } else { /* path not found or not a directory */ - d = NULL; + d = nullptr; errno = ENOENT; } @@ -178,11 +179,11 @@ struct dirent *readdir(DIR *d) if (d->at_first_entry) { /* the directory was empty when opened */ - if (d->hFind == INVALID_HANDLE_VALUE) return NULL; + if (d->hFind == INVALID_HANDLE_VALUE) return nullptr; d->at_first_entry = false; } else if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err); - return NULL; + return nullptr; } /* This entry has passed all checks; return information about it. @@ -250,7 +251,7 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) DWORD spc, bps, nfc, tnc; _sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]); - if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) { + if (tot != nullptr && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) { *tot = ((spc * bps) * (uint64)nfc); retval = true; } @@ -338,9 +339,9 @@ void CreateConsole() *stderr = *fdopen(2, "w" ); #endif - setvbuf(stdin, NULL, _IONBF, 0); - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stderr, NULL, _IONBF, 0); + setvbuf(stdin, nullptr, _IONBF, 0); + setvbuf(stdout, nullptr, _IONBF, 0); + setvbuf(stderr, nullptr, _IONBF, 0); } /** Temporary pointer to get the help message to the window */ @@ -397,7 +398,7 @@ void ShowInfo(const char *str) * ShowInfo are much shorter, or so long they need this way of displaying * them anyway. */ _help_msg = str; - DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, HelpDialogFunc); + DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(101), nullptr, HelpDialogFunc); } else { /* We need to put the text in a separate buffer because the default * buffer in OTTD2FS might not be large enough (512 chars). */ @@ -458,28 +459,28 @@ void DetermineBasePaths(const char *exe) char tmp[MAX_PATH]; TCHAR path[MAX_PATH]; #ifdef WITH_PERSONAL_DIR - if (SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))) { + if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, path))) { strecpy(tmp, FS2OTTD(path), lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); strecat(tmp, PERSONAL_DIR, lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); } else { - _searchpaths[SP_PERSONAL_DIR] = NULL; + _searchpaths[SP_PERSONAL_DIR] = nullptr; } - if (SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))) { + if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_COMMON_DOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) { strecpy(tmp, FS2OTTD(path), lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); strecat(tmp, PERSONAL_DIR, lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_SHARED_DIR] = stredup(tmp); } else { - _searchpaths[SP_SHARED_DIR] = NULL; + _searchpaths[SP_SHARED_DIR] = nullptr; } #else - _searchpaths[SP_PERSONAL_DIR] = NULL; - _searchpaths[SP_SHARED_DIR] = NULL; + _searchpaths[SP_PERSONAL_DIR] = nullptr; + _searchpaths[SP_SHARED_DIR] = nullptr; #endif /* Get the path to working directory of OpenTTD */ @@ -487,15 +488,15 @@ void DetermineBasePaths(const char *exe) AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_WORKING_DIR] = stredup(tmp); - if (!GetModuleFileName(NULL, path, lengthof(path))) { + if (!GetModuleFileName(nullptr, path, lengthof(path))) { DEBUG(misc, 0, "GetModuleFileName failed (%lu)\n", GetLastError()); - _searchpaths[SP_BINARY_DIR] = NULL; + _searchpaths[SP_BINARY_DIR] = nullptr; } else { TCHAR exec_dir[MAX_PATH]; _tcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path)); - if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, NULL)) { + if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, nullptr)) { DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); - _searchpaths[SP_BINARY_DIR] = NULL; + _searchpaths[SP_BINARY_DIR] = nullptr; } else { strecpy(tmp, convert_from_fs(exec_dir, tmp, lengthof(tmp)), lastof(tmp)); char *s = strrchr(tmp, PATHSEPCHAR); @@ -504,8 +505,8 @@ void DetermineBasePaths(const char *exe) } } - _searchpaths[SP_INSTALLATION_DIR] = NULL; - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL; + _searchpaths[SP_INSTALLATION_DIR] = nullptr; + _searchpaths[SP_APPLICATION_BUNDLE_DIR] = nullptr; } @@ -515,18 +516,18 @@ bool GetClipboardContents(char *buffer, const char *last) const char *ptr; if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { - OpenClipboard(NULL); + OpenClipboard(nullptr); cbuf = GetClipboardData(CF_UNICODETEXT); ptr = (const char*)GlobalLock(cbuf); - int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1, NULL, NULL); + int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1, nullptr, nullptr); GlobalUnlock(cbuf); CloseClipboard(); if (out_len == 0) return false; #if !defined(UNICODE) } else if (IsClipboardFormatAvailable(CF_TEXT)) { - OpenClipboard(NULL); + OpenClipboard(nullptr); cbuf = GetClipboardData(CF_TEXT); ptr = (const char*)GlobalLock(cbuf); @@ -543,12 +544,6 @@ bool GetClipboardContents(char *buffer, const char *last) } -void CSleep(int milliseconds) -{ - Sleep(milliseconds); -} - - /** * Convert to OpenTTD's encoding from that of the local environment. * When the project is built in UNICODE, the system codepage is irrelevant and @@ -601,7 +596,7 @@ char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen) const WCHAR *wide_buf = name; #else /* Convert string from the local codepage to UTF-16. */ - int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); + int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, nullptr, 0); if (wide_len == 0) { utf8_buf[0] = '\0'; return utf8_buf; @@ -612,7 +607,7 @@ char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen) #endif /* Convert UTF-16 string to UTF-8. */ - int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, NULL, NULL); + int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, nullptr, nullptr); if (len == 0) utf8_buf[0] = '\0'; return utf8_buf; @@ -635,7 +630,7 @@ TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool co int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (int)buflen); if (len == 0) system_buf[0] = '\0'; #else - int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); + int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0); if (len == 0) { system_buf[0] = '\0'; return system_buf; @@ -644,7 +639,7 @@ TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool co WCHAR *wide_buf = AllocaM(WCHAR, len); MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len); - len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (int)buflen, NULL, NULL); + len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (int)buflen, nullptr, nullptr); if (len == 0) system_buf[0] = '\0'; #endif @@ -659,7 +654,7 @@ TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool co */ HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath) { - static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL; + static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = nullptr; static bool first_time = true; /* We only try to load the library one time; if it fails, it fails */ @@ -679,7 +674,7 @@ HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, first_time = false; } - if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath); + if (SHGetFolderPath != nullptr) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath); /* SHGetFolderPath doesn't exist, try a more conservative approach, * eg environment variables. This is only included for legacy modes @@ -703,7 +698,7 @@ HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, HKEY key; if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS) break; DWORD len = MAX_PATH; - ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T("Personal") : _T("Common Documents"), NULL, NULL, (LPBYTE)pszPath, &len); + ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T("Personal") : _T("Common Documents"), nullptr, nullptr, (LPBYTE)pszPath, &len); RegCloseKey(key); if (ret == ERROR_SUCCESS) return (HRESULT)0; break; @@ -723,21 +718,13 @@ const char *GetCurrentLocale(const char *) if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 || GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) { /* Unable to retrieve the locale. */ - return NULL; + return nullptr; } /* Format it as 'en_us'. */ static char retbuf[6] = {lang[0], lang[1], '_', country[0], country[1], 0}; return retbuf; } -uint GetCPUCoreCount() -{ - SYSTEM_INFO info; - - GetSystemInfo(&info); - return info.dwNumberOfProcessors; -} - static WCHAR _cur_iso_locale[16] = L""; @@ -763,7 +750,7 @@ void Win32SetCurrentLocaleName(const char *iso_code) int OTTDStringCompare(const char *s1, const char *s2) { typedef int (WINAPI *PFNCOMPARESTRINGEX)(LPCWSTR, DWORD, LPCWCH, int, LPCWCH, int, LPVOID, LPVOID, LPARAM); - static PFNCOMPARESTRINGEX _CompareStringEx = NULL; + static PFNCOMPARESTRINGEX _CompareStringEx = nullptr; static bool first_time = true; #ifndef SORT_DIGITSASNUMBERS @@ -778,10 +765,10 @@ int OTTDStringCompare(const char *s1, const char *s2) first_time = false; } - if (_CompareStringEx != NULL) { + if (_CompareStringEx != nullptr) { /* CompareStringEx takes UTF-16 strings, even in ANSI-builds. */ - int len_s1 = MultiByteToWideChar(CP_UTF8, 0, s1, -1, NULL, 0); - int len_s2 = MultiByteToWideChar(CP_UTF8, 0, s2, -1, NULL, 0); + int len_s1 = MultiByteToWideChar(CP_UTF8, 0, s1, -1, nullptr, 0); + int len_s2 = MultiByteToWideChar(CP_UTF8, 0, s2, -1, nullptr, 0); if (len_s1 != 0 && len_s2 != 0) { LPWSTR str_s1 = AllocaM(WCHAR, len_s1); @@ -790,7 +777,7 @@ int OTTDStringCompare(const char *s1, const char *s2) MultiByteToWideChar(CP_UTF8, 0, s1, -1, str_s1, len_s1); MultiByteToWideChar(CP_UTF8, 0, s2, -1, str_s2, len_s2); - int result = _CompareStringEx(_cur_iso_locale, LINGUISTIC_IGNORECASE | SORT_DIGITSASNUMBERS, str_s1, -1, str_s2, -1, NULL, NULL, 0); + int result = _CompareStringEx(_cur_iso_locale, LINGUISTIC_IGNORECASE | SORT_DIGITSASNUMBERS, str_s1, -1, str_s2, -1, nullptr, nullptr, 0); if (result != 0) return result; } } @@ -816,12 +803,12 @@ PACK_N(struct THREADNAME_INFO { /** * Signal thread name to any attached debuggers. */ -void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) +void SetCurrentThreadName(const char *threadName) { THREADNAME_INFO info; info.dwType = 0x1000; info.szName = threadName; - info.dwThreadID = dwThreadID; + info.dwThreadID = -1; info.dwFlags = 0; #pragma warning(push) @@ -832,4 +819,6 @@ void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) } #pragma warning(pop) } +#else +void SetCurrentThreadName(const char *) {} #endif diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index 4f813c4a6f..23e216762c 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -39,12 +39,6 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR); #define SHGFP_TYPE_CURRENT 0 #endif /* __MINGW32__ */ -#ifdef _MSC_VER -void SetWin32ThreadName(DWORD dwThreadID, const char* threadName); -#else -static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {} -#endif - void Win32SetCurrentLocaleName(const char *iso_code); int OTTDStringCompare(const char *s1, const char *s2); diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index dc069d1686..380b1b0331 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -46,10 +46,10 @@ struct OskWindow : public Window { OskWindow(WindowDesc *desc, Window *parent, int button) : Window(desc) { this->parent = parent; - assert(parent != NULL); + assert(parent != nullptr); NWidgetCore *par_wid = parent->GetWidget(button); - assert(par_wid != NULL); + assert(par_wid != nullptr); assert(parent->querystrings.Contains(button)); this->qs = parent->querystrings.Find(button)->second; @@ -94,12 +94,12 @@ struct OskWindow : public Window { this->SetWidgetLoweredState(WID_OSK_CAPS, HasBit(_keystate, KEYS_CAPS)); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_OSK_CAPTION) SetDParam(0, this->caption); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget < WID_OSK_LETTERS) return; @@ -110,7 +110,7 @@ struct OskWindow : public Window { TC_BLACK); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { /* clicked a letter */ if (widget >= WID_OSK_LETTERS) { @@ -166,7 +166,7 @@ struct OskWindow : public Window { break; case WID_OSK_OK: - if (this->qs->orig == NULL || strcmp(this->qs->text.buf, this->qs->orig) != 0) { + if (this->qs->orig == nullptr || strcmp(this->qs->text.buf, this->qs->orig) != 0) { /* pass information by simulating a button press on parent window */ if (this->qs->ok_button >= 0) { this->parent->OnClick(pt, this->qs->ok_button, 1); @@ -192,21 +192,21 @@ struct OskWindow : public Window { } } - virtual void OnEditboxChanged(int widget) + void OnEditboxChanged(int widget) override { this->SetWidgetDirty(WID_OSK_TEXT); this->parent->OnEditboxChanged(this->text_btn); this->parent->SetWidgetDirty(this->text_btn); } - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->SetWidgetDirty(WID_OSK_TEXT); this->parent->SetWidgetDirty(this->text_btn); } - virtual void OnFocusLost() + void OnFocusLost() override { VideoDriver::GetInstance()->EditBoxLostFocus(); delete this; @@ -421,13 +421,13 @@ void ShowOnScreenKeyboard(Window *parent, int button) * Updates the original text of the OSK so when the 'parent' changes the * original and you press on cancel you won't get the 'old' original text * but the updated one. - * @param parent window that just updated its orignal text + * @param parent window that just updated its original text * @param button widget number of parent's textbox to update */ void UpdateOSKOriginalText(const Window *parent, int button) { OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); - if (osk == NULL || osk->parent != parent || osk->text_btn != button) return; + if (osk == nullptr || osk->parent != parent || osk->text_btn != button) return; free(osk->orig_str_buf); osk->orig_str_buf = stredup(osk->qs->text.buf); @@ -444,5 +444,5 @@ void UpdateOSKOriginalText(const Window *parent, int button) bool IsOSKOpenedFor(const Window *w, int button) { OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); - return osk != NULL && osk->parent == w && osk->text_btn == button; + return osk != nullptr && osk->parent == w && osk->text_btn == button; } diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp index 9b4377248e..31a7816509 100644 --- a/src/pathfinder/follow_track.hpp +++ b/src/pathfinder/follow_track.hpp @@ -32,7 +32,7 @@ struct CFollowTrackT enum ErrorCode { EC_NONE, EC_OWNER, - EC_RAIL_TYPE, + EC_RAIL_ROAD_TYPE, EC_90DEG, EC_NO_WAY, EC_RESERVED, @@ -53,27 +53,28 @@ struct CFollowTrackT CPerformanceTimer *m_pPerf; RailTypes m_railtypes; - inline CFollowTrackT(const VehicleType *v = NULL, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL) + inline CFollowTrackT(const VehicleType *v = nullptr, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr) { Init(v, railtype_override, pPerf); } - inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL) + inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr) { - m_veh = NULL; + assert(IsRailTT()); + m_veh = nullptr; Init(o, railtype_override, pPerf); } inline void Init(const VehicleType *v, RailTypes railtype_override, CPerformanceTimer *pPerf) { - assert(!IsRailTT() || (v != NULL && v->type == VEH_TRAIN)); + assert(!IsRailTT() || (v != nullptr && v->type == VEH_TRAIN)); m_veh = v; - Init(v != NULL ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf); + Init(v != nullptr ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf); } inline void Init(Owner o, RailTypes railtype_override, CPerformanceTimer *pPerf) { - assert(!IsRoadTT() || m_veh != NULL); + assert(!IsRoadTT() || m_veh != nullptr); assert(!IsRailTT() || railtype_override != INVALID_RAILTYPES); m_veh_owner = o; m_pPerf = pPerf; @@ -92,7 +93,7 @@ struct CFollowTrackT inline static TransportType TT() { return Ttr_type_; } inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; } inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; } - inline bool IsTram() { return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM); } + inline bool IsTram() { return IsRoadTT() && RoadTypeIsTram(RoadVehicle::From(m_veh)->roadtype); } inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; } inline static bool Allow90degTurns() { return T90deg_turns_allowed_; } inline static bool DoTrackMasking() { return Tmask_reserved_tracks; } @@ -103,7 +104,7 @@ struct CFollowTrackT assert(IsTram()); // this function shouldn't be called in other cases if (IsNormalRoadTile(tile)) { - RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM); + RoadBits rb = GetRoadBits(tile, RTT_TRAM); switch (rb) { case ROAD_NW: return DIAGDIR_NW; case ROAD_SW: return DIAGDIR_SW; @@ -126,7 +127,7 @@ struct CFollowTrackT m_err = EC_NONE; assert( ((TrackStatusToTrackdirBits( - GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != NULL) ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0) + GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != nullptr) ? (this->IsTram() ? RTT_TRAM : RTT_ROAD) : 0) ) & TrackdirToTrackdirBits(m_old_td)) != 0) || (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR) // Disable the assertion for single tram bits ); @@ -151,13 +152,13 @@ struct CFollowTrackT if (IsRoadTT() && !IsTram() && TryReverse()) return true; /* CanEnterNewTile already set a reason. - * Do NOT overwrite it (important for example for EC_RAIL_TYPE). + * Do NOT overwrite it (important for example for EC_RAIL_ROAD_TYPE). * Only set a reason if CanEnterNewTile was not called */ if (m_new_td_bits == TRACKDIR_BIT_NONE) m_err = EC_NO_WAY; return false; } - if (!Allow90degTurns()) { + if ((!IsRailTT() && !Allow90degTurns()) || (IsRailTT() && Rail90DegTurnDisallowed(GetTileRailType(m_old_tile), GetTileRailType(m_new_tile), !Allow90degTurns()))) { m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td); if (m_new_td_bits == TRACKDIR_BIT_NONE) { m_err = EC_90DEG; @@ -241,7 +242,7 @@ protected: if (IsRailTT() && IsPlainRailTile(m_new_tile)) { m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101); } else { - m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)); + m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? (this->IsTram() ? RTT_TRAM : RTT_ROAD) : 0)); if (IsTram() && m_new_td_bits == TRACKDIR_BIT_NONE) { /* GetTileTrackStatus() returns 0 for single tram bits. @@ -350,7 +351,18 @@ protected: RailType rail_type = GetTileRailType(m_new_tile); if (!HasBit(m_railtypes, rail_type)) { /* incompatible rail type */ - m_err = EC_RAIL_TYPE; + m_err = EC_RAIL_ROAD_TYPE; + return false; + } + } + + /* road transport is possible only on compatible road types */ + if (IsRoadTT()) { + const RoadVehicle *v = RoadVehicle::From(m_veh); + RoadType roadtype = GetRoadType(m_new_tile, GetRoadTramType(v->roadtype)); + if (!HasBit(v->compatible_roadtypes, roadtype)) { + /* incompatible road type */ + m_err = EC_RAIL_ROAD_TYPE; return false; } } @@ -447,7 +459,7 @@ protected: public: /** Helper for pathfinders - get min/max speed on the m_old_tile/m_old_td */ - int GetSpeedLimit(int *pmin_speed = NULL) const + int GetSpeedLimit(int *pmin_speed = nullptr) const { int min_speed = 0; int max_speed = INT_MAX; // no limit @@ -465,7 +477,7 @@ public: } /* if min speed was requested, return it */ - if (pmin_speed != NULL) *pmin_speed = min_speed; + if (pmin_speed != nullptr) *pmin_speed = min_speed; return max_speed; } }; @@ -474,8 +486,6 @@ typedef CFollowTrackT CFollowTrackWater; typedef CFollowTrackT CFollowTrackRoad; typedef CFollowTrackT CFollowTrackRail; -typedef CFollowTrackT CFollowTrackWaterNo90; -typedef CFollowTrackT CFollowTrackRoadNo90; typedef CFollowTrackT CFollowTrackRailNo90; typedef CFollowTrackT CFollowTrackFreeRail; diff --git a/src/pathfinder/npf/aystar.cpp b/src/pathfinder/npf/aystar.cpp index beac06291f..addfc4930e 100644 --- a/src/pathfinder/npf/aystar.cpp +++ b/src/pathfinder/npf/aystar.cpp @@ -32,7 +32,7 @@ /** * This looks in the hash whether a node exists in the closed list. * @param node Node to search. - * @return The #PathNode if it is available, else \c NULL + * @return The #PathNode if it is available, else \c nullptr */ PathNode *AyStar::ClosedListIsInList(const AyStarNode *node) { @@ -55,7 +55,7 @@ void AyStar::ClosedListAdd(const PathNode *node) /** * Check whether a node is in the open list. * @param node Node to search. - * @return If the node is available, it is returned, else \c NULL is returned. + * @return If the node is available, it is returned, else \c nullptr is returned. */ OpenListNode *AyStar::OpenListIsInList(const AyStarNode *node) { @@ -65,13 +65,13 @@ OpenListNode *AyStar::OpenListIsInList(const AyStarNode *node) /** * Gets the best node from the open list. * It deletes the returned node from the open list. - * @returns the best node available, or \c NULL of none is found. + * @returns the best node available, or \c nullptr of none is found. */ OpenListNode *AyStar::OpenListPop() { /* Return the item the Queue returns.. the best next OpenList item. */ OpenListNode *res = (OpenListNode*)this->openlist_queue.Pop(); - if (res != NULL) { + if (res != nullptr) { this->openlist_hash.DeleteValue(res->path.node.tile, res->path.node.direction); } @@ -105,7 +105,7 @@ void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent) OpenListNode *check; /* Check the new node against the ClosedList */ - if (this->ClosedListIsInList(current) != NULL) return; + if (this->ClosedListIsInList(current) != nullptr) return; /* Calculate the G-value for this node */ new_g = this->CalculateG(this, current, parent); @@ -131,7 +131,7 @@ void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent) /* Check if this item is already in the OpenList */ check = this->OpenListIsInList(current); - if (check != NULL) { + if (check != nullptr) { uint i; /* Yes, check if this g value is lower.. */ if (new_g > check->g) return; @@ -167,11 +167,11 @@ int AyStar::Loop() /* Get the best node from OpenList */ OpenListNode *current = this->OpenListPop(); /* If empty, drop an error */ - if (current == NULL) return AYSTAR_EMPTY_OPENLIST; + if (current == nullptr) return AYSTAR_EMPTY_OPENLIST; /* Check for end node and if found, return that code */ if (this->EndNodeCheck(this, current) == AYSTAR_FOUND_END_NODE && !CheckIgnoreFirstTile(¤t->path)) { - if (this->FoundEndNode != NULL) { + if (this->FoundEndNode != nullptr) { this->FoundEndNode(this, current); } free(current); @@ -285,7 +285,7 @@ void AyStar::AddStartNode(AyStarNode *start_node, uint g) printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", TileX(start_node->tile), TileY(start_node->tile), start_node->direction); #endif - this->OpenListAdd(NULL, start_node, 0, g); + this->OpenListAdd(nullptr, start_node, 0, g); } /** diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index 7d19d4ef1d..1c39a30a05 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -14,6 +14,7 @@ #include "../../viewport_func.h" #include "../../ship.h" #include "../../roadstop_base.h" +#include "../../vehicle_func.h" #include "../pathfinder_func.h" #include "../pathfinder_type.h" #include "../follow_track.hpp" @@ -43,6 +44,7 @@ struct AyStarUserData { TransportType type; RailTypes railtypes; RoadTypes roadtypes; + uint subtype; }; /** Indices into AyStarNode.userdata[] */ @@ -103,7 +105,7 @@ static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value) bool CheckIgnoreFirstTile(const PathNode *node) { - return (node->parent == NULL && HasBit(node->node.user_data[NPF_NODE_FLAGS], NPF_FLAG_IGNORE_START_TILE)); + return (node->parent == nullptr && HasBit(node->node.user_data[NPF_NODE_FLAGS], NPF_FLAG_IGNORE_START_TILE)); } /** @@ -164,8 +166,8 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open uint dist; AyStarUserData *user = (AyStarUserData *)as->user_data; - /* for train-stations, we are going to aim for the closest station tile */ - if (user->type != TRANSPORT_WATER && fstd->station_index != INVALID_STATION) { + /* aim for the closest station tile */ + if (fstd->station_index != INVALID_STATION) { to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type); } @@ -192,7 +194,7 @@ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, Open * choice */ static void NPFFillTrackdirChoice(AyStarNode *current, OpenListNode *parent) { - if (parent->path.parent == NULL) { + if (parent->path.parent == nullptr) { Trackdir trackdir = current->direction; /* This is a first order decision, so we'd better save the * direction we chose */ @@ -302,6 +304,15 @@ static void NPFMarkTile(TileIndex tile) } } +static Vehicle *CountShipProc(Vehicle *v, void *data) +{ + uint *count = (uint *)data; + /* Ignore other vehicles (aircraft) and ships inside depot. */ + if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++; + + return nullptr; +} + static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent) { /* TileIndex tile = current->tile; */ @@ -318,6 +329,13 @@ static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *par cost += _settings_game.pf.npf.npf_water_curve_penalty; } + if (IsDockingTile(current->tile)) { + /* Check docking tile for occupancy */ + uint count = 1; + HasVehicleOnPos(current->tile, &count, &CountShipProc); + cost += count * 3 * _trackdir_length[trackdir]; + } + /* @todo More penalties? */ return cost; @@ -562,6 +580,12 @@ static int32 NPFFindStationOrTile(const AyStar *as, const OpenListNode *current) if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE; + if (fstd->v->type == VEH_SHIP) { + /* Ships do not actually reach the destination station, so we check for a docking tile instead. */ + if (IsDockingTile(tile) && IsShipDestinationTile(tile, fstd->station_index)) return AYSTAR_FOUND_END_NODE; + return AYSTAR_DONE; + } + if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) { if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE; @@ -584,7 +608,7 @@ static const PathNode *FindSafePosition(PathNode *path, const Train *v) /* If there is no signal, reserve the whole path. */ PathNode *sig = path; - for (; path->parent != NULL; path = path->parent) { + for (; path->parent != nullptr; path = path->parent) { if (IsSafeWaitingPosition(v, path->node.tile, path->node.direction, true, _settings_game.pf.forbid_90_deg)) { sig = path; } @@ -625,7 +649,7 @@ static void NPFSaveTargetData(AyStar *as, OpenListNode *current) ftd->node = current->path.node; ftd->res_okay = false; - if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && user->type == TRANSPORT_RAIL) { + if (as->user_target != nullptr && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && user->type == TRANSPORT_RAIL) { /* Path reservation is requested. */ const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v); @@ -647,7 +671,7 @@ static void NPFSaveTargetData(AyStar *as, OpenListNode *current) if (!IsWaitingPositionFree(v, target->node.tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return; } - for (const PathNode *cur = target; cur->parent != NULL; cur = cur->parent) { + for (const PathNode *cur = target; cur->parent != nullptr; cur = cur->parent) { if (!TryReserveRailTrack(cur->node.tile, TrackdirToTrack(cur->node.direction))) { /* Reservation failed, undo. */ ClearPathReservation(target, cur); @@ -719,7 +743,7 @@ static DiagDirection GetDepotDirection(TileIndex tile, TransportType type) static DiagDirection GetSingleTramBit(TileIndex tile) { if (IsNormalRoadTile(tile)) { - RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM); + RoadBits rb = GetRoadBits(tile, RTT_TRAM); switch (rb) { case ROAD_NW: return DIAGDIR_NW; case ROAD_SW: return DIAGDIR_SW; @@ -747,7 +771,7 @@ static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint if (type == TRANSPORT_ROAD) { if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile); - if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile); + if ((RoadTramType)subtype == RTT_TRAM) return GetSingleTramBit(tile); } return INVALID_DIAGDIR; @@ -785,13 +809,24 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user if (!CanEnterTileOwnerCheck(user->owner, tile, dir)) return false; /* check correct rail type (mono, maglev, etc) */ - if (user->type == TRANSPORT_RAIL) { - RailType rail_type = GetTileRailType(tile); - if (!HasBit(user->railtypes, rail_type)) return false; + switch (user->type) { + case TRANSPORT_RAIL: { + RailType rail_type = GetTileRailType(tile); + if (!HasBit(user->railtypes, rail_type)) return false; + break; + } + + case TRANSPORT_ROAD: { + RoadType road_type = GetRoadType(tile, (RoadTramType)user->subtype); + if (!HasBit(user->roadtypes, road_type)) return false; + break; + } + + default: break; } /* Depots, standard roadstops and single tram bits can only be entered from one direction */ - DiagDirection single_entry = GetTileSingleEntry(tile, user->type, user->roadtypes); + DiagDirection single_entry = GetTileSingleEntry(tile, user->type, user->subtype); if (single_entry != INVALID_DIAGDIR && single_entry != ReverseDiagDir(dir)) return false; return true; @@ -803,16 +838,17 @@ static bool CanEnterTile(TileIndex tile, DiagDirection dir, AyStarUserData *user * One-way-roads are taken into account. Signals are not tested. * * @param dst_tile The tile of interest. + * @param src_tile The originating tile. * @param src_trackdir The direction the vehicle is currently moving. * @param type The transporttype of the vehicle. * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle. * @return The Trackdirs the vehicle can continue moving on. */ -static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype) +static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, TileIndex src_tile, Trackdir src_trackdir, TransportType type, uint subtype) { TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype)); - if (trackdirbits == TRACKDIR_BIT_NONE && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) { + if (trackdirbits == TRACKDIR_BIT_NONE && type == TRANSPORT_ROAD && (RoadTramType)subtype == RTT_TRAM) { /* GetTileTrackStatus() returns 0 for single tram bits. * As we cannot change it there (easily) without breaking something, change it here */ switch (GetSingleTramBit(dst_tile)) { @@ -836,7 +872,9 @@ static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_tr trackdirbits &= TrackdirReachesTrackdirs(src_trackdir); /* Filter out trackdirs that would make 90 deg turns for trains */ - if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir); + if (type == TRANSPORT_RAIL && Rail90DegTurnDisallowed(GetTileRailType(src_tile), GetTileRailType(dst_tile))) { + trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir); + } DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits); @@ -860,7 +898,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) /* Information about the vehicle: TransportType (road/rail/water) and SubType (compatible rail/road types) */ TransportType type = user->type; - uint subtype = user->roadtypes; + uint subtype = user->subtype; /* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */ aystar->num_neighbours = 0; @@ -877,7 +915,7 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) if (CheckIgnoreFirstTile(¤t->path)) { /* Do not perform any checks that involve src_tile */ dst_tile = src_tile + TileOffsByDiagDir(src_exitdir); - trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); + trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype); } else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) { /* We drive through the wormhole and arrive on the other side */ dst_tile = GetOtherTunnelBridgeEnd(src_tile); @@ -891,26 +929,26 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) /* We leave src_tile in src_exitdir and reach dst_tile */ dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir)); - if (dst_tile != INVALID_TILE && !CanEnterTile(dst_tile, src_exitdir, user)) dst_tile = INVALID_TILE; + if (dst_tile != INVALID_TILE && IsNormalRoadTile(dst_tile) && !CanEnterTile(dst_tile, src_exitdir, user)) dst_tile = INVALID_TILE; if (dst_tile == INVALID_TILE) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ - if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; + if (type != TRANSPORT_ROAD || (RoadTramType)subtype == RTT_TRAM) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); } - trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); + trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype); if (trackdirbits == TRACKDIR_BIT_NONE) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ - if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; + if (type != TRANSPORT_ROAD || (RoadTramType)subtype == RTT_TRAM) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); - trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); + trackdirbits = GetDriveableTrackdirBits(dst_tile, src_tile, src_trackdir, type, subtype); } } @@ -954,13 +992,13 @@ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) /* * Plan a route to the specified target (which is checked by target_proc), - * from start1 and if not NULL, from start2 as well. The type of transport we + * from start1 and if not nullptr, from start2 as well. The type of transport we * are checking is in type. reverse_penalty is applied to all routes that * originate from the second start node. * When we are looking for one specific target (optionally multiple tiles), we * should use a good heuristic to perform aystar search. When we search for * multiple targets that are spread around, we should perform a breadth first - * search by specifiying CalcZero as our heuristic. + * search by specifying CalcZero as our heuristic. */ static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start_tile1, AyStarNode *start2, bool ignore_start_tile2, NPFFindStationOrTileData *target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, AyStarUserData *user, uint reverse_penalty, bool ignore_reserved = false, int max_penalty = 0) { @@ -986,7 +1024,7 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start NPFSetFlag(start1, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile1); NPFSetFlag(start1, NPF_FLAG_IGNORE_RESERVED, ignore_reserved); _npf_aystar.AddStartNode(start1, 0); - if (start2 != NULL) { + if (start2 != nullptr) { start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start2->user_data[NPF_NODE_FLAGS] = 0; NPFSetFlag(start2, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile2); @@ -1014,10 +1052,10 @@ static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start assert(r != AYSTAR_STILL_BUSY); if (result.best_bird_dist != 0) { - if (target != NULL) { + if (target != nullptr) { DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile); } else { - /* Assumption: target == NULL, so we are looking for a depot */ + /* Assumption: target == nullptr, so we are looking for a depot */ DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile); } @@ -1038,7 +1076,7 @@ static NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdi start1.direction = trackdir1; start2.direction = trackdir2; - return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, user, 0); + return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : nullptr), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, user, 0); } /* Will search from the given tile and direction, for a route to the given @@ -1066,9 +1104,9 @@ static NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Tra start1.direction = trackdir1; start2.direction = trackdir2; - /* perform a breadth first search. Target is NULL, + /* perform a breadth first search. Target is nullptr, * since we are just looking for any depot...*/ - return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindDepot, NPFCalcZero, user, reverse_penalty, false, max_penalty); + return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : nullptr), ignore_start_tile2, target, NPFFindDepot, NPFCalcZero, user, reverse_penalty, false, max_penalty); } void InitializeNPF() @@ -1096,10 +1134,16 @@ static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle * * dest_tile, not just any stop of that station. * So only for train orders to stations we fill fstd->station_index, for all * others only dest_coords */ - if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) { - assert(v->IsGroundVehicle()); + if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT)) { fstd->station_index = v->current_order.GetDestination(); - fstd->station_type = (v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) : (RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK); + if (v->type == VEH_TRAIN) { + fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT; + } else if (v->type == VEH_ROAD) { + fstd->station_type = RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK; + } else if (v->type == VEH_SHIP) { + fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_DOCK : STATION_BUOY; + } + fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart(); /* Let's take the closest tile of the station as our target for vehicles */ fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type); @@ -1117,8 +1161,8 @@ FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penal { Trackdir trackdir = v->GetVehicleTrackdir(); - AyStarUserData user = { v->owner, TRANSPORT_ROAD, INVALID_RAILTYPES, v->compatible_roadtypes }; - NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, INVALID_TILE, INVALID_TRACKDIR, false, NULL, &user, 0, max_penalty); + AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes, GetRoadTramType(v->roadtype) }; + NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, INVALID_TILE, INVALID_TRACKDIR, false, nullptr, &user, 0, max_penalty); if (ftd.best_bird_dist != 0) return FindDepotData(); @@ -1137,7 +1181,7 @@ Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDir NPFFillWithOrderData(&fstd, v); Trackdir trackdir = DiagDirToDiagTrackdir(enterdir); - AyStarUserData user = { v->owner, TRANSPORT_ROAD, INVALID_RAILTYPES, v->compatible_roadtypes }; + AyStarUserData user = { v->owner, TRANSPORT_ROAD, RAILTYPES_NONE, v->compatible_roadtypes, GetRoadTramType(v->roadtype) }; NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, &user); assert(ftd.best_trackdir != INVALID_TRACKDIR); @@ -1160,7 +1204,7 @@ Track NPFShipChooseTrack(const Ship *v, bool &path_found) NPFFillWithOrderData(&fstd, v); - AyStarUserData user = { v->owner, TRANSPORT_WATER, INVALID_RAILTYPES, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE, 0 }; NPFFoundTargetData ftd = NPFRouteToStationOrTile(v->tile, trackdir, true, &fstd, &user); assert(ftd.best_trackdir != INVALID_TRACKDIR); @@ -1185,7 +1229,7 @@ bool NPFShipCheckReverse(const Ship *v) assert(trackdir != INVALID_TRACKDIR); assert(trackdir_rev != INVALID_TRACKDIR); - AyStarUserData user = { v->owner, TRANSPORT_WATER, INVALID_RAILTYPES, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_WATER, RAILTYPES_NONE, ROADTYPES_NONE, 0 }; ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, v->tile, trackdir_rev, false, &fstd, &user); /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); @@ -1203,7 +1247,7 @@ FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty) fstd.reserve_path = false; assert(trackdir != INVALID_TRACKDIR); - AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 }; NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, &user, NPF_INFINITE_PENALTY, max_penalty); if (ftd.best_bird_dist != 0) return FindDepotData(); @@ -1230,10 +1274,10 @@ bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackd RailTypes railtypes = v->compatible_railtypes; if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes; - /* perform a breadth first search. Target is NULL, + /* perform a breadth first search. Target is nullptr, * since we are just looking for any safe tile...*/ - AyStarUserData user = { v->owner, TRANSPORT_RAIL, railtypes, ROADTYPES_NONE }; - return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, &user, 0, true).res_okay; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, railtypes, ROADTYPES_NONE, 0 }; + return NPFRouteInternal(&start1, true, nullptr, false, &fstd, NPFFindSafeTile, NPFCalcZero, &user, 0, true).res_okay; } bool NPFTrainCheckReverse(const Train *v) @@ -1249,7 +1293,7 @@ bool NPFTrainCheckReverse(const Train *v) assert(trackdir != INVALID_TRACKDIR); assert(trackdir_rev != INVALID_TRACKDIR); - AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 }; ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, &user); /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); @@ -1263,10 +1307,10 @@ Track NPFTrainChooseTrack(const Train *v, bool &path_found, bool reserve_track, PBSTileInfo origin = FollowTrainReservation(v); assert(IsValidTrackdir(origin.trackdir)); - AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE }; + AyStarUserData user = { v->owner, TRANSPORT_RAIL, v->compatible_railtypes, ROADTYPES_NONE, 0 }; NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, &user); - if (target != NULL) { + if (target != nullptr) { target->tile = ftd.node.tile; target->trackdir = (Trackdir)ftd.node.direction; target->okay = ftd.res_okay; diff --git a/src/pathfinder/npf/queue.cpp b/src/pathfinder/npf/queue.cpp index 2afb413918..02a195c5df 100644 --- a/src/pathfinder/npf/queue.cpp +++ b/src/pathfinder/npf/queue.cpp @@ -37,7 +37,7 @@ void BinaryHeap::Clear(bool free_values) uint j; for (i = 0; i < this->blocks; i++) { - if (this->elements[i] == NULL) { + if (this->elements[i] == nullptr) { /* No more allocated blocks */ break; } @@ -55,7 +55,7 @@ void BinaryHeap::Clear(bool free_values) if (i != 0) { /* Leave the first block of memory alone */ free(this->elements[i]); - this->elements[i] = NULL; + this->elements[i] = nullptr; } } this->size = 0; @@ -73,7 +73,7 @@ void BinaryHeap::Free(bool free_values) this->Clear(free_values); for (i = 0; i < this->blocks; i++) { - if (this->elements[i] == NULL) break; + if (this->elements[i] == nullptr) break; free(this->elements[i]); } free(this->elements); @@ -88,7 +88,7 @@ bool BinaryHeap::Push(void *item, int priority) if (this->size == this->max_size) return false; assert(this->size < this->max_size); - if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) { + if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == nullptr) { /* The currently allocated blocks are full, allocate a new one */ assert((this->size & BINARY_HEAP_BLOCKSIZE_MASK) == 0); this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT(BINARY_HEAP_BLOCKSIZE); @@ -195,7 +195,7 @@ void *BinaryHeap::Pop() { void *result; - if (this->size == 0) return NULL; + if (this->size == 0) return nullptr; /* The best item is always on top, so give that as result */ result = this->GetElement(1).item; @@ -264,7 +264,7 @@ void Hash::Delete(bool free_values) /* Free the first value */ if (free_values) free(this->buckets[i].value); node = this->buckets[i].next; - while (node != NULL) { + while (node != nullptr) { HashNode *prev = node; node = node->next; @@ -296,7 +296,7 @@ void Hash::PrintStatistics() const const HashNode *node; used_buckets++; - for (node = &this->buckets[i]; node != NULL; node = node->next) collision++; + for (node = &this->buckets[i]; node != nullptr; node = node->next) collision++; if (collision > max_collision) max_collision = collision; } if (collision >= lengthof(usage)) collision = lengthof(usage) - 1; @@ -351,7 +351,7 @@ void Hash::Clear(bool free_values) /* Free the first value */ if (free_values) free(this->buckets[i].value); node = this->buckets[i].next; - while (node != NULL) { + while (node != nullptr) { HashNode *prev = node; node = node->next; @@ -365,32 +365,32 @@ void Hash::Clear(bool free_values) /** * Finds the node that that saves this key pair. If it is not - * found, returns NULL. If it is found, *prev is set to the + * found, returns nullptr. If it is found, *prev is set to the * node before the one found, or if the node found was the first in the bucket - * to NULL. If it is not found, *prev is set to the last HashNode in the - * bucket, or NULL if it is empty. prev can also be NULL, in which case it is + * to nullptr. If it is not found, *prev is set to the last HashNode in the + * bucket, or nullptr if it is empty. prev can also be nullptr, in which case it is * not used for output. */ HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const { uint hash = this->hash(key1, key2); - HashNode *result = NULL; + HashNode *result = nullptr; /* Check if the bucket is empty */ if (!this->buckets_in_use[hash]) { - if (prev_out != NULL) *prev_out = NULL; - result = NULL; + if (prev_out != nullptr) *prev_out = nullptr; + result = nullptr; /* Check the first node specially */ } else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) { /* Save the value */ result = this->buckets + hash; - if (prev_out != NULL) *prev_out = NULL; + if (prev_out != nullptr) *prev_out = nullptr; /* Check all other nodes */ } else { HashNode *prev = this->buckets + hash; HashNode *node; - for (node = prev->next; node != NULL; node = node->next) { + for (node = prev->next; node != nullptr; node = node->next) { if (node->key1 == key1 && node->key2 == key2) { /* Found it */ result = node; @@ -398,14 +398,14 @@ HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const } prev = node; } - if (prev_out != NULL) *prev_out = prev; + if (prev_out != nullptr) *prev_out = prev; } return result; } /** * Deletes the value with the specified key pair from the hash and returns - * that value. Returns NULL when the value was not present. The value returned + * that value. Returns nullptr when the value was not present. The value returned * is _not_ free()'d! */ void *Hash::DeleteValue(uint key1, uint key2) @@ -414,15 +414,15 @@ void *Hash::DeleteValue(uint key1, uint key2) HashNode *prev; // Used as output var for below function call HashNode *node = this->FindNode(key1, key2, &prev); - if (node == NULL) { + if (node == nullptr) { /* not found */ - result = NULL; - } else if (prev == NULL) { + result = nullptr; + } else if (prev == nullptr) { /* It is in the first node, we can't free that one, so we free * the next one instead (if there is any)*/ /* Save the value */ result = node->value; - if (node->next != NULL) { + if (node->next != nullptr) { HashNode *next = node->next; /* Copy the second to the first */ *node = *next; @@ -443,20 +443,20 @@ void *Hash::DeleteValue(uint key1, uint key2) /* Free the node */ free(node); } - if (result != NULL) this->size--; + if (result != nullptr) this->size--; return result; } /** * Sets the value associated with the given key pair to the given value. - * Returns the old value if the value was replaced, NULL when it was not yet present. + * Returns the old value if the value was replaced, nullptr when it was not yet present. */ void *Hash::Set(uint key1, uint key2, void *value) { HashNode *prev; HashNode *node = this->FindNode(key1, key2, &prev); - if (node != NULL) { + if (node != nullptr) { /* Found it */ void *result = node->value; @@ -464,7 +464,7 @@ void *Hash::Set(uint key1, uint key2, void *value) return result; } /* It is not yet present, let's add it */ - if (prev == NULL) { + if (prev == nullptr) { /* The bucket is still empty */ uint hash = this->hash(key1, key2); this->buckets_in_use[hash] = true; @@ -474,21 +474,21 @@ void *Hash::Set(uint key1, uint key2, void *value) node = MallocT(1); prev->next = node; } - node->next = NULL; + node->next = nullptr; node->key1 = key1; node->key2 = key2; node->value = value; this->size++; - return NULL; + return nullptr; } /** - * Gets the value associated with the given key pair, or NULL when it is not + * Gets the value associated with the given key pair, or nullptr when it is not * present. */ void *Hash::Get(uint key1, uint key2) const { - HashNode *node = this->FindNode(key1, key2, NULL); + HashNode *node = this->FindNode(key1, key2, nullptr); - return (node != NULL) ? node->value : NULL; + return (node != nullptr) ? node->value : nullptr; } diff --git a/src/pathfinder/pathfinder_type.h b/src/pathfinder/pathfinder_type.h index 0ecf00bbd2..3740d03902 100644 --- a/src/pathfinder/pathfinder_type.h +++ b/src/pathfinder/pathfinder_type.h @@ -43,6 +43,9 @@ static const int YAPF_INFINITE_PENALTY = 1000 * YAPF_TILE_LENGTH; /** Maximum length of ship path cache */ static const int YAPF_SHIP_PATH_CACHE_LENGTH = 32; +/** Maximum segments of road vehicle path cache */ +static const int YAPF_ROADVEH_PATH_CACHE_SEGMENTS = 8; + /** * Helper container to find a depot */ diff --git a/src/pathfinder/pf_performance_timer.hpp b/src/pathfinder/pf_performance_timer.hpp index 808542d25a..c06ef815ef 100644 --- a/src/pathfinder/pf_performance_timer.hpp +++ b/src/pathfinder/pf_performance_timer.hpp @@ -53,7 +53,7 @@ struct CPerfStartReal inline CPerfStartReal(CPerformanceTimer& perf) : m_pperf(&perf) { - if (m_pperf != NULL) m_pperf->Start(); + if (m_pperf != nullptr) m_pperf->Start(); } inline ~CPerfStartReal() @@ -63,9 +63,9 @@ struct CPerfStartReal inline void Stop() { - if (m_pperf != NULL) { + if (m_pperf != nullptr) { m_pperf->Stop(); - m_pperf = NULL; + m_pperf = nullptr; } } }; diff --git a/src/pathfinder/yapf/nodelist.hpp b/src/pathfinder/yapf/nodelist.hpp index 87e65fd26e..45a72efd5e 100644 --- a/src/pathfinder/yapf/nodelist.hpp +++ b/src/pathfinder/yapf/nodelist.hpp @@ -42,7 +42,7 @@ public: /** default constructor */ CNodeList_HashTableT() : m_open_queue(2048) { - m_new_node = NULL; + m_new_node = nullptr; } /** destructor */ @@ -65,7 +65,7 @@ public: /** allocate new data item from m_arr */ inline Titem_ *CreateNewNode() { - if (m_new_node == NULL) m_new_node = m_arr.AppendC(); + if (m_new_node == nullptr) m_new_node = m_arr.AppendC(); return m_new_node; } @@ -74,7 +74,7 @@ public: { /* for now it is enough to invalidate m_new_node if it is our given node */ if (&item == m_new_node) { - m_new_node = NULL; + m_new_node = nullptr; } /* TODO: do we need to store best nodes found in some extra list/array? Probably not now. */ } @@ -82,11 +82,11 @@ public: /** insert given item as open node (into m_open and m_open_queue) */ inline void InsertOpenNode(Titem_ &item) { - assert(m_closed.Find(item.GetKey()) == NULL); + assert(m_closed.Find(item.GetKey()) == nullptr); m_open.Push(item); m_open_queue.Include(&item); if (&item == m_new_node) { - m_new_node = NULL; + m_new_node = nullptr; } } @@ -96,7 +96,7 @@ public: if (!m_open_queue.IsEmpty()) { return m_open_queue.Begin(); } - return NULL; + return nullptr; } /** remove and return the best open node */ @@ -107,10 +107,10 @@ public: m_open.Pop(*item); return item; } - return NULL; + return nullptr; } - /** return the open node specified by a key or NULL if not found */ + /** return the open node specified by a key or nullptr if not found */ inline Titem_ *FindOpenNode(const Key &key) { Titem_ *item = m_open.Find(key); @@ -129,11 +129,11 @@ public: /** close node */ inline void InsertClosedNode(Titem_ &item) { - assert(m_open.Find(item.GetKey()) == NULL); + assert(m_open.Find(item.GetKey()) == nullptr); m_closed.Push(item); } - /** return the closed node specified by a key or NULL if not found */ + /** return the closed node specified by a key or nullptr if not found */ inline Titem_ *FindClosedNode(const Key &key) { Titem_ *item = m_closed.Find(key); diff --git a/src/pathfinder/yapf/yapf.h b/src/pathfinder/yapf/yapf.h index 84bd35c8b0..3bea692b79 100644 --- a/src/pathfinder/yapf/yapf.h +++ b/src/pathfinder/yapf/yapf.h @@ -16,6 +16,7 @@ #include "../../track_type.h" #include "../../vehicle_type.h" #include "../../ship.h" +#include "../../roadveh.h" #include "../pathfinder_type.h" /** @@ -45,7 +46,7 @@ bool YapfShipCheckReverse(const Ship *v); * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @return the best trackdir for next turn or INVALID_TRACKDIR if the path could not be found */ -Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found); +Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache); /** * Finds the best path for given train using YAPF. diff --git a/src/pathfinder/yapf/yapf_base.hpp b/src/pathfinder/yapf/yapf_base.hpp index 6360567bb2..5483b98747 100644 --- a/src/pathfinder/yapf/yapf_base.hpp +++ b/src/pathfinder/yapf/yapf_base.hpp @@ -81,11 +81,11 @@ public: public: /** default constructor */ inline CYapfBaseT() - : m_pBestDestNode(NULL) - , m_pBestIntermediateNode(NULL) + : m_pBestDestNode(nullptr) + , m_pBestIntermediateNode(nullptr) , m_settings(&_settings_game.pf.yapf) , m_max_search_nodes(PfGetSettings().max_search_nodes) - , m_veh(NULL) + , m_veh(nullptr) , m_stats_cost_calcs(0) , m_stats_cache_hits(0) , m_num_steps(0) @@ -131,12 +131,12 @@ public: for (;;) { m_num_steps++; Node *n = m_nodes.GetBestOpenNode(); - if (n == NULL) { + if (n == nullptr) { break; } /* if the best open node was worse than the best path found, we can finish */ - if (m_pBestDestNode != NULL && m_pBestDestNode->GetCost() < n->GetCostEstimate()) { + if (m_pBestDestNode != nullptr && m_pBestDestNode->GetCost() < n->GetCostEstimate()) { break; } @@ -150,7 +150,7 @@ public: } } - bDestFound &= (m_pBestDestNode != NULL); + bDestFound &= (m_pBestDestNode != nullptr); perf.Stop(); if (_debug_yapf_level >= 2) { @@ -158,7 +158,7 @@ public: _total_pf_time_us += t; if (_debug_yapf_level >= 3) { - UnitID veh_idx = (m_veh != NULL) ? m_veh->unitnumber : 0; + UnitID veh_idx = (m_veh != nullptr) ? m_veh->unitnumber : 0; char ttc = Yapf().TransportTypeChar(); float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f); int cost = bDestFound ? m_pBestDestNode->m_cost : -1; @@ -180,7 +180,7 @@ public: */ inline Node *GetBestNode() { - return (m_pBestDestNode != NULL) ? m_pBestDestNode : m_pBestIntermediateNode; + return (m_pBestDestNode != nullptr) ? m_pBestDestNode : m_pBestIntermediateNode; } /** @@ -198,7 +198,7 @@ public: { Yapf().PfNodeCacheFetch(n); /* insert the new node only if it is not there */ - if (m_nodes.FindOpenNode(n.m_key) == NULL) { + if (m_nodes.FindOpenNode(n.m_key) == nullptr) { m_nodes.InsertOpenNode(n); } else { /* if we are here, it means that node is already there - how it is possible? @@ -229,7 +229,7 @@ public: */ void PruneIntermediateNodeBranch() { - while (Yapf().m_pBestIntermediateNode != NULL && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) { + while (Yapf().m_pBestIntermediateNode != nullptr && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) { Yapf().m_pBestIntermediateNode = Yapf().m_pBestIntermediateNode->m_parent; } } @@ -262,20 +262,20 @@ public: /* detect the destination */ bool bDestination = Yapf().PfDetectDestination(n); if (bDestination) { - if (m_pBestDestNode == NULL || n < *m_pBestDestNode) { + if (m_pBestDestNode == nullptr || n < *m_pBestDestNode) { m_pBestDestNode = &n; } m_nodes.FoundBestNode(n); return; } - if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == NULL || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) { + if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == nullptr || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) { m_pBestIntermediateNode = &n; } /* check new node against open list */ Node *openNode = m_nodes.FindOpenNode(n.GetKey()); - if (openNode != NULL) { + if (openNode != nullptr) { /* another node exists with the same key in the open list * is it better than new one? */ if (n.GetCostEstimate() < openNode->GetCostEstimate()) { @@ -290,7 +290,7 @@ public: /* check new node against closed list */ Node *closedNode = m_nodes.FindClosedNode(n.GetKey()); - if (closedNode != NULL) { + if (closedNode != nullptr) { /* another node exists with the same key in the closed list * is it better than new one? */ int node_est = n.GetCostEstimate(); diff --git a/src/pathfinder/yapf/yapf_common.hpp b/src/pathfinder/yapf/yapf_common.hpp index 8ff69b3f6b..95adf37d7b 100644 --- a/src/pathfinder/yapf/yapf_common.hpp +++ b/src/pathfinder/yapf/yapf_common.hpp @@ -46,7 +46,7 @@ public: for (TrackdirBits tdb = m_orgTrackdirs; tdb != TRACKDIR_BIT_NONE; tdb = KillFirstBit(tdb)) { Trackdir td = (Trackdir)FindFirstBit2x64(tdb); Node &n1 = Yapf().CreateNewNode(); - n1.Set(NULL, m_orgTile, td, is_choice); + n1.Set(nullptr, m_orgTile, td, is_choice); Yapf().AddStartupNode(n1); } } @@ -92,12 +92,12 @@ public: { if (m_orgTile != INVALID_TILE && m_orgTd != INVALID_TRACKDIR) { Node &n1 = Yapf().CreateNewNode(); - n1.Set(NULL, m_orgTile, m_orgTd, false); + n1.Set(nullptr, m_orgTile, m_orgTd, false); Yapf().AddStartupNode(n1); } if (m_revTile != INVALID_TILE && m_revTd != INVALID_TRACKDIR) { Node &n2 = Yapf().CreateNewNode(); - n2.Set(NULL, m_revTile, m_revTd, false); + n2.Set(nullptr, m_revTile, m_revTd, false); n2.m_cost = m_reverse_penalty; Yapf().AddStartupNode(n2); } diff --git a/src/pathfinder/yapf/yapf_costcache.hpp b/src/pathfinder/yapf/yapf_costcache.hpp index f16d4054c6..2cdbf06c0b 100644 --- a/src/pathfinder/yapf/yapf_costcache.hpp +++ b/src/pathfinder/yapf/yapf_costcache.hpp @@ -143,7 +143,7 @@ struct CSegmentCostCacheT : public CSegmentCostCacheBase { inline Tsegment& Get(Key &key, bool *found) { Tsegment *item = m_map.Find(key); - if (item == NULL) { + if (item == nullptr) { *found = false; item = new (m_heap.Append()) Tsegment(key); m_map.Push(*item); diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 022b9a1678..d7f9a519ec 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -47,14 +47,6 @@ protected: this->tile_type = GetTileType(tile); this->rail_type = GetTileRailType(tile); } - - TILE(const TILE &src) - { - tile = src.tile; - td = src.td; - tile_type = src.tile_type; - rail_type = src.rail_type; - } }; protected: @@ -251,7 +243,7 @@ public: { int cost = 0; const Train *v = Yapf().GetVehicle(); - assert(v != NULL); + assert(v != nullptr); assert(v->type == VEH_TRAIN); assert(v->gcache.cached_total_length != 0); int missing_platform_length = CeilDiv(v->gcache.cached_total_length, TILE_SIZE) - platform_length; @@ -285,7 +277,7 @@ public: CPerfStart perf_cost(Yapf().m_perf_cost); /* Does the node have some parent node? */ - bool has_parent = (n.m_parent != NULL); + bool has_parent = (n.m_parent != nullptr); /* Do we already have a cached segment? */ CachedData &segment = *n.m_segment; @@ -496,7 +488,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th if (!tf_local.Follow(cur.tile, cur.td)) { assert(tf_local.m_err != TrackFollower::EC_NONE); /* Can't move to the next tile (EOL?). */ - if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) { + if (tf_local.m_err == TrackFollower::EC_RAIL_ROAD_TYPE) { end_segment_reason |= ESRB_RAIL_TYPE; } else { end_segment_reason |= ESRB_DEAD_END; @@ -606,7 +598,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* Station platform-length penalty. */ if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) { const BaseStation *st = BaseStation::GetByTile(n.GetLastTile()); - assert(st != NULL); + assert(st != nullptr); uint platform_length = st->GetPlatformLength(n.GetLastTile(), ReverseDiagDir(TrackdirToExitdir(n.GetLastTrackdir()))); /* Reduce the extra cost caused by passing-station penalty (each station receives it in the segment cost). */ extra_cost -= Yapf().PfGetSettings().rail_station_penalty * platform_length; @@ -624,7 +616,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th inline bool CanUseGlobalCache(Node &n) const { return !m_disable_cache - && (n.m_parent != NULL) + && (n.m_parent != nullptr) && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size()); } diff --git a/src/pathfinder/yapf/yapf_node.hpp b/src/pathfinder/yapf/yapf_node.hpp index b3021096b3..136ce53bde 100644 --- a/src/pathfinder/yapf/yapf_node.hpp +++ b/src/pathfinder/yapf/yapf_node.hpp @@ -67,14 +67,16 @@ struct CYapfNodeT { Node *m_parent; int m_cost; int m_estimate; + bool m_is_choice; inline void Set(Node *parent, TileIndex tile, Trackdir td, bool is_choice) { m_key.Set(tile, td); - m_hash_next = NULL; + m_hash_next = nullptr; m_parent = parent; m_cost = 0; m_estimate = 0; + m_is_choice = is_choice; } inline Node *GetHashNext() @@ -112,6 +114,11 @@ struct CYapfNodeT { return m_estimate; } + inline bool GetIsChoice() const + { + return m_is_choice; + } + inline bool operator<(const Node &other) const { return m_estimate < other.m_estimate; diff --git a/src/pathfinder/yapf/yapf_node_rail.hpp b/src/pathfinder/yapf/yapf_node_rail.hpp index 180c894392..2dfd6ae7d6 100644 --- a/src/pathfinder/yapf/yapf_node_rail.hpp +++ b/src/pathfinder/yapf/yapf_node_rail.hpp @@ -83,7 +83,7 @@ struct CYapfRailSegment , m_last_signal_tile(INVALID_TILE) , m_last_signal_td(INVALID_TRACKDIR) , m_end_segment_reason(ESRB_NONE) - , m_hash_next(NULL) + , m_hash_next(nullptr) {} inline const Key& GetKey() const @@ -142,8 +142,8 @@ struct CYapfRailNodeT inline void Set(CYapfRailNodeT *parent, TileIndex tile, Trackdir td, bool is_choice) { base::Set(parent, tile, td, is_choice); - m_segment = NULL; - if (parent == NULL) { + m_segment = nullptr; + if (parent == nullptr) { m_num_signals_passed = 0; flags_u.m_inherited_flags = 0; m_last_red_signal_type = SIGTYPE_NORMAL; @@ -169,19 +169,19 @@ struct CYapfRailNodeT inline TileIndex GetLastTile() const { - assert(m_segment != NULL); + assert(m_segment != nullptr); return m_segment->m_last_tile; } inline Trackdir GetLastTrackdir() const { - assert(m_segment != NULL); + assert(m_segment != nullptr); return m_segment->m_last_td; } inline void SetLastTileTrackdir(TileIndex tile, Trackdir td) { - assert(m_segment != NULL); + assert(m_segment != nullptr); m_segment->m_last_tile = tile; m_segment->m_last_td = td; } diff --git a/src/pathfinder/yapf/yapf_node_ship.hpp b/src/pathfinder/yapf/yapf_node_ship.hpp index df4254fd98..a8f8270714 100644 --- a/src/pathfinder/yapf/yapf_node_ship.hpp +++ b/src/pathfinder/yapf/yapf_node_ship.hpp @@ -14,7 +14,19 @@ /** Yapf Node for ships */ template -struct CYapfShipNodeT : CYapfNodeT > { }; +struct CYapfShipNodeT : CYapfNodeT > { + typedef CYapfNodeT > base; + + TileIndex m_segment_last_tile; + Trackdir m_segment_last_td; + + void Set(CYapfShipNodeT *parent, TileIndex tile, Trackdir td, bool is_choice) + { + base::Set(parent, tile, td, is_choice); + m_segment_last_tile = tile; + m_segment_last_td = td; + } +}; /* now define two major node types (that differ by key type) */ typedef CYapfShipNodeT CYapfShipNodeExitDir; diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index d3f8e8aeee..8d69b8aade 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -28,8 +28,8 @@ template void DumpState(Tpf &pf1, Tpf &pf2) pf2.DumpBase(dmp2); FILE *f1 = fopen("yapf1.txt", "wt"); FILE *f2 = fopen("yapf2.txt", "wt"); - assert(f1 != NULL); - assert(f2 != NULL); + assert(f1 != nullptr); + assert(f2 != nullptr); fwrite(dmp1.m_out.Data(), 1, dmp1.m_out.Size(), f1); fwrite(dmp2.m_out.Data(), 1, dmp2.m_out.Size(), f2); fclose(f1); @@ -84,7 +84,7 @@ private: tile = TILE_ADD(tile, diff); } while (IsCompatibleTrainStationTile(tile, start) && tile != m_origin_tile); - TriggerStationRandomisation(NULL, start, SRT_PATH_RESERVATION); + TriggerStationRandomisation(nullptr, start, SRT_PATH_RESERVATION); return true; } @@ -138,7 +138,7 @@ public: /** Check the node for a possible reservation target. */ inline void FindSafePositionOnNode(Node *node) { - assert(node->m_parent != NULL); + assert(node->m_parent != nullptr); /* We will never pass more than two signals, no need to check for a safe tile. */ if (node->m_parent->m_num_signals_passed >= 2) return; @@ -154,7 +154,7 @@ public: m_res_fail_tile = INVALID_TILE; m_origin_tile = origin; - if (target != NULL) { + if (target != nullptr) { target->tile = m_res_dest; target->trackdir = m_res_dest_td; target->okay = false; @@ -163,7 +163,7 @@ public: /* Don't bother if the target is reserved. */ if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td)) return false; - for (Node *node = m_res_node; node->m_parent != NULL; node = node->m_parent) { + for (Node *node = m_res_node; node->m_parent != nullptr; node = node->m_parent) { node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack::ReserveSingleTrack); if (m_res_fail_tile != INVALID_TILE) { /* Reservation failed, undo. */ @@ -173,13 +173,13 @@ public: /* If this is the node that failed, stop at the failed tile. */ m_res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE; fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack::UnreserveSingleTrack); - } while (fail_node != node && (fail_node = fail_node->m_parent) != NULL); + } while (fail_node != node && (fail_node = fail_node->m_parent) != nullptr); return false; } } - if (target != NULL) target->okay = true; + if (target != nullptr) target->okay = true; if (Yapf().CanUseGlobalCache(*m_res_node)) { YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); @@ -270,7 +270,7 @@ public: /* walk through the path back to the origin */ Node *pNode = n; - while (pNode->m_parent != NULL) { + while (pNode->m_parent != nullptr) { pNode = pNode->m_parent; } @@ -351,15 +351,15 @@ public: this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir()); /* Walk through the path back to the origin. */ - Node *pPrev = NULL; - while (pNode->m_parent != NULL) { + Node *pPrev = nullptr; + while (pNode->m_parent != nullptr) { pPrev = pNode; pNode = pNode->m_parent; this->FindSafePositionOnNode(pPrev); } - return dont_reserve || this->TryReservePath(NULL, pNode->GetLastTile()); + return dont_reserve || this->TryReservePath(nullptr, pNode->GetLastTile()); } }; @@ -408,7 +408,7 @@ public: if (_debug_desync_level < 2) { result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target); } else { - result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, NULL); + result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, nullptr); Tpf pf2; pf2.DisableCache(true); Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target); @@ -423,7 +423,7 @@ public: inline Trackdir ChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target) { - if (target != NULL) target->tile = INVALID_TILE; + if (target != nullptr) target->tile = INVALID_TILE; /* set origin and destination nodes */ PBSTileInfo origin = FollowTrainReservation(v); @@ -436,14 +436,14 @@ public: /* if path not found - return INVALID_TRACKDIR */ Trackdir next_trackdir = INVALID_TRACKDIR; Node *pNode = Yapf().GetBestNode(); - if (pNode != NULL) { + if (pNode != nullptr) { /* reserve till end of path */ this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir()); /* path was found or at least suggested * walk through the path back to the origin */ - Node *pPrev = NULL; - while (pNode->m_parent != NULL) { + Node *pPrev = nullptr; + while (pNode->m_parent != nullptr) { pPrev = pNode; pNode = pNode->m_parent; @@ -494,7 +494,7 @@ public: /* path was found * walk through the path back to the origin */ Node *pNode = Yapf().GetBestNode(); - while (pNode->m_parent != NULL) { + while (pNode->m_parent != nullptr) { pNode = pNode->m_parent; } diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp index 0240eb9366..3935ba18d3 100644 --- a/src/pathfinder/yapf/yapf_road.cpp +++ b/src/pathfinder/yapf/yapf_road.cpp @@ -118,7 +118,7 @@ public: /* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */ TileIndex tile = n.m_key.m_tile; Trackdir trackdir = n.m_key.m_td; - int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0; + int parent_cost = (n.m_parent != nullptr) ? n.m_parent->m_cost : 0; for (;;) { /* base tile cost depending on distance between edges */ @@ -249,7 +249,7 @@ public: } else { m_dest_station = INVALID_STATION; m_destTile = v->dest_tile; - m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes)); + m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))); } } @@ -348,13 +348,13 @@ public: return 'r'; } - static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found) + static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found, RoadVehPathCache &path_cache) { Tpf pf; - return pf.ChooseRoadTrack(v, tile, enterdir, path_found); + return pf.ChooseRoadTrack(v, tile, enterdir, path_found, path_cache); } - inline Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found) + inline Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found, RoadVehPathCache &path_cache) { /* Handle special case - when next tile is destination tile. * However, when going to a station the (initial) destination @@ -367,7 +367,7 @@ public: /* our source tile will be the next vehicle tile (should be the given one) */ TileIndex src_tile = tile; /* get available trackdirs on the start tile */ - TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)); + TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))); /* select reachable trackdirs only */ src_trackdirs &= DiagdirReachesTrackdirs(enterdir); @@ -381,16 +381,29 @@ public: /* if path not found - return INVALID_TRACKDIR */ Trackdir next_trackdir = INVALID_TRACKDIR; Node *pNode = Yapf().GetBestNode(); - if (pNode != NULL) { + if (pNode != nullptr) { + uint steps = 0; + for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++; + /* path was found or at least suggested * walk through the path back to its origin */ - while (pNode->m_parent != NULL) { + while (pNode->m_parent != nullptr) { + steps--; + if (pNode->GetIsChoice() && steps < YAPF_ROADVEH_PATH_CACHE_SEGMENTS) { + path_cache.td.push_front(pNode->GetTrackdir()); + path_cache.tile.push_front(pNode->GetTile()); + } pNode = pNode->m_parent; } /* return trackdir from the best origin node (one of start nodes) */ Node &best_next_node = *pNode; assert(best_next_node.GetTile() == tile); next_trackdir = best_next_node.GetTrackdir(); + /* remove last element for the special case when tile == dest_tile */ + if (path_found && !path_cache.empty() && tile == v->dest_tile) { + path_cache.td.pop_back(); + path_cache.tile.pop_back(); + } } return next_trackdir; } @@ -421,7 +434,7 @@ public: if (!Yapf().FindPath(v)) return dist; Node *pNode = Yapf().GetBestNode(); - if (pNode != NULL) { + if (pNode != nullptr) { /* path was found * get the path cost estimate */ dist = pNode->GetCostEstimate(); @@ -436,7 +449,7 @@ public: /* set origin (tile, trackdir) */ TileIndex src_tile = v->tile; Trackdir src_td = v->GetVehicleTrackdir(); - if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)), src_td)) { + if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, this->IsTram() ? RTT_TRAM : RTT_ROAD)), src_td)) { /* sometimes the roadveh is not on the road (it resides on non-existing track) * how should we handle that situation? */ return false; @@ -497,18 +510,18 @@ struct CYapfRoadAnyDepot1 : CYapfT > {}; -Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found) +Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found, RoadVehPathCache &path_cache) { /* default is YAPF type 2 */ - typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection, bool &path_found); + typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection, bool &path_found, RoadVehPathCache &path_cache); PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack; // default: ExitDir, allow 90-deg /* check if non-default YAPF type should be used */ if (_settings_game.pf.yapf.disable_node_optimization) { - pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack; // Trackdir, allow 90-deg + pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack; // Trackdir } - Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found); + Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found, path_cache); return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs); } @@ -516,7 +529,7 @@ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_dist { TileIndex tile = v->tile; Trackdir trackdir = v->GetVehicleTrackdir(); - if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)), trackdir)) { + if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype))), trackdir)) { return FindDepotData(); } @@ -526,7 +539,7 @@ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_dist /* check if non-default YAPF type should be used */ if (_settings_game.pf.yapf.disable_node_optimization) { - pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir, allow 90-deg + pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir } return pfnFindNearestDepot(v, tile, trackdir, max_distance); diff --git a/src/pathfinder/yapf/yapf_ship.cpp b/src/pathfinder/yapf/yapf_ship.cpp index c6e484feaa..731ae2f845 100644 --- a/src/pathfinder/yapf/yapf_ship.cpp +++ b/src/pathfinder/yapf/yapf_ship.cpp @@ -11,12 +11,96 @@ #include "../../stdafx.h" #include "../../ship.h" +#include "../../industry.h" +#include "../../vehicle_func.h" #include "yapf.hpp" #include "yapf_node_ship.hpp" #include "../../safeguards.h" +template +class CYapfDestinationTileWaterT +{ +public: + typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) + typedef typename Types::TrackFollower TrackFollower; + typedef typename Types::NodeList::Titem Node; ///< this will be our node type + typedef typename Node::Key Key; ///< key to hash tables + +protected: + TileIndex m_destTile; + TrackdirBits m_destTrackdirs; + StationID m_destStation; + +public: + void SetDestination(const Ship *v) + { + if (v->current_order.IsType(OT_GOTO_STATION)) { + m_destStation = v->current_order.GetDestination(); + m_destTile = CalcClosestStationTile(m_destStation, v->tile, STATION_DOCK); + m_destTrackdirs = INVALID_TRACKDIR_BIT; + } else { + m_destStation = INVALID_STATION; + m_destTile = v->dest_tile; + m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0)); + } + } + +protected: + /** to access inherited path finder */ + inline Tpf& Yapf() + { + return *static_cast(this); + } + +public: + /** Called by YAPF to detect if node ends in the desired destination */ + inline bool PfDetectDestination(Node& n) + { + return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td); + } + + inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir) + { + if (m_destStation != INVALID_STATION) { + return IsDockingTile(tile) && IsShipDestinationTile(tile, m_destStation); + } + + return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE); + } + + /** + * Called by YAPF to calculate cost estimate. Calculates distance to the destination + * adds it to the actual cost from origin and stores the sum to the Node::m_estimate + */ + inline bool PfCalcEstimate(Node& n) + { + static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0}; + static const int dg_dir_to_y_offs[] = {0, 1, 0, -1}; + if (PfDetectDestination(n)) { + n.m_estimate = n.m_cost; + return true; + } + + TileIndex tile = n.m_segment_last_tile; + DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td); + int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir]; + int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir]; + int x2 = 2 * TileX(m_destTile); + int y2 = 2 * TileY(m_destTile); + int dx = abs(x1 - x2); + int dy = abs(y1 - y2); + int dmin = min(dx, dy); + int dxy = abs(dx - dy); + int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2); + n.m_estimate = n.m_cost + d; + assert(n.m_estimate >= n.m_parent->m_estimate); + return true; + } +}; + + /** Node Follower module of YAPF for ships */ template class CYapfFollowShipT @@ -75,31 +159,32 @@ public: /* convert origin trackdir to TrackdirBits */ TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir); - /* get available trackdirs on the destination tile */ - TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0)); /* create pathfinder instance */ Tpf pf; /* set origin and destination nodes */ pf.SetOrigin(src_tile, trackdirs); - pf.SetDestination(v->dest_tile, dest_trackdirs); + pf.SetDestination(v); /* find best path */ path_found = pf.FindPath(v); Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found" Node *pNode = pf.GetBestNode(); - if (pNode != NULL) { + if (pNode != nullptr) { uint steps = 0; - for (Node *n = pNode; n->m_parent != NULL; n = n->m_parent) steps++; + for (Node *n = pNode; n->m_parent != nullptr; n = n->m_parent) steps++; + uint skip = 0; + if (path_found) skip = YAPF_SHIP_PATH_CACHE_LENGTH / 2; /* walk through the path back to the origin */ - Node *pPrevNode = NULL; - while (pNode->m_parent != NULL) { - if (steps > 1 && --steps < YAPF_SHIP_PATH_CACHE_LENGTH) { - TrackdirByte td; - td = pNode->GetTrackdir(); - path_cache.push_front(td); + Node *pPrevNode = nullptr; + while (pNode->m_parent != nullptr) { + steps--; + /* Skip tiles at end of path near destination. */ + if (skip > 0) skip--; + if (skip == 0 && steps > 0 && steps < YAPF_SHIP_PATH_CACHE_LENGTH) { + path_cache.push_front(pNode->GetTrackdir()); } pPrevNode = pNode; pNode = pNode->m_parent; @@ -125,23 +210,20 @@ public: */ static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2) { - /* get available trackdirs on the destination tile */ - TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0)); - /* create pathfinder instance */ Tpf pf; /* set origin and destination nodes */ pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2)); - pf.SetDestination(v->dest_tile, dest_trackdirs); + pf.SetDestination(v); /* find best path */ if (!pf.FindPath(v)) return false; Node *pNode = pf.GetBestNode(); - if (pNode == NULL) return false; + if (pNode == nullptr) return false; /* path was found * walk through the path back to the origin */ - while (pNode->m_parent != NULL) { + while (pNode->m_parent != nullptr) { pNode = pNode->m_parent; } @@ -169,6 +251,30 @@ protected: } public: + inline int CurveCost(Trackdir td1, Trackdir td2) + { + assert(IsValidTrackdir(td1)); + assert(IsValidTrackdir(td2)); + + if (HasTrackdir(TrackdirCrossesTrackdirs(td1), td2)) { + /* 90-deg curve penalty */ + return Yapf().PfGetSettings().ship_curve90_penalty; + } else if (td2 != NextTrackdir(td1)) { + /* 45-deg curve penalty */ + return Yapf().PfGetSettings().ship_curve45_penalty; + } + return 0; + } + + static Vehicle *CountShipProc(Vehicle *v, void *data) + { + uint *count = (uint *)data; + /* Ignore other vehicles (aircraft) and ships inside depot. */ + if (v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0) (*count)++; + + return nullptr; + } + /** * Called by YAPF to calculate the cost from the origin to the given node. * Calculates only the cost of given node, adds it to the parent node cost @@ -179,9 +285,13 @@ public: /* base tile cost depending on distance */ int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH; /* additional penalty for curves */ - if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) { - /* new trackdir does not match the next one when going straight */ - c += YAPF_TILE_LENGTH; + c += CurveCost(n.m_parent->GetTrackdir(), n.GetTrackdir()); + + if (IsDockingTile(n.GetTile())) { + /* Check docking tile for occupancy */ + uint count = 1; + HasVehicleOnPos(n.GetTile(), &count, &CountShipProc); + c += count * 3 * YAPF_TILE_LENGTH; } /* Skipped tile cost for aqueducts. */ @@ -219,30 +329,36 @@ struct CYapfShip_TypesT typedef CYapfBaseT PfBase; // base pathfinder class typedef CYapfFollowShipT PfFollow; // node follower typedef CYapfOriginTileT PfOrigin; // origin provider - typedef CYapfDestinationTileT PfDestination; // destination/distance provider + typedef CYapfDestinationTileWaterT PfDestination; // destination/distance provider typedef CYapfSegmentCostCacheNoneT PfCache; // segment cost cache provider typedef CYapfCostShipT PfCost; // cost provider }; -/* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */ +/* YAPF type 1 - uses TileIndex/Trackdir as Node key */ struct CYapfShip1 : CYapfT > {}; -/* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */ +/* YAPF type 2 - uses TileIndex/DiagDirection as Node key */ struct CYapfShip2 : CYapfT > {}; -/* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */ -struct CYapfShip3 : CYapfT > {}; + +static inline bool RequireTrackdirKey() +{ + /* If the two curve penalties are not equal, then it is not possible to use the + * ExitDir keyed node list, as it there will be key overlap. Using Trackdir keyed + * nodes means potentially more paths are tested, which would be wasteful if it's + * not necessary. + */ + return _settings_game.pf.yapf.ship_curve45_penalty != _settings_game.pf.yapf.ship_curve90_penalty; +} /** Ship controller helper - path finder invoker */ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, ShipPathCache &path_cache) { /* default is YAPF type 2 */ typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits, bool &path_found, ShipPathCache &path_cache); - PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg + PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir /* check if non-default YAPF type needed */ - if (_settings_game.pf.forbid_90_deg) { - pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg - } else if (_settings_game.pf.yapf.disable_node_optimization) { - pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg + if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) { + pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir } Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found, path_cache); @@ -256,13 +372,11 @@ bool YapfShipCheckReverse(const Ship *v) TileIndex tile = v->tile; typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir); - PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir, allow 90-deg + PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir /* check if non-default YAPF type needed */ - if (_settings_game.pf.forbid_90_deg) { - pfnCheckReverseShip = &CYapfShip3::CheckShipReverse; // Trackdir, forbid 90-deg - } else if (_settings_game.pf.yapf.disable_node_optimization) { - pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir, allow 90-deg + if (_settings_game.pf.yapf.disable_node_optimization || RequireTrackdirKey()) { + pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir } bool reverse = pfnCheckReverseShip(v, tile, td, td_rev); diff --git a/src/pbs.cpp b/src/pbs.cpp index 6bb35a6964..90ac3e70e1 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -116,7 +116,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations) case MP_STATION: if (HasStationRail(tile) && !HasStationReservation(tile)) { SetRailStationReservation(tile, true); - if (trigger_stations && IsRailStation(tile)) TriggerStationRandomisation(NULL, tile, SRT_PATH_RESERVATION); + if (trigger_stations && IsRailStation(tile)) TriggerStationRandomisation(nullptr, tile, SRT_PATH_RESERVATION); MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track return true; } @@ -258,8 +258,8 @@ struct FindTrainOnTrackInfo { PBSTileInfo res; ///< Information about the track. Train *best; ///< The currently "best" vehicle we have found. - /** Init the best location to NULL always! */ - FindTrainOnTrackInfo() : best(NULL) {} + /** Init the best location to nullptr always! */ + FindTrainOnTrackInfo() : best(nullptr) {} }; /** Callback for Has/FindVehicleOnPos to find a train on a specific track. */ @@ -267,18 +267,18 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) { FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data; - if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL; + if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr; Train *t = Train::From(v); if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) { t = t->First(); /* ALWAYS return the lowest ID (anti-desync!) */ - if (info->best == NULL || t->index < info->best->index) info->best = t; + if (info->best == nullptr || t->index < info->best->index) info->best = t; return t; } - return NULL; + return nullptr; } /** @@ -300,24 +300,24 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res) FindTrainOnTrackInfo ftoti; ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir); ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg); - if (train_on_res != NULL) { + if (train_on_res != nullptr) { FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); - if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); - if (*train_on_res == NULL && IsRailStationTile(ftoti.res.tile)) { + if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); + if (*train_on_res == nullptr && IsRailStationTile(ftoti.res.tile)) { /* The target tile is a rail station. The track follower * has stopped on the last platform tile where we haven't * found a train. Also check all previous platform tiles * for a possible train. */ TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); - for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == NULL && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { + for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == nullptr && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); - if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); + if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); } } - if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { + if (*train_on_res == nullptr && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { /* The target tile is a bridge/tunnel, also check the other end tile. */ FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); - if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); + if (ftoti.best != nullptr) *train_on_res = ftoti.best->First(); } } return ftoti.res; @@ -328,7 +328,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res) * * @param tile A tile on the path. * @param track A reserved track on the tile. - * @return The vehicle holding the reservation or NULL if the path is stray. + * @return The vehicle holding the reservation or nullptr if the path is stray. */ Train *GetTrainForReservation(TileIndex tile, Track track) { @@ -349,25 +349,25 @@ Train *GetTrainForReservation(TileIndex tile, Track track) ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); - if (ftoti.best != NULL) return ftoti.best; + if (ftoti.best != nullptr) return ftoti.best; /* Special case for stations: check the whole platform for a vehicle. */ if (IsRailStationTile(ftoti.res.tile)) { TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); - if (ftoti.best != NULL) return ftoti.best; + if (ftoti.best != nullptr) return ftoti.best; } } /* Special case for bridges/tunnels: check the other end as well. */ if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); - if (ftoti.best != NULL) return ftoti.best; + if (ftoti.best != nullptr) return ftoti.best; } } - return NULL; + return nullptr; } /** @@ -400,7 +400,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo /* Check for reachable tracks. */ ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir); - if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); + if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile), forbid_90deg)) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end; if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { @@ -445,7 +445,7 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo /* Check for reachable tracks. */ ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir); - if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); + if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile), forbid_90deg)) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits)); } diff --git a/src/pbs.h b/src/pbs.h index a02d4d06e1..96f9184b2b 100644 --- a/src/pbs.h +++ b/src/pbs.h @@ -44,7 +44,7 @@ struct PBSTileInfo { PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {} }; -PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res = NULL); +PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res = nullptr); bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false); bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false); diff --git a/src/progress.cpp b/src/progress.cpp index b498be109b..923f1ef83f 100644 --- a/src/progress.cpp +++ b/src/progress.cpp @@ -10,17 +10,19 @@ /** @file progress.cpp Functions for modal progress windows. */ #include "stdafx.h" -#include "thread/thread.h" +#include "progress.h" #include "safeguards.h" /** Are we in a modal progress or not? */ bool _in_modal_progress = false; bool _first_in_modal_loop = false; +/** Threading usable for modal progress? */ +bool _use_threaded_modal_progress = true; /** Rights for the performing work. */ -ThreadMutex *_modal_progress_work_mutex = ThreadMutex::New(); +std::mutex _modal_progress_work_mutex; /** Rights for the painting. */ -ThreadMutex *_modal_progress_paint_mutex = ThreadMutex::New(); +std::mutex _modal_progress_paint_mutex; /** * Set the modal progress state. diff --git a/src/progress.h b/src/progress.h index eec369b23c..2a9d73b038 100644 --- a/src/progress.h +++ b/src/progress.h @@ -12,7 +12,7 @@ #ifndef PROGRESS_H #define PROGRESS_H -#include "thread/thread.h" +#include static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws @@ -26,10 +26,20 @@ static inline bool HasModalProgress() return _in_modal_progress; } +/** + * Check if we can use a thread for modal progress. + * @return Threading usable? + */ +static inline bool UseThreadedModelProgress() +{ + extern bool _use_threaded_modal_progress; + return _use_threaded_modal_progress; +} + bool IsFirstModalProgressLoop(); void SetModalProgress(bool state); -extern class ThreadMutex *_modal_progress_work_mutex; -extern class ThreadMutex *_modal_progress_paint_mutex; +extern std::mutex _modal_progress_work_mutex; +extern std::mutex _modal_progress_paint_mutex; #endif /* PROGRESS_H */ diff --git a/src/querystring_gui.h b/src/querystring_gui.h index a1f3896dd1..6764a6c91a 100644 --- a/src/querystring_gui.h +++ b/src/querystring_gui.h @@ -37,7 +37,7 @@ struct QueryString { * @param size Maximum size in bytes. * @param chars Maximum size in chars. */ - QueryString(uint16 size, uint16 chars = UINT16_MAX) : ok_button(ACTION_NOTHING), cancel_button(ACTION_DESELECT), text(size, chars), orig(NULL) + QueryString(uint16 size, uint16 chars = UINT16_MAX) : ok_button(ACTION_NOTHING), cancel_button(ACTION_DESELECT), text(size, chars), orig(nullptr) { } @@ -79,11 +79,11 @@ public: /** * Get the currently marked text. * @param[out] length Length of the marked text. - * @return Begining of the marked area or NULL if no text is marked. + * @return Beginning of the marked area or nullptr if no text is marked. */ const char *GetMarkedText(size_t *length) const { - if (this->text.markend == 0) return NULL; + if (this->text.markend == 0) return nullptr; *length = this->text.markend - this->text.markpos; return this->text.buf + this->text.markpos; diff --git a/src/rail.cpp b/src/rail.cpp index 8bd7aa5181..f2870c1eb9 100644 --- a/src/rail.cpp +++ b/src/rail.cpp @@ -262,13 +262,14 @@ RailTypes AddDateIntroducedRailTypes(RailTypes current, Date date) /** * Get the rail types the given company can build. * @param company the company to get the rail types for. + * @param introduces If true, include rail types introduced by other rail types * @return the rail types. */ -RailTypes GetCompanyRailtypes(CompanyID company) +RailTypes GetCompanyRailtypes(CompanyID company, bool introduces) { RailTypes rts = RAILTYPES_NONE; - Engine *e; + const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { const EngineInfo *ei = &e->info; @@ -278,12 +279,46 @@ RailTypes GetCompanyRailtypes(CompanyID company) if (rvi->railveh_type != RAILVEH_WAGON) { assert(rvi->railtype < RAILTYPE_END); - rts |= GetRailTypeInfo(rvi->railtype)->introduces_railtypes; + if (introduces) { + rts |= GetRailTypeInfo(rvi->railtype)->introduces_railtypes; + } else { + SetBit(rts, rvi->railtype); + } } } } - return AddDateIntroducedRailTypes(rts, _date); + if (introduces) return AddDateIntroducedRailTypes(rts, _date); + return rts; +} + +/** + * Get list of rail types, regardless of company availability. + * @param introduces If true, include rail types introduced by other rail types + * @return the rail types. + */ +RailTypes GetRailTypes(bool introduces) +{ + RailTypes rts = RAILTYPES_NONE; + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { + const EngineInfo *ei = &e->info; + if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue; + + const RailVehicleInfo *rvi = &e->u.rail; + if (rvi->railveh_type != RAILVEH_WAGON) { + assert(rvi->railtype < RAILTYPE_END); + if (introduces) { + rts |= GetRailTypeInfo(rvi->railtype)->introduces_railtypes; + } else { + SetBit(rts, rvi->railtype); + } + } + } + + if (introduces) return AddDateIntroducedRailTypes(rts, MAX_DAY); + return rts; } /** @@ -304,7 +339,7 @@ RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels) /* Test if any rail type defines the label as an alternate. */ for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) { const RailtypeInfo *rti = GetRailTypeInfo(r); - if (rti->alternate_labels.Contains(label)) return r; + if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r; } } diff --git a/src/rail.h b/src/rail.h index 83d1d9b7af..8619bac6d9 100644 --- a/src/rail.h +++ b/src/rail.h @@ -21,17 +21,24 @@ #include "strings_type.h" #include "date_type.h" #include "signal_type.h" +#include "settings_type.h" /** Railtype flags. */ enum RailTypeFlags { RTF_CATENARY = 0, ///< Bit number for drawing a catenary. RTF_NO_LEVEL_CROSSING = 1, ///< Bit number for disallowing level crossings. RTF_HIDDEN = 2, ///< Bit number for hiding from selection. + RTF_NO_SPRITE_COMBINE = 3, ///< Bit number for using non-combined junctions. + RTF_ALLOW_90DEG = 4, ///< Bit number for always allowed 90 degree turns, regardless of setting. + RTF_DISALLOW_90DEG = 5, ///< Bit number for never allowed 90 degree turns, regardless of setting. RTFB_NONE = 0, ///< All flags cleared. RTFB_CATENARY = 1 << RTF_CATENARY, ///< Value for drawing a catenary. RTFB_NO_LEVEL_CROSSING = 1 << RTF_NO_LEVEL_CROSSING, ///< Value for disallowing level crossings. RTFB_HIDDEN = 1 << RTF_HIDDEN, ///< Value for hiding from selection. + RTFB_NO_SPRITE_COMBINE = 1 << RTF_NO_SPRITE_COMBINE, ///< Value for using non-combined junctions. + RTFB_ALLOW_90DEG = 1 << RTF_ALLOW_90DEG, ///< Value for always allowed 90 degree turns, regardless of setting. + RTFB_DISALLOW_90DEG = 1 << RTF_DISALLOW_90DEG, ///< Value for never allowed 90 degree turns, regardless of setting. }; DECLARE_ENUM_AS_BIT_SET(RailTypeFlags) @@ -51,6 +58,7 @@ enum RailTypeSpriteGroup { RTSG_FENCES, ///< Fence images RTSG_TUNNEL_PORTAL, ///< Tunnel portal overlay RTSG_SIGNALS, ///< Signal images + RTSG_GROUND_COMPLETE, ///< Complete ground images RTSG_END, }; @@ -110,7 +118,7 @@ enum RailFenceOffset { }; /** List of rail type labels. */ -typedef SmallVector RailTypeLabelList; +typedef std::vector RailTypeLabelList; /** * This struct contains all the info that is needed to draw and construct tracks. @@ -262,7 +270,7 @@ public: byte sorting_order; /** - * NewGRF providing the Action3 for the railtype. NULL if not available. + * NewGRF providing the Action3 for the railtype. nullptr if not available. */ const GRFFile *grffile[RTSG_END]; @@ -273,7 +281,7 @@ public: inline bool UsesOverlay() const { - return this->group[RTSG_GROUND] != NULL; + return this->group[RTSG_GROUND] != nullptr; } /** @@ -338,6 +346,26 @@ static inline bool RailNoLevelCrossings(RailType rt) return HasBit(GetRailTypeInfo(rt)->flags, RTF_NO_LEVEL_CROSSING); } +/** + * Test if 90 degree turns are disallowed between two railtypes. + * @param rt1 First railtype to test for. + * @param rt2 Second railtype to test for. + * @param def Default value to use if the rail type doesn't specify anything. + * @return True if 90 degree turns are disallowed between the two rail types. + */ +static inline bool Rail90DegTurnDisallowed(RailType rt1, RailType rt2, bool def = _settings_game.pf.forbid_90_deg) +{ + if (rt1 == INVALID_RAILTYPE || rt2 == INVALID_RAILTYPE) return def; + + const RailtypeInfo *rti1 = GetRailTypeInfo(rt1); + const RailtypeInfo *rti2 = GetRailTypeInfo(rt2); + + bool rt1_90deg = HasBit(rti1->flags, RTF_DISALLOW_90DEG) || (!HasBit(rti1->flags, RTF_ALLOW_90DEG) && def); + bool rt2_90deg = HasBit(rti2->flags, RTF_DISALLOW_90DEG) || (!HasBit(rti2->flags, RTF_ALLOW_90DEG) && def); + + return rt1_90deg || rt2_90deg; +} + /** * Returns the cost of building the specified railtype. * @param railtype The railtype being built. @@ -427,7 +455,8 @@ bool ValParamRailtype(const RailType rail); RailTypes AddDateIntroducedRailTypes(RailTypes current, Date date); RailType GetBestRailtype(const CompanyID company); -RailTypes GetCompanyRailtypes(const CompanyID c); +RailTypes GetCompanyRailtypes(CompanyID company, bool introduces = true); +RailTypes GetRailTypes(bool introduces); RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels = true); @@ -435,14 +464,13 @@ void ResetRailTypes(); void InitRailTypes(); RailType AllocateRailType(RailTypeLabel label); -extern RailType _sorted_railtypes[RAILTYPE_END]; -extern uint8 _sorted_railtypes_size; +extern std::vector _sorted_railtypes; extern RailTypes _railtypes_hidden_mask; /** * Loop header for iterating over railtypes, sorted by sortorder. * @param var Railtype. */ -#define FOR_ALL_SORTED_RAILTYPES(var) for (uint8 index = 0; index < _sorted_railtypes_size && (var = _sorted_railtypes[index], true) ; index++) +#define FOR_ALL_SORTED_RAILTYPES(var) for (uint8 index = 0; index < _sorted_railtypes.size() && (var = _sorted_railtypes[index], true) ; index++) #endif /* RAIL_H */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index f4fc163926..152d73a191 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -41,10 +41,10 @@ #include "safeguards.h" /** Helper type for lists/vectors of trains */ -typedef SmallVector TrainList; +typedef std::vector TrainList; RailtypeInfo _railtypes[RAILTYPE_END]; -RailType _sorted_railtypes[RAILTYPE_END]; +std::vector _sorted_railtypes; uint8 _sorted_railtypes_size; TileIndex _rail_track_endtile; ///< The end of a rail track; as hidden return from the rail build/remove command for GUI purposes. RailTypes _railtypes_hidden_mask; @@ -131,9 +131,9 @@ void ResolveRailTypeGUISprites(RailtypeInfo *rti) * @param second The railtype to compare. * @return True iff the first should be sorted before the second. */ -static int CDECL CompareRailTypes(const RailType *first, const RailType *second) +static bool CompareRailTypes(const RailType &first, const RailType &second) { - return GetRailTypeInfo(*first)->sorting_order - GetRailTypeInfo(*second)->sorting_order; + return GetRailTypeInfo(first)->sorting_order < GetRailTypeInfo(second)->sorting_order; } /** @@ -147,13 +147,13 @@ void InitRailTypes() if (HasBit(rti->flags, RTF_HIDDEN)) SetBit(_railtypes_hidden_mask, rt); } - _sorted_railtypes_size = 0; + _sorted_railtypes.clear(); for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { if (_railtypes[rt].label != 0 && !HasBit(_railtypes_hidden_mask, rt)) { - _sorted_railtypes[_sorted_railtypes_size++] = rt; + _sorted_railtypes.push_back(rt); } } - QSortT(_sorted_railtypes, _sorted_railtypes_size, CompareRailTypes); + std::sort(_sorted_railtypes.begin(), _sorted_railtypes.end(), CompareRailTypes); } /** @@ -168,7 +168,7 @@ RailType AllocateRailType(RailTypeLabel label) /* Set up new rail type */ *rti = _original_railtypes[RAILTYPE_RAIL]; rti->label = label; - rti->alternate_labels.Clear(); + rti->alternate_labels.clear(); /* Make us compatible with ourself. */ rti->powered_railtypes = (RailTypes)(1LL << rt); @@ -519,41 +519,48 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD); - if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); + if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_RAIL); - RoadTypes roadtypes = GetRoadTypes(tile); - RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD); - RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM); + RoadType roadtype_road = GetRoadTypeRoad(tile); + RoadType roadtype_tram = GetRoadTypeTram(tile); + + if (roadtype_road != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_road)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + if (roadtype_tram != INVALID_ROADTYPE && RoadNoLevelCrossing(roadtype_tram)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + + RoadBits road = GetRoadBits(tile, RTT_ROAD); + RoadBits tram = GetRoadBits(tile, RTT_TRAM); if ((track == TRACK_X && ((road | tram) & ROAD_X) == 0) || (track == TRACK_Y && ((road | tram) & ROAD_Y) == 0)) { - Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + Owner road_owner = GetRoadOwner(tile, RTT_ROAD); + Owner tram_owner = GetRoadOwner(tile, RTT_TRAM); /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ if (Company::IsValidID(tram_owner) && HasExactlyOneBit(tram)) { CommandCost ret = CheckOwnership(tram_owner); if (ret.Failed()) return ret; } - /* Crossings must always have a road... */ - uint num_new_road_pieces = 2 - CountBits(road); - if (road == ROAD_NONE) road_owner = _current_company; - roadtypes |= ROADTYPES_ROAD; - /* ...but tram is not required. */ - uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0; - cost.AddCost((num_new_road_pieces + num_new_tram_pieces) * _price[PR_BUILD_ROAD]); + uint num_new_road_pieces = (road != ROAD_NONE) ? 2 - CountBits(road) : 0; + if (num_new_road_pieces > 0) { + cost.AddCost(num_new_road_pieces * RoadBuildCost(roadtype_road)); + } + + uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0; + if (num_new_tram_pieces > 0) { + cost.AddCost(num_new_tram_pieces * RoadBuildCost(roadtype_tram)); + } if (flags & DC_EXEC) { - MakeRoadCrossing(tile, road_owner, tram_owner, _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile)); + MakeRoadCrossing(tile, road_owner, tram_owner, _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtype_road, roadtype_tram, GetTownIndex(tile)); UpdateLevelCrossing(tile, false); Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(_current_company); if (num_new_road_pieces > 0 && Company::IsValidID(road_owner)) { - Company::Get(road_owner)->infrastructure.road[ROADTYPE_ROAD] += num_new_road_pieces; + Company::Get(road_owner)->infrastructure.road[roadtype_road] += num_new_road_pieces; DirtyCompanyInfrastructureWindows(road_owner); } if (num_new_tram_pieces > 0 && Company::IsValidID(tram_owner)) { - Company::Get(tram_owner)->infrastructure.road[ROADTYPE_TRAM] += num_new_tram_pieces; + Company::Get(tram_owner)->infrastructure.road[roadtype_tram] += num_new_tram_pieces; DirtyCompanyInfrastructureWindows(tram_owner); } } @@ -571,6 +578,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u default: { /* Will there be flat water on the lower halftile? */ bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh); + bool docking = IsPossibleDockingTile(tile) && IsDockingTile(tile); CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile); if (ret.Failed()) return ret; @@ -587,7 +595,10 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (flags & DC_EXEC) { MakeRailNormal(tile, _current_company, trackbit, railtype); - if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER); + if (water_ground) { + SetRailGroundType(tile, RAIL_GROUND_WATER); + SetDockingTile(tile, docking); + } Company::Get(_current_company)->infrastructure.rail[railtype]++; DirtyCompanyInfrastructureWindows(_current_company); } @@ -632,7 +643,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, * so do not call GetTileOwner(tile) in any case here */ Owner owner = INVALID_OWNER; - Train *v = NULL; + Train *v = nullptr; switch (GetTileType(tile)) { case MP_ROAD: { @@ -653,12 +664,13 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, if (flags & DC_EXEC) { if (HasReservedTracks(tile, trackbit)) { v = GetTrainForReservation(tile, track); - if (v != NULL) FreeTrainTrackReservation(v); + if (v != nullptr) FreeTrainTrackReservation(v); } + owner = GetTileOwner(tile); Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(owner); - MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM)); + MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypeRoad(tile), GetRoadTypeTram(tile), GetTownIndex(tile), GetRoadOwner(tile, RTT_ROAD), GetRoadOwner(tile, RTT_TRAM)); DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile); } break; @@ -691,7 +703,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, if (flags & DC_EXEC) { if (HasReservedTracks(tile, trackbit)) { v = GetTrainForReservation(tile, track); - if (v != NULL) FreeTrainTrackReservation(v); + if (v != nullptr) FreeTrainTrackReservation(v); } owner = GetTileOwner(tile); @@ -711,7 +723,9 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, Slope tileh = GetTileSlope(tile); /* If there is flat water on the lower halftile, convert the tile to shore so the water remains */ if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) { + bool docking = IsDockingTile(tile); MakeShore(tile); + SetDockingTile(tile, docking); } else { DoClearSquare(tile); } @@ -746,7 +760,7 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, YapfNotifyTrackLayoutChange(tile, track); } - if (v != NULL) TryPathReserve(v, true); + if (v != nullptr) TryPathReserve(v, true); } _rail_track_endtile = tile; @@ -776,7 +790,7 @@ bool FloodHalftile(TileIndex t) TrackBits to_remove = lower_track & rail_bits; if (to_remove != 0) { - Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); + Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded(); cur_company.Restore(); if (!flooded) return flooded; // not yet floodable @@ -1110,13 +1124,13 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, } if (flags & DC_EXEC) { - Train *v = NULL; + Train *v = nullptr; /* The new/changed signal could block our path. As this can lead to * stale reservations, we clear the path reservation here and try * to redo it later on. */ if (HasReservedTracks(tile, TrackToTrackBits(track))) { v = GetTrainForReservation(tile, track); - if (v != NULL) FreeTrainTrackReservation(v); + if (v != nullptr) FreeTrainTrackReservation(v); } if (!HasSignals(tile)) { @@ -1192,7 +1206,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, MarkTileDirtyByTile(tile); AddTrackToSignalBuffer(tile, track, _current_company); YapfNotifyTrackLayoutChange(tile, track); - if (v != NULL) { + if (v != nullptr) { /* Extend the train's path if it's not stopped or loading, or not at a safe position. */ if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) || !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) { @@ -1482,13 +1496,13 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1 /* Do it? */ if (flags & DC_EXEC) { - Train *v = NULL; + Train *v = nullptr; if (HasReservedTracks(tile, TrackToTrackBits(track))) { v = GetTrainForReservation(tile, track); } else if (IsPbsSignal(GetSignalType(tile, track))) { /* PBS signal, might be the end of a path reservation. */ Trackdir td = TrackToTrackdir(track); - for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) { + for (int i = 0; v == nullptr && i < 2; i++, td = ReverseTrackdir(td)) { /* Only test the active signal side. */ if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue; TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td)); @@ -1512,7 +1526,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1 AddTrackToSignalBuffer(tile, track, GetTileOwner(tile)); YapfNotifyTrackLayoutChange(tile, track); - if (v != NULL) TryPathReserve(v, false); + if (v != nullptr) TryPathReserve(v, false); MarkTileDirtyByTile(tile); } @@ -1546,12 +1560,12 @@ CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, /** Update power of train under which is the railtype being converted */ static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data) { - if (v->type != VEH_TRAIN) return NULL; + if (v->type != VEH_TRAIN) return nullptr; TrainList *affected_trains = static_cast(data); - affected_trains->Include(Train::From(v)->First()); + include(*affected_trains, Train::From(v)->First()); - return NULL; + return nullptr; } /** @@ -1596,7 +1610,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 case MP_ROAD: if (!IsLevelCrossing(tile)) continue; if (RailNoLevelCrossings(totype)) { - error.MakeError(STR_ERROR_CROSSING_DISALLOWED); + error.MakeError(STR_ERROR_CROSSING_DISALLOWED_RAIL); continue; } break; @@ -1619,7 +1633,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 continue; } - SmallVector vehicles_affected; + std::vector vehicles_affected; /* Vehicle on the tile when not converting Rail <-> ElRail * Tunnels and bridges have special check later */ @@ -1636,10 +1650,10 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Track track; while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) { Train *v = GetTrainForReservation(tile, track); - if (v != NULL && !HasPowerOnRail(v->railtype, totype)) { + if (v != nullptr && !HasPowerOnRail(v->railtype, totype)) { /* No power on new rail type, reroute. */ FreeTrainTrackReservation(v); - *vehicles_affected.Append() = v; + vehicles_affected.push_back(v); } } @@ -1720,10 +1734,10 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile)); if (HasTunnelBridgeReservation(tile)) { Train *v = GetTrainForReservation(tile, track); - if (v != NULL && !HasPowerOnRail(v->railtype, totype)) { + if (v != nullptr && !HasPowerOnRail(v->railtype, totype)) { /* No power on new rail type, reroute. */ FreeTrainTrackReservation(v); - *vehicles_affected.Append() = v; + vehicles_affected.push_back(v); } } @@ -1767,15 +1781,15 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 break; } - for (uint i = 0; i < vehicles_affected.Length(); ++i) { + for (uint i = 0; i < vehicles_affected.size(); ++i) { TryPathReserve(vehicles_affected[i], true); } } if (flags & DC_EXEC) { /* Railtype changed, update trains as when entering different track */ - for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) { - (*v)->ConsistChanged(CCF_TRACK); + for (Train *v : affected_trains) { + v->ConsistChanged(CCF_TRACK); } } @@ -1797,11 +1811,11 @@ static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags) /* read variables before the depot is removed */ DiagDirection dir = GetRailDepotDirection(tile); Owner owner = GetTileOwner(tile); - Train *v = NULL; + Train *v = nullptr; if (HasDepotReservation(tile)) { v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir)); - if (v != NULL) FreeTrainTrackReservation(v); + if (v != nullptr) FreeTrainTrackReservation(v); } Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--; @@ -1811,7 +1825,7 @@ static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags) DoClearSquare(tile); AddSideToSignalBuffer(tile, dir, owner); YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir)); - if (v != NULL) TryPathReserve(v, true); + if (v != nullptr) TryPathReserve(v, true); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]); @@ -2084,7 +2098,7 @@ static const SubSprite _halftile_sub_sprite[4] = { static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s) { - DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0); + DrawGroundSprite(sprite, pal, nullptr, 0, (ti->tileh & s) ? -8 : 0); } static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti) @@ -2127,12 +2141,25 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn DrawGroundSprite(image, PAL_NONE); } + bool no_combine = ti->tileh == SLOPE_FLAT && HasBit(rti->flags, RTF_NO_SPRITE_COMBINE); SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); - SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND); + SpriteID ground = GetCustomRailSprite(rti, ti->tile, no_combine ? RTSG_GROUND_COMPLETE : RTSG_GROUND); TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE; if (track == TRACK_BIT_NONE) { /* Half-tile foundation, no track here? */ + } else if (no_combine) { + /* Use trackbits as direct index from ground sprite, subtract 1 + * because there is no sprite for no bits. */ + DrawGroundSprite(ground + track - 1, PAL_NONE); + + /* Draw reserved track bits */ + if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); + if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); + if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N); + if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S); + if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E); + if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W); } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) { DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE); if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + RTO_SLOPE_NW, PALETTE_CRASH); @@ -2265,7 +2292,7 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track) SpriteID image; PaletteID pal = PAL_NONE; - const SubSprite *sub = NULL; + const SubSprite *sub = nullptr; bool junction = false; /* Select the sprite to use. */ @@ -2292,23 +2319,30 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track) image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y; } else { /* track on flat ground */ - (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) || - (image++, track == TRACK_BIT_X) || - (image++, track == TRACK_BIT_UPPER) || - (image++, track == TRACK_BIT_LOWER) || - (image++, track == TRACK_BIT_RIGHT) || - (image++, track == TRACK_BIT_LEFT) || - (image++, track == TRACK_BIT_CROSS) || + switch (track) { + /* single track, select combined track + ground sprite*/ + case TRACK_BIT_Y: image = rti->base_sprites.track_y; break; + case TRACK_BIT_X: image = rti->base_sprites.track_y + 1; break; + case TRACK_BIT_UPPER: image = rti->base_sprites.track_y + 2; break; + case TRACK_BIT_LOWER: image = rti->base_sprites.track_y + 3; break; + case TRACK_BIT_RIGHT: image = rti->base_sprites.track_y + 4; break; + case TRACK_BIT_LEFT: image = rti->base_sprites.track_y + 5; break; + case TRACK_BIT_CROSS: image = rti->base_sprites.track_y + 6; break; - (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) || - (image++, track == TRACK_BIT_VERT) || + /* double diagonal track, select combined track + ground sprite*/ + case TRACK_BIT_HORZ: image = rti->base_sprites.track_ns; break; + case TRACK_BIT_VERT: image = rti->base_sprites.track_ns + 1; break; - (junction = true, false) || - (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) || - (image++, (track & TRACK_BIT_3WAY_SW) == 0) || - (image++, (track & TRACK_BIT_3WAY_NW) == 0) || - (image++, (track & TRACK_BIT_3WAY_SE) == 0) || - (image++, true); + /* junction, select only ground sprite, handle track sprite later */ + default: + junction = true; + if ((track & TRACK_BIT_3WAY_NE) == 0) { image = rti->base_sprites.ground; break; } + if ((track & TRACK_BIT_3WAY_SW) == 0) { image = rti->base_sprites.ground + 1; break; } + if ((track & TRACK_BIT_3WAY_NW) == 0) { image = rti->base_sprites.ground + 2; break; } + if ((track & TRACK_BIT_3WAY_SE) == 0) { image = rti->base_sprites.ground + 3; break; } + image = rti->base_sprites.ground + 4; + break; + } } switch (rgt) { @@ -2355,10 +2389,10 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track) DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH); } } - if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0); - if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0); - if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0); - if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0); + if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0); + if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0); + if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0); + if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, nullptr, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0); } if (IsValidCorner(halftile_corner)) { @@ -2378,7 +2412,7 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track) if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) { static const byte _corner_to_track_sprite[] = {3, 1, 2, 0}; - DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT); + DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, nullptr, 0, -(int)TILE_HEIGHT); } } } @@ -2454,9 +2488,8 @@ static void DrawTile_Track(TileInfo *ti) if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset(); } - /* adjust ground tile for desert - * don't adjust for snow, because snow in depots looks weird */ - if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) { + /* Adjust ground tile for desert and snow. */ + if (IsSnowRailGround(ti->tile)) { if (image != SPR_FLAT_GRASS_TILE) { image += rti->snow_offset; // tile with tracks } else { @@ -2958,7 +2991,7 @@ static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int if (fract_coord_leave == fract_coord) { /* Leave the depot. */ - if ((v = v->Next()) != NULL) { + if ((v = v->Next()) != nullptr) { v->vehstatus &= ~VS_HIDDEN; v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y); } @@ -2969,7 +3002,7 @@ static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int v->track = TRACK_BIT_DEPOT, v->vehstatus |= VS_HIDDEN; v->direction = ReverseDir(v->direction); - if (v->Next() == NULL) VehicleEnterDepot(v->First()); + if (v->Next() == nullptr) VehicleEnterDepot(v->First()); v->tile = tile; InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); @@ -3034,7 +3067,7 @@ static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old */ static Vehicle *EnsureNoShipProc(Vehicle *v, void *data) { - return v->type == VEH_SHIP ? v : NULL; + return v->type == VEH_SHIP ? v : nullptr; } static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) @@ -3047,7 +3080,7 @@ static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)); /* Allow clearing the water only if there is no ship */ - if (was_water && HasVehicleOnPos(tile, NULL, &EnsureNoShipProc)) return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY); + if (was_water && HasVehicleOnPos(tile, nullptr, &EnsureNoShipProc)) return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY); /* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */ CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits); @@ -3090,14 +3123,14 @@ extern const TileTypeProcs _tile_type_rail_procs = { DrawTile_Track, // draw_tile_proc GetSlopePixelZ_Track, // get_slope_z_proc ClearTile_Track, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_Track, // get_tile_desc_proc GetTileTrackStatus_Track, // get_tile_track_status_proc ClickTile_Track, // click_tile_proc - NULL, // animate_tile_proc + nullptr, // animate_tile_proc TileLoop_Track, // tile_loop_proc ChangeTileOwner_Track, // change_tile_owner_proc - NULL, // add_produced_cargo_proc + nullptr, // add_produced_cargo_proc VehicleEnter_Track, // vehicle_enter_tile_proc GetFoundation_Track, // get_foundation_proc TerraformTile_Track, // terraform_tile_proc diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index e585c4950c..4d9f6ab890 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -85,9 +85,9 @@ static void ShowSignalBuilder(Window *parent); */ static bool IsStationAvailable(const StationSpec *statspec) { - if (statspec == NULL || !HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) return true; + if (statspec == nullptr || !HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) return true; - uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE); + uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, nullptr, INVALID_TILE); if (cb_res == CALLBACK_FAILED) return true; return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res); @@ -248,7 +248,7 @@ static void GenericPlaceSignals(TileIndex tile) /* various bitstuffed elements for CmdBuildSingleSignal() */ uint32 p1 = track; - if (w != NULL) { + if (w != nullptr) { /* signal GUI is used */ SB(p1, 3, 1, _ctrl_pressed); SB(p1, 4, 1, _cur_signal_variant); @@ -264,7 +264,7 @@ static void GenericPlaceSignals(TileIndex tile) } DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | - CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), + CMD_MSG((w != nullptr && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), CcPlaySound_SPLAT_RAIL); } } @@ -426,7 +426,7 @@ static void HandleAutoSignalPlacement() const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); - if (w != NULL) { + if (w != nullptr) { /* signal GUI is used */ SB(p2, 3, 1, 0); SB(p2, 4, 1, _cur_signal_variant); @@ -537,6 +537,7 @@ struct BuildRailToolbarWindow : Window { ~BuildRailToolbarWindow() { + if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -545,7 +546,7 @@ struct BuildRailToolbarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -614,7 +615,7 @@ struct BuildRailToolbarWindow : Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_RAT_CAPTION) { const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); @@ -637,7 +638,7 @@ struct BuildRailToolbarWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget < WID_RAT_BUILD_NS) return; bool remove_on_ctrl = true; /* do not check ctrl for hotkeys */ @@ -778,7 +779,7 @@ struct BuildRailToolbarWindow : Window { if (_ctrl_pressed && remove_on_ctrl) RailToolbar_CtrlChanged(this); } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { // EventState es; MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection @@ -800,7 +801,7 @@ struct BuildRailToolbarWindow : Window { return Window::OnHotkey(hotkey); } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { DiagDirection ddir; switch (this->last_user_action) { @@ -869,15 +870,15 @@ struct BuildRailToolbarWindow : Window { } } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { /* no dragging if you have pressed the convert button */ - if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(WID_RAT_BUILD_SIGNALS)) return; + if (FindWindowById(WC_BUILD_SIGNAL, 0) != nullptr && _convert_signal_button && this->IsWidgetLowered(WID_RAT_BUILD_SIGNALS)) return; VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1) { switch (select_proc) { @@ -930,8 +931,10 @@ struct BuildRailToolbarWindow : Window { } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { + if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) SetViewportCatchmentStation(nullptr, true); + this->RaiseButtons(); this->DisableWidget(WID_RAT_REMOVE); this->SetWidgetDirty(WID_RAT_REMOVE); @@ -944,13 +947,13 @@ struct BuildRailToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } - virtual void OnPlacePresize(Point pt, TileIndex tile) + void OnPlacePresize(Point pt, TileIndex tile) override { DoCommand(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); } - virtual EventState OnCTRLStateChange() + EventState OnCTRLStateChange() override { /* do not toggle Remove button by Ctrl when placing station */ if (!this->IsWidgetLowered(WID_RAT_BUILD_STATION) && !this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED; @@ -970,7 +973,7 @@ static EventState RailToolbarGlobalHotkeys(int hotkey) if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_TRAIN)) return ES_NOT_HANDLED; extern RailType _last_built_railtype; Window *w = ShowBuildRailToolbar(_last_built_railtype); - if (w == NULL) return ES_NOT_HANDLED; + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -1059,12 +1062,12 @@ static WindowDesc _build_rail_desc( * If the terraform toolbar is linked to the toolbar, that window is also opened. * * @param railtype Rail type to open the window for - * @return newly opened rail toolbar, or NULL if the toolbar could not be opened. + * @return newly opened rail toolbar, or nullptr if the toolbar could not be opened. */ Window *ShowBuildRailToolbar(RailType railtype) { - if (!Company::IsValidID(_local_company)) return NULL; - if (!ValParamRailtype(railtype)) return NULL; + if (!Company::IsValidID(_local_company)) return nullptr; + if (!ValParamRailtype(railtype)) return nullptr; DeleteWindowByClass(WC_BUILD_TOOLBAR); _cur_railtype = railtype; @@ -1104,7 +1107,7 @@ private: */ void CheckSelectedSize(const StationSpec *statspec) { - if (statspec == NULL || _settings_client.gui.station_dragdrop) return; + if (statspec == nullptr || _settings_client.gui.station_dragdrop) return; /* If current number of tracks is not allowed, make it as big as possible */ if (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { @@ -1134,7 +1137,7 @@ public: BuildRailStationWindow(WindowDesc *desc, Window *parent, bool newstation) : PickerWindowBase(desc, parent) { this->coverage_height = 2 * FONT_HEIGHT_NORMAL + 3 * WD_PAR_VSEP_NORMAL; - this->vscroll = NULL; + this->vscroll = nullptr; _railstation.newstations = newstation; this->CreateNestedTree(); @@ -1167,7 +1170,7 @@ public: * type is 'selected'. */ _railstation.station_class = STAT_CLASS_DFLT; _railstation.station_type = 0; - this->vscroll2 = NULL; + this->vscroll2 = nullptr; } if (newstation) { _railstation.station_count = StationClass::Get(_railstation.station_class)->GetSpecCount(); @@ -1193,10 +1196,10 @@ public: DeleteWindowById(WC_SELECT_STATION, 0); } - virtual void OnPaint() + void OnPaint() override { bool newstations = _railstation.newstations; - const StationSpec *statspec = newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; + const StationSpec *statspec = newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : nullptr; if (_settings_client.gui.station_dragdrop) { SetTileSelectSize(1, 1); @@ -1215,7 +1218,7 @@ public: for (uint bits = 0; bits < 7; bits++) { bool disable = bits >= _settings_game.station.station_spread; - if (statspec == NULL) { + if (statspec == nullptr) { this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, disable); this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, disable); } else { @@ -1226,6 +1229,7 @@ public: this->DrawWidgets(); + if (this->IsShaded()) return; /* 'Accepts' and 'Supplies' texts. */ NWidgetBase *cov = this->GetWidget(WID_BRAS_COVERAGE_TEXTS); int top = cov->pos_y + WD_PAR_VSEP_NORMAL; @@ -1243,7 +1247,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BRAS_NEWST_LIST: { @@ -1274,7 +1278,7 @@ public: StationClass *stclass = StationClass::Get(statclass); for (uint16 j = 0; j < stclass->GetSpecCount(); j++) { const StationSpec *statspec = stclass->GetSpec(j); - SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); + SetDParam(0, (statspec != nullptr && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); d = maxdim(d, GetStringBoundingBox(str)); } } @@ -1300,7 +1304,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { DrawPixelInfo tmp_dpi; @@ -1374,22 +1378,22 @@ public: } } - virtual void OnResize() + void OnResize() override { - if (this->vscroll != NULL) { // New stations available. + if (this->vscroll != nullptr) { // New stations available. this->vscroll->SetCapacityFromWidget(this, WID_BRAS_NEWST_LIST); } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_BRAS_SHOW_NEWST_TYPE) { const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type); - SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); + SetDParam(0, (statspec != nullptr && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (GB(widget, 0, 16)) { case WID_BRAS_PLATFORM_DIR_X: @@ -1417,8 +1421,8 @@ public: _settings_client.gui.station_dragdrop = false; - const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { + const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : nullptr; + if (statspec != nullptr && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { /* The previously selected number of platforms in invalid */ for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_lengths, i)) { @@ -1452,8 +1456,8 @@ public: _settings_client.gui.station_dragdrop = false; - const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { + const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : nullptr; + if (statspec != nullptr && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { /* The previously selected number of tracks in invalid */ for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_platforms, i)) { @@ -1478,8 +1482,8 @@ public: this->ToggleWidgetLoweredState(WID_BRAS_PLATFORM_DRAG_N_DROP); /* get the first allowed length/number of platforms */ - const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; - if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { + const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : nullptr; + if (statspec != nullptr && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_lengths, i)) { this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); @@ -1488,7 +1492,7 @@ public: } } } - if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { + if (statspec != nullptr && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_platforms, i)) { this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); @@ -1565,7 +1569,7 @@ public: } } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { CheckRedrawStationCoverage(this); } @@ -1575,6 +1579,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_DEFSIZE), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), @@ -1718,7 +1723,7 @@ public: _convert_signal_button = false; } - virtual void OnInit() + void OnInit() override { /* Calculate maximum signal sprite size. */ this->sig_sprite_size.width = 0; @@ -1738,7 +1743,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget == WID_BS_DRAG_SIGNALS_DENSITY_LABEL) { /* Two digits for signals density. */ @@ -1749,7 +1754,7 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_BS_DRAG_SIGNALS_DENSITY_LABEL: @@ -1758,7 +1763,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { /* Extract signal from widget number. */ @@ -1770,7 +1775,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BS_SEMAPHORE_NORM: @@ -1793,7 +1798,7 @@ public: /* If 'remove' button of rail build toolbar is active, disable it. */ if (_remove_button_clicked) { Window *w = FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL); - if (w != NULL) ToggleRailButton_Remove(w); + if (w != nullptr) ToggleRailButton_Remove(w); } break; @@ -1827,7 +1832,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); @@ -1899,7 +1904,7 @@ struct BuildRailDepotWindow : public PickerWindowBase { this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BRAD_DEPOT_NE: @@ -1916,14 +1921,14 @@ struct BuildRailDepotWindow : public PickerWindowBase { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (!IsInsideMM(widget, WID_BRAD_DEPOT_NE, WID_BRAD_DEPOT_NW + 1)) return; DrawTrainDepotSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), widget - WID_BRAD_DEPOT_NE + DIAGDIR_NE, _cur_railtype); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BRAD_DEPOT_NE: @@ -1979,7 +1984,7 @@ static const NWidgetPart _nested_build_depot_widgets[] = { }; static WindowDesc _build_depot_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets) @@ -2004,7 +2009,7 @@ struct BuildRailWaypointWindow : PickerWindowBase { matrix->SetClicked(_cur_waypoint_type); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BRW_WAYPOINT_MATRIX: @@ -2023,7 +2028,7 @@ struct BuildRailWaypointWindow : PickerWindowBase { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (GB(widget, 0, 16)) { case WID_BRW_WAYPOINT: { @@ -2038,7 +2043,7 @@ struct BuildRailWaypointWindow : PickerWindowBase { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (GB(widget, 0, 16)) { case WID_BRW_WAYPOINT: { @@ -2107,7 +2112,7 @@ void ReinitGuiAfterToggleElrail(bool disable) if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) { _last_built_railtype = _cur_railtype = RAILTYPE_RAIL; BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); - if (w != NULL) w->ModifyRailType(_cur_railtype); + if (w != nullptr) w->ModifyRailType(_cur_railtype); } MarkWholeScreenDirty(); } @@ -2154,7 +2159,7 @@ static void SetDefaultRailGui() _last_built_railtype = _cur_railtype = rt; BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); - if (w != NULL) w->ModifyRailType(_cur_railtype); + if (w != nullptr) w->ModifyRailType(_cur_railtype); } /** @@ -2169,7 +2174,7 @@ bool ResetSignalVariant(int32 p) if (new_variant != _cur_signal_variant) { Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); - if (w != NULL) { + if (w != nullptr) { w->SetDirty(); w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); } @@ -2198,30 +2203,39 @@ void InitializeRailGUI() * @param all_option Whether to add an 'all types' item. * @return The populated and sorted #DropDownList. */ -DropDownList *GetRailTypeDropDownList(bool for_replacement, bool all_option) +DropDownList GetRailTypeDropDownList(bool for_replacement, bool all_option) { - RailTypes used_railtypes = RAILTYPES_NONE; - - /* 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; - - used_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes; - } - - /* Get the date introduced railtypes as well. */ - used_railtypes = AddDateIntroducedRailTypes(used_railtypes, MAX_DAY); + RailTypes used_railtypes; + RailTypes avail_railtypes; const Company *c = Company::Get(_local_company); - DropDownList *list = new DropDownList(); - if (all_option) { - DropDownListStringItem *item = new DropDownListStringItem(STR_REPLACE_ALL_RAILTYPE, INVALID_RAILTYPE, false); - *list->Append() = item; + /* Find the used railtypes. */ + if (for_replacement) { + avail_railtypes = GetCompanyRailtypes(c->index, false); + used_railtypes = GetRailTypes(false); + } else { + avail_railtypes = c->avail_railtypes; + used_railtypes = GetRailTypes(true); } + DropDownList list; + + if (all_option) { + list.emplace_back(new DropDownListStringItem(STR_REPLACE_ALL_RAILTYPE, INVALID_RAILTYPE, false)); + } + + Dimension d = { 0, 0 }; RailType rt; + /* Get largest icon size, to ensure text is aligned on each menu item. */ + if (!for_replacement) { + FOR_ALL_SORTED_RAILTYPES(rt) { + if (!HasBit(used_railtypes, rt)) continue; + const RailtypeInfo *rti = GetRailTypeInfo(rt); + d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_rail)); + } + } + FOR_ALL_SORTED_RAILTYPES(rt) { /* If it's not used ever, don't show it to the user. */ if (!HasBit(used_railtypes, rt)) continue; @@ -2229,10 +2243,23 @@ DropDownList *GetRailTypeDropDownList(bool for_replacement, bool all_option) const RailtypeInfo *rti = GetRailTypeInfo(rt); StringID str = for_replacement ? rti->strings.replace_text : (rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING); - DropDownListParamStringItem *item = new DropDownListParamStringItem(str, rt, !HasBit(c->avail_railtypes, rt)); + DropDownListParamStringItem *item; + if (for_replacement) { + item = new DropDownListParamStringItem(str, rt, !HasBit(avail_railtypes, rt)); + } else { + DropDownListIconItem *iconitem = new DropDownListIconItem(rti->gui_sprites.build_x_rail, PAL_NONE, str, rt, !HasBit(avail_railtypes, rt)); + iconitem->SetDimension(d); + item = iconitem; + } item->SetParam(0, rti->strings.menu_text); item->SetParam(1, rti->max_speed); - *list->Append() = item; + list.emplace_back(item); } + + if (list.size() == 0) { + /* Empty dropdowns are not allowed */ + list.emplace_back(new DropDownListStringItem(STR_NONE, INVALID_RAILTYPE, true)); + } + return list; } diff --git a/src/rail_gui.h b/src/rail_gui.h index e7a03b9120..0a5f240ab3 100644 --- a/src/rail_gui.h +++ b/src/rail_gui.h @@ -19,6 +19,6 @@ struct Window *ShowBuildRailToolbar(RailType railtype); void ReinitGuiAfterToggleElrail(bool disable); bool ResetSignalVariant(int32 = 0); void InitializeRailGUI(); -DropDownList *GetRailTypeDropDownList(bool for_replacement = false, bool all_option = false); +DropDownList GetRailTypeDropDownList(bool for_replacement = false, bool all_option = false); #endif /* RAIL_GUI_H */ diff --git a/src/rail_map.h b/src/rail_map.h index 74afe5ace5..0142559e78 100644 --- a/src/rail_map.h +++ b/src/rail_map.h @@ -17,6 +17,7 @@ #include "signal_func.h" #include "track_func.h" #include "tile_map.h" +#include "water_map.h" #include "signal_type.h" @@ -521,6 +522,7 @@ static inline void MakeRailNormal(TileIndex t, Owner o, TrackBits b, RailType r) { SetTileType(t, MP_RAILWAY); SetTileOwner(t, o); + SetDockingTile(t, false); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; @@ -535,6 +537,7 @@ static inline void MakeRailDepot(TileIndex t, Owner o, DepotID did, DiagDirectio { SetTileType(t, MP_RAILWAY); SetTileOwner(t, o); + SetDockingTile(t, false); _m[t].m2 = did; _m[t].m3 = 0; _m[t].m4 = 0; diff --git a/src/rail_type.h b/src/rail_type.h index 2bd602a37e..7e465866cf 100644 --- a/src/rail_type.h +++ b/src/rail_type.h @@ -26,7 +26,7 @@ static const RailTypeLabel RAILTYPE_MAGLEV_LABEL = 'MGLV'; * * This enumeration defines all 4 possible railtypes. */ -enum RailType { +enum RailType : byte { RAILTYPE_BEGIN = 0, ///< Used for iterations RAILTYPE_RAIL = 0, ///< Standard non-electric rails RAILTYPE_ELECTRIC = 1, ///< Electric rails @@ -44,7 +44,6 @@ enum RailType { DECLARE_POSTFIX_INCREMENT(RailType) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT RailTypeByte; /** * The different railtypes we support, but then a bitmask of them. diff --git a/src/rev.cpp b/src/rev.cpp index fc1554110e..16a1e7a018 100644 --- a/src/rev.cpp +++ b/src/rev.cpp @@ -37,7 +37,7 @@ bool IsReleasedVersion() * * shows a "M", if the binary is made from modified source code. */ -const char _openttd_revision[] = "1.9.3"; +const char _openttd_revision[] = "1.10.0-beta1"; /** * The text version of OpenTTD's build date. @@ -50,7 +50,7 @@ const char _openttd_build_date[] = __DATE__ " " __TIME__; /** * The git revision hash of this version. */ -const char _openttd_revision_hash[] = "f6643952ce53b1823c2273964466f785a907ec1a"; +const char _openttd_revision_hash[] = "9f50c754ffee52211e61d88e6d5fc296dfc585e0"; /** * Let us know if current build was modified. This detection @@ -82,11 +82,4 @@ const byte _openttd_revision_tagged = 1; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 9 << 24 | 3 << 20 | 1 << 19 | 28004; - -#ifdef __MORPHOS__ -/** - * Variable used by MorphOS to show the version. - */ -extern const char morphos_versions_tag[] = "$VER: OpenTTD 1.9.3 (16.09.19) OpenTTD Team [MorphOS, PowerPC]"; -#endif +const uint32 _openttd_newgrf_version = 1 << 28 | 10 << 24 | 0 << 20 | 0 << 19 | 28004; diff --git a/src/rev.cpp.in b/src/rev.cpp.in index fc1554110e..16a1e7a018 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -37,7 +37,7 @@ bool IsReleasedVersion() * * shows a "M", if the binary is made from modified source code. */ -const char _openttd_revision[] = "1.9.3"; +const char _openttd_revision[] = "1.10.0-beta1"; /** * The text version of OpenTTD's build date. @@ -50,7 +50,7 @@ const char _openttd_build_date[] = __DATE__ " " __TIME__; /** * The git revision hash of this version. */ -const char _openttd_revision_hash[] = "f6643952ce53b1823c2273964466f785a907ec1a"; +const char _openttd_revision_hash[] = "9f50c754ffee52211e61d88e6d5fc296dfc585e0"; /** * Let us know if current build was modified. This detection @@ -82,11 +82,4 @@ const byte _openttd_revision_tagged = 1; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 9 << 24 | 3 << 20 | 1 << 19 | 28004; - -#ifdef __MORPHOS__ -/** - * Variable used by MorphOS to show the version. - */ -extern const char morphos_versions_tag[] = "$VER: OpenTTD 1.9.3 (16.09.19) OpenTTD Team [MorphOS, PowerPC]"; -#endif +const uint32 _openttd_newgrf_version = 1 << 28 | 10 << 24 | 0 << 20 | 0 << 19 | 28004; diff --git a/src/road.cpp b/src/road.cpp index f51597538d..d76d6901cb 100644 --- a/src/road.cpp +++ b/src/road.cpp @@ -19,6 +19,9 @@ #include "engine_base.h" #include "date_func.h" #include "landscape.h" +#include "road.h" +#include "road_func.h" +#include "roadveh.h" #include "safeguards.h" @@ -38,9 +41,9 @@ static bool IsPossibleCrossing(const TileIndex tile, Axis ax) } /** - * Clean up unnecessary RoadBits of a planed tile. + * Clean up unnecessary RoadBits of a planned tile. * @param tile current tile - * @param org_rb planed RoadBits + * @param org_rb planned RoadBits * @return optimised RoadBits */ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) @@ -72,7 +75,7 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) /* Always connective */ connective = true; } else { - const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, ROADTYPE_ROAD) | GetAnyRoadBits(neighbor_tile, ROADTYPE_TRAM); + const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, RTT_ROAD) | GetAnyRoadBits(neighbor_tile, RTT_TRAM); /* Accept only connective tiles */ connective = (neighbor_rb & mirrored_rb) != ROAD_NONE; @@ -93,7 +96,7 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) } } - /* If the neighbor tile is inconnective, remove the planed road connection to it */ + /* If the neighbor tile is inconnective, remove the planned road connection to it */ if (!connective) org_rb ^= target_rb; } } @@ -102,53 +105,236 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) } /** - * Finds out, whether given company has all given RoadTypes available + * Finds out, whether given company has a given RoadType available for construction. * @param company ID of company - * @param rts RoadTypes to test - * @return true if company has all requested RoadTypes available + * @param roadtypet RoadType to test + * @return true if company has the requested RoadType available */ -bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts) +bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype) { - RoadTypes avail_roadtypes; - if (company == OWNER_DEITY || company == OWNER_TOWN || _game_mode == GM_EDITOR || _generating_world) { - avail_roadtypes = ROADTYPES_ROAD; + return true; // TODO: should there be a proper check? } else { - Company *c = Company::GetIfValid(company); - if (c == NULL) return false; - avail_roadtypes = (RoadTypes)c->avail_roadtypes | ROADTYPES_ROAD; // road is available for always for everybody + const Company *c = Company::GetIfValid(company); + if (c == nullptr) return false; + return HasBit(c->avail_roadtypes & ~_roadtypes_hidden_mask, roadtype); } - return (rts & ~avail_roadtypes) == 0; +} + +static RoadTypes GetMaskForRoadTramType(RoadTramType rtt) +{ + return rtt == RTT_TRAM ? _roadtypes_type : ~_roadtypes_type; +} + +/** + * Test if any buildable RoadType is available for a company. + * @param company the company in question + * @return true if company has any RoadTypes available + */ +bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt) +{ + return (Company::Get(company)->avail_roadtypes & ~_roadtypes_hidden_mask & GetMaskForRoadTramType(rtt)) != ROADTYPES_NONE; } /** * Validate functions for rail building. - * @param rt road type to check. + * @param roadtype road type to check. * @return true if the current company may build the road. */ -bool ValParamRoadType(const RoadType rt) +bool ValParamRoadType(RoadType roadtype) { - return HasRoadTypesAvail(_current_company, RoadTypeToRoadTypes(rt)); + return roadtype != INVALID_ROADTYPE && HasRoadTypeAvail(_current_company, roadtype); +} + +/** + * Add the road types that are to be introduced at the given date. + * @param rt Roadtype + * @param current The currently available roadtypes. + * @param date The date for the introduction comparisons. + * @return The road types that should be available when date + * introduced road types are taken into account as well. + */ +RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, Date date) +{ + RoadTypes rts = current; + + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + /* Unused road type. */ + if (rti->label == 0) continue; + + /* Not date introduced. */ + if (!IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue; + + /* Not yet introduced at this date. */ + if (rti->introduction_date > date) continue; + + /* Have we introduced all required roadtypes? */ + RoadTypes required = rti->introduction_required_roadtypes; + if ((rts & required) != required) continue; + + rts |= rti->introduces_roadtypes; + } + + /* When we added roadtypes we need to run this method again; the added + * roadtypes might enable more rail types to become introduced. */ + return rts == current ? rts : AddDateIntroducedRoadTypes(rts, date); } /** * Get the road types the given company can build. - * @param company the company to get the roadtypes for. + * @param company the company to get the road types for. + * @param introduces If true, include road types introduced by other road types * @return the road types. */ -RoadTypes GetCompanyRoadtypes(CompanyID company) +RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces) { - RoadTypes rt = ROADTYPES_NONE; + RoadTypes rts = ROADTYPES_NONE; - Engine *e; + const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { const EngineInfo *ei = &e->info; if (HasBit(ei->climates, _settings_game.game_creation.landscape) && (HasBit(e->company_avail, company) || _date >= e->intro_date + DAYS_IN_YEAR)) { - SetBit(rt, HasBit(ei->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); + const RoadVehicleInfo *rvi = &e->u.road; + assert(rvi->roadtype < ROADTYPE_END); + if (introduces) { + rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes; + } else { + SetBit(rts, rvi->roadtype); + } } } - return rt; + if (introduces) return AddDateIntroducedRoadTypes(rts, _date); + return rts; +} + +/** + * Get list of road types, regardless of company availability. + * @param introduces If true, include road types introduced by other road types + * @return the road types. + */ +RoadTypes GetRoadTypes(bool introduces) +{ + RoadTypes rts = ROADTYPES_NONE; + + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + const EngineInfo *ei = &e->info; + if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue; + + const RoadVehicleInfo *rvi = &e->u.road; + assert(rvi->roadtype < ROADTYPE_END); + if (introduces) { + rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes; + } else { + SetBit(rts, rvi->roadtype); + } + } + + if (introduces) return AddDateIntroducedRoadTypes(rts, MAX_DAY); + return rts; +} + +/** + * Get the road type for a given label. + * @param label the roadtype label. + * @param allow_alternate_labels Search in the alternate label lists as well. + * @return the roadtype. + */ +RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels) +{ + /* Loop through each road type until the label is found */ + for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(r); + if (rti->label == label) return r; + } + + if (allow_alternate_labels) { + /* Test if any road type defines the label as an alternate. */ + for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) { + const RoadTypeInfo *rti = GetRoadTypeInfo(r); + if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r; + } + } + + /* No matching label was found, so it is invalid */ + return INVALID_ROADTYPE; +} + +/** + * Returns the available RoadSubTypes for the provided RoadType + * If the given company is valid then will be returned a list of the available sub types at the current date, while passing + * a deity company will make all the sub types available + * @param rt the RoadType to filter + * @param c the company ID to check the roadtype against + * @param any_date whether to return only currently introduced roadtypes or also future ones + * @returns the existing RoadSubTypes + */ +RoadTypes ExistingRoadTypes(CompanyID c) +{ + /* Check only players which can actually own vehicles, editor and gamescripts are considered deities */ + if (c < OWNER_END) { + const Company *company = Company::GetIfValid(c); + if (company != nullptr) return company->avail_roadtypes; + } + + RoadTypes known_roadtypes = ROADTYPES_NONE; + + /* Find used roadtypes */ + Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + /* Check if the roadtype can be used in the current climate */ + if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue; + + /* Check whether available for all potential companies */ + if (e->company_avail != (CompanyMask)-1) continue; + + known_roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes; + } + + /* Get the date introduced roadtypes as well. */ + known_roadtypes = AddDateIntroducedRoadTypes(known_roadtypes, MAX_DAY); + + return known_roadtypes; +} + +/** + * Check whether we can build infrastructure for the given RoadType. This to disable building stations etc. when + * you are not allowed/able to have the RoadType yet. + * @param roadtype the roadtype to check this for + * @param company the company id to check this for + * @param any_date to check only existing vehicles or if it is possible to build them in the future + * @return true if there is any reason why you may build the infrastructure for the given roadtype + */ +bool CanBuildRoadTypeInfrastructure(RoadType roadtype, CompanyID company) +{ + if (_game_mode != GM_EDITOR && !Company::IsValidID(company)) return false; + if (!_settings_client.gui.disable_unsuitable_building) return true; + if (!HasAnyRoadTypesAvail(company, GetRoadTramType(roadtype))) return false; + + RoadTypes roadtypes = ExistingRoadTypes(company); + + /* Check if the filtered roadtypes does have the roadtype we are checking for + * and if we can build new ones */ + if (_settings_game.vehicle.max_roadveh > 0 && HasBit(roadtypes, roadtype)) { + /* Can we actually build the vehicle type? */ + const Engine *e; + FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { + if (!HasBit(e->company_avail, company)) continue; + if (HasPowerOnRoad(e->u.road.roadtype, roadtype) || HasPowerOnRoad(roadtype, e->u.road.roadtype)) return true; + } + return false; + } + + /* We should be able to build infrastructure when we have the actual vehicle type */ + const Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type == VEH_ROAD && (company == OWNER_DEITY || v->owner == company) && + HasBit(roadtypes, RoadVehicle::From(v)->roadtype) && HasPowerOnRoad(RoadVehicle::From(v)->roadtype, roadtype)) return true; + } + + return false; } diff --git a/src/road.h b/src/road.h new file mode 100644 index 0000000000..c359fc779c --- /dev/null +++ b/src/road.h @@ -0,0 +1,316 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 road.h Road specific functions. */ + +#ifndef ROAD_H +#define ROAD_H + +#include "road_type.h" +#include "gfx_type.h" +#include "core/bitmath_func.hpp" +#include "strings_type.h" +#include "date_type.h" +#include "core/enum_type.hpp" +#include "newgrf.h" +#include "economy_func.h" + +#include + +enum RoadTramType : bool { + RTT_ROAD, + RTT_TRAM, +}; + +enum RoadTramTypes : uint8 { + RTTB_ROAD = 1 << RTT_ROAD, + RTTB_TRAM = 1 << RTT_TRAM, +}; +DECLARE_ENUM_AS_BIT_SET(RoadTramTypes) + +#define FOR_ALL_ROADTRAMTYPES(x) for (RoadTramType x : { RTT_ROAD, RTT_TRAM }) + +/** Roadtype flags. Starts with RO instead of R because R is used for rails */ +enum RoadTypeFlags { + ROTF_CATENARY = 0, ///< Bit number for adding catenary + ROTF_NO_LEVEL_CROSSING, ///< Bit number for disabling level crossing + ROTF_NO_HOUSES, ///< Bit number for setting this roadtype as not house friendly + ROTF_HIDDEN, ///< Bit number for hidden from construction. + ROTF_TOWN_BUILD, ///< Bit number for allowing towns to build this roadtype. + + ROTFB_NONE = 0, ///< All flags cleared. + ROTFB_CATENARY = 1 << ROTF_CATENARY, ///< Value for drawing a catenary. + ROTFB_NO_LEVEL_CROSSING = 1 << ROTF_NO_LEVEL_CROSSING, ///< Value for disabling a level crossing. + ROTFB_NO_HOUSES = 1 << ROTF_NO_HOUSES, ///< Value for for setting this roadtype as not house friendly. + ROTFB_HIDDEN = 1 << ROTF_HIDDEN, ///< Value for hidden from construction. + ROTFB_TOWN_BUILD = 1 << ROTF_TOWN_BUILD, ///< Value for allowing towns to build this roadtype. +}; +DECLARE_ENUM_AS_BIT_SET(RoadTypeFlags) + +struct SpriteGroup; + +/** Sprite groups for a roadtype. */ +enum RoadTypeSpriteGroup { + ROTSG_CURSORS, ///< Optional: Cursor and toolbar icon images + ROTSG_OVERLAY, ///< Optional: Images for overlaying track + ROTSG_GROUND, ///< Required: Main group of ground images + ROTSG_reserved1, ///< Placeholder, if we need specific tunnel sprites. + ROTSG_CATENARY_FRONT, ///< Optional: Catenary front + ROTSG_CATENARY_BACK, ///< Optional: Catenary back + ROTSG_BRIDGE, ///< Required: Bridge surface images + ROTSG_reserved2, ///< Placeholder, if we need specific level crossing sprites. + ROTSG_DEPOT, ///< Optional: Depot images + ROTSG_reserved3, ///< Placeholder, if we add road fences (for highways). + ROTSG_ROADSTOP, ///< Required: Drive-in stop surface + ROTSG_END, +}; + +/** List of road type labels. */ +typedef std::vector RoadTypeLabelList; + +class RoadTypeInfo { +public: + /** + * struct containing the sprites for the road GUI. @note only sprites referred to + * directly in the code are listed + */ + struct { + SpriteID build_x_road; ///< button for building single rail in X direction + SpriteID build_y_road; ///< button for building single rail in Y direction + SpriteID auto_road; ///< button for the autoroad construction + SpriteID build_depot; ///< button for building depots + SpriteID build_tunnel; ///< button for building a tunnel + SpriteID convert_road; ///< button for converting road types + } gui_sprites; + + struct { + CursorID road_swne; ///< Cursor for building rail in X direction + CursorID road_nwse; ///< Cursor for building rail in Y direction + CursorID autoroad; ///< Cursor for autorail tool + CursorID depot; ///< Cursor for building a depot + CursorID tunnel; ///< Cursor for building a tunnel + SpriteID convert_road; ///< Cursor for converting road types + } cursor; ///< Cursors associated with the road type. + + struct { + StringID name; ///< Name of this rail type. + StringID toolbar_caption; ///< Caption in the construction toolbar GUI for this rail type. + StringID menu_text; ///< Name of this rail type in the main toolbar dropdown. + StringID build_caption; ///< Caption of the build vehicle GUI for this rail type. + StringID replace_text; ///< Text used in the autoreplace GUI. + StringID new_engine; ///< Name of an engine for this type of road in the engine preview GUI. + + StringID err_build_road; ///< Building a normal piece of road + StringID err_remove_road; ///< Removing a normal piece of road + StringID err_depot; ///< Building a depot + StringID err_build_station[2]; ///< Building a bus or truck station + StringID err_remove_station[2]; ///< Removing of a bus or truck station + StringID err_convert_road; ///< Converting a road type + + StringID picker_title[2]; ///< Title for the station picker for bus or truck stations + StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations + } strings; ///< Strings associated with the rail type. + + /** bitmask to the OTHER roadtypes on which a vehicle of THIS roadtype generates power */ + RoadTypes powered_roadtypes; + + /** + * Bit mask of road type flags + */ + RoadTypeFlags flags; + + /** + * Cost multiplier for building this road type + */ + uint16 cost_multiplier; + + /** + * Cost multiplier for maintenance of this road type + */ + uint16 maintenance_multiplier; + + /** + * Maximum speed for vehicles travelling on this road type + */ + uint16 max_speed; + + /** + * Unique 32 bit road type identifier + */ + RoadTypeLabel label; + + /** + * Road type labels this type provides in addition to the main label. + */ + RoadTypeLabelList alternate_labels; + + /** + * Colour on mini-map + */ + byte map_colour; + + /** + * Introduction date. + * When #INVALID_DATE or a vehicle using this roadtype gets introduced earlier, + * the vehicle's introduction date will be used instead for this roadtype. + * The introduction at this date is furthermore limited by the + * #introduction_required_types. + */ + Date introduction_date; + + /** + * Bitmask of roadtypes that are required for this roadtype to be introduced + * at a given #introduction_date. + */ + RoadTypes introduction_required_roadtypes; + + /** + * Bitmask of which other roadtypes are introduced when this roadtype is introduced. + */ + RoadTypes introduces_roadtypes; + + /** + * The sorting order of this roadtype for the toolbar dropdown. + */ + byte sorting_order; + + /** + * NewGRF providing the Action3 for the roadtype. nullptr if not available. + */ + const GRFFile *grffile[ROTSG_END]; + + /** + * Sprite groups for resolving sprites + */ + const SpriteGroup *group[ROTSG_END]; + + inline bool UsesOverlay() const + { + return this->group[ROTSG_GROUND] != nullptr; + } +}; + +extern RoadTypes _roadtypes_type; + +static inline bool RoadTypeIsRoad(RoadType roadtype) +{ + return !HasBit(_roadtypes_type, roadtype); +} + +static inline bool RoadTypeIsTram(RoadType roadtype) +{ + return HasBit(_roadtypes_type, roadtype); +} + +static inline RoadTramType GetRoadTramType(RoadType roadtype) +{ + return RoadTypeIsTram(roadtype) ? RTT_TRAM : RTT_ROAD; +} + +static inline RoadTramType OtherRoadTramType(RoadTramType rtt) +{ + return rtt == RTT_ROAD ? RTT_TRAM : RTT_ROAD; +} + +/** + * Returns a pointer to the Roadtype information for a given roadtype + * @param roadtype the road type which the information is requested for + * @return The pointer to the RoadTypeInfo + */ +static inline const RoadTypeInfo *GetRoadTypeInfo(RoadType roadtype) +{ + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + assert(roadtype < ROADTYPE_END); + return &_roadtypes[roadtype]; +} + +/** + * Checks if an engine of the given RoadType got power on a tile with a given + * RoadType. This would normally just be an equality check, but for electrified + * roads (which also support non-electric vehicles). + * @return Whether the engine got power on this tile. + * @param enginetype The RoadType of the engine we are considering. + * @param tiletype The RoadType of the tile we are considering. + */ +static inline bool HasPowerOnRoad(RoadType enginetype, RoadType tiletype) +{ + return HasBit(GetRoadTypeInfo(enginetype)->powered_roadtypes, tiletype); +} + +/** + * Returns the cost of building the specified roadtype. + * @param roadtype The roadtype being built. + * @return The cost multiplier. + */ +static inline Money RoadBuildCost(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + return (_price[PR_BUILD_ROAD] * GetRoadTypeInfo(roadtype)->cost_multiplier) >> 3; +} + +/** + * Returns the cost of clearing the specified roadtype. + * @param roadtype The roadtype being removed. + * @return The cost. + */ +static inline Money RoadClearCost(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + + /* Flat fee for removing road. */ + if (RoadTypeIsRoad(roadtype)) return _price[PR_CLEAR_ROAD]; + + /* Clearing tram earns a little money, but also incurs the standard clear road cost, + * so no profit can be made. */ + return _price[PR_CLEAR_ROAD] - RoadBuildCost(roadtype) * 3 / 4; +} + +/** + * Calculates the cost of road conversion + * @param from The roadtype we are converting from + * @param to The roadtype we are converting to + * @return Cost per RoadBit + */ +static inline Money RoadConvertCost(RoadType from, RoadType to) +{ + /* Don't apply convert costs when converting to the same roadtype (ex. building a roadstop over existing road) */ + if (from == to) return (Money)0; + + /* Same cost as removing and then building. */ + return RoadBuildCost(to) + RoadClearCost(from); +} + +/** + * Test if road disallows level crossings + * @param roadtype The roadtype we are testing + * @return True iff the roadtype disallows level crossings + */ +static inline bool RoadNoLevelCrossing(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + return HasBit(GetRoadTypeInfo(roadtype)->flags, ROTF_NO_LEVEL_CROSSING); +} + +RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels = true); + +void ResetRoadTypes(); +void InitRoadTypes(); +RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt); +bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt); + +extern std::vector _sorted_roadtypes; +extern RoadTypes _roadtypes_hidden_mask; + +/** + * Loop header for iterating over roadtypes, sorted by sortorder. + * @param var Roadtype. + */ +#define FOR_ALL_SORTED_ROADTYPES(var) for (uint8 index = 0; index < _sorted_roadtypes.size() && (var = _sorted_roadtypes[index], true) ; index++) + +#endif /* ROAD_H */ diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 200e443982..b3bdaf0487 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -11,6 +11,7 @@ #include "stdafx.h" #include "cmd_helper.h" +#include "road.h" #include "road_internal.h" #include "viewport_func.h" #include "command_func.h" @@ -31,15 +32,152 @@ #include "town.h" #include "company_base.h" #include "core/random_func.hpp" +#include "newgrf_debug.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "date_func.h" #include "genworld.h" #include "company_gui.h" +#include "road_func.h" #include "table/strings.h" +#include "table/roadtypes.h" #include "safeguards.h" +/** Helper type for lists/vectors of road vehicles */ +typedef std::vector RoadVehicleList; + +RoadTypeInfo _roadtypes[ROADTYPE_END]; +std::vector _sorted_roadtypes; +RoadTypes _roadtypes_hidden_mask; + +/** + * Bitmap of road/tram types. + * Bit if set if a roadtype is tram. + */ +RoadTypes _roadtypes_type; + +/** + * Reset all road type information to its default values. + */ +void ResetRoadTypes() +{ + assert_compile(lengthof(_original_roadtypes) <= lengthof(_roadtypes)); + + uint i = 0; + for (; i < lengthof(_original_roadtypes); i++) _roadtypes[i] = _original_roadtypes[i]; + + static const RoadTypeInfo empty_roadtype = { + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, {}, 0, {}, {} }, + ROADTYPES_NONE, ROTFB_NONE, 0, 0, 0, 0, + RoadTypeLabelList(), 0, 0, ROADTYPES_NONE, ROADTYPES_NONE, 0, + {}, {} }; + for (; i < lengthof(_roadtypes); i++) _roadtypes[i] = empty_roadtype; + + _roadtypes_hidden_mask = ROADTYPES_NONE; + _roadtypes_type = ROADTYPES_TRAM; +} + +void ResolveRoadTypeGUISprites(RoadTypeInfo *rti) +{ + SpriteID cursors_base = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_CURSORS); + if (cursors_base != 0) { + rti->gui_sprites.build_y_road = cursors_base + 0; + rti->gui_sprites.build_x_road = cursors_base + 1; + rti->gui_sprites.auto_road = cursors_base + 2; + rti->gui_sprites.build_depot = cursors_base + 3; + rti->gui_sprites.build_tunnel = cursors_base + 4; + rti->gui_sprites.convert_road = cursors_base + 5; + rti->cursor.road_swne = cursors_base + 6; + rti->cursor.road_nwse = cursors_base + 7; + rti->cursor.autoroad = cursors_base + 8; + rti->cursor.depot = cursors_base + 9; + rti->cursor.tunnel = cursors_base + 10; + rti->cursor.convert_road = cursors_base + 11; + } +} + +/** + * Compare roadtypes based on their sorting order. + * @param first The roadtype to compare to. + * @param second The roadtype to compare. + * @return True iff the first should be sorted before the second. + */ +static bool CompareRoadTypes(const RoadType &first, const RoadType &second) +{ + if (RoadTypeIsRoad(first) == RoadTypeIsRoad(second)) { + return GetRoadTypeInfo(first)->sorting_order < GetRoadTypeInfo(second)->sorting_order; + } + return RoadTypeIsTram(first) < RoadTypeIsTram(second); +} + +/** + * Resolve sprites of custom road types + */ +void InitRoadTypes() +{ + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + RoadTypeInfo *rti = &_roadtypes[rt]; + ResolveRoadTypeGUISprites(rti); + if (HasBit(rti->flags, ROTF_HIDDEN)) SetBit(_roadtypes_hidden_mask, rt); + } + + _sorted_roadtypes.clear(); + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (_roadtypes[rt].label != 0 && !HasBit(_roadtypes_hidden_mask, rt)) { + _sorted_roadtypes.push_back(rt); + } + } + std::sort(_sorted_roadtypes.begin(), _sorted_roadtypes.end(), CompareRoadTypes); +} + +/** + * Allocate a new road type label + */ +RoadType AllocateRoadType(RoadTypeLabel label, RoadTramType rtt) +{ + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + RoadTypeInfo *rti = &_roadtypes[rt]; + + if (rti->label == 0) { + /* Set up new road type */ + *rti = _original_roadtypes[(rtt == RTT_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD]; + rti->label = label; + rti->alternate_labels.clear(); + rti->flags = ROTFB_NONE; + rti->introduction_date = INVALID_DATE; + + /* Make us compatible with ourself. */ + rti->powered_roadtypes = (RoadTypes)(1ULL << rt); + + /* We also introduce ourself. */ + rti->introduces_roadtypes = (RoadTypes)(1ULL << rt); + + /* Default sort order; order of allocation, but with some + * offsets so it's easier for NewGRF to pick a spot without + * changing the order of other (original) road types. + * The << is so you can place other roadtypes in between the + * other roadtypes, the 7 is to be able to place something + * before the first (default) road type. */ + rti->sorting_order = rt << 2 | 7; + + /* Set bitmap of road/tram types */ + if (rtt == RTT_TRAM) { + SetBit(_roadtypes_type, rt); + } else { + ClrBit(_roadtypes_type, rt); + } + + return rt; + } + } + + return INVALID_ROADTYPE; +} + /** * Verify whether a road vehicle is available. * @return \c true if at least one road vehicle is available, \c false if not @@ -52,6 +190,23 @@ bool RoadVehiclesAreBuilt() return false; } +/** + * Update road infrastructure counts for a company. + * @param rt Road type to update count of. + * @param o Owner of road piece. + * @param count Number of road pieces to adjust. + */ +void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count) +{ + if (rt == INVALID_ROADTYPE) return; + + Company *c = Company::GetIfValid(o); + if (c == nullptr) return; + + c->infrastructure.road[rt] += count; + DirtyCompanyInfrastructureWindows(c->index); +} + /** Invalid RoadBits on slopes. */ static const RoadBits _invalid_tileh_slopes_road[2][15] = { /* The inverse of the mixable RoadBits on a leveled slope */ @@ -113,7 +268,7 @@ static Foundation GetRoadFoundation(Slope tileh, RoadBits bits); * @param town_check Shall the town rating checked/affected * @return A succeeded command when it is allowed to remove the road bits, a failed command otherwise. */ -CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check) +CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadTramType rtt, DoCommandFlag flags, bool town_check) { if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return CommandCost(); @@ -121,7 +276,7 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R * Towns are not be allowed to remove non "normal" road pieces, like tram * tracks as that would result in trams that cannot turn. */ if (_current_company == OWNER_WATER || - (rt == ROADTYPE_ROAD && !Company::IsValidID(_current_company))) return CommandCost(); + (rtt == RTT_ROAD && !Company::IsValidID(_current_company))) return CommandCost(); /* Only do the special processing if the road is owned * by a town */ @@ -136,7 +291,7 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R if (_cheats.magic_bulldozer.value) return CommandCost(); Town *t = ClosestTownFromTile(tile, UINT_MAX); - if (t == NULL) return CommandCost(); + if (t == nullptr) return CommandCost(); /* check if you're allowed to remove the street owned by a town * removal allowance depends on difficulty setting */ @@ -145,11 +300,11 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R /* Get a bitmask of which neighbouring roads has a tile */ RoadBits n = ROAD_NONE; - RoadBits present = GetAnyRoadBits(tile, rt); - if ((present & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rt) & ROAD_SW)) n |= ROAD_NE; - if ((present & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rt) & ROAD_NW)) n |= ROAD_SE; - if ((present & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rt) & ROAD_NE)) n |= ROAD_SW; - if ((present & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rt) & ROAD_SE)) n |= ROAD_NW; + RoadBits present = GetAnyRoadBits(tile, rtt); + if ((present & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rtt) & ROAD_SW)) n |= ROAD_NE; + if ((present & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rtt) & ROAD_NW)) n |= ROAD_SE; + if ((present & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rtt) & ROAD_NE)) n |= ROAD_SW; + if ((present & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rtt) & ROAD_SE)) n |= ROAD_NW; int rating_decrease = RATING_ROAD_DOWN_STEP_EDGE; /* If 0 or 1 bits are set in n, or if no bits that match the bits to remove, @@ -177,11 +332,13 @@ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, R * @param crossing_check should we check if there is a tram track when we are removing road from crossing? * @param town_check should we check if the town allows removal? */ -static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits pieces, RoadType rt, bool crossing_check, bool town_check = true) +static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits pieces, RoadTramType rtt, bool crossing_check, bool town_check = true) { - RoadTypes rts = GetRoadTypes(tile); + assert(pieces != ROAD_NONE); + + RoadType existing_rt = MayHaveRoad(tile) ? GetRoadType(tile, rtt) : INVALID_ROADTYPE; /* The tile doesn't have the given road type */ - if (!HasBit(rts, rt)) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); + if (existing_rt == INVALID_ROADTYPE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); switch (GetTileType(tile)) { case MP_ROAD: { @@ -209,37 +366,32 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec return CMD_ERROR; } - CommandCost ret = CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rt), rt, flags, town_check); + CommandCost ret = CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rtt), rtt, flags, town_check); if (ret.Failed()) return ret; if (!IsTileType(tile, MP_ROAD)) { /* If it's the last roadtype, just clear the whole tile */ - if (rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); + if (GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); CommandCost cost(EXPENSES_CONSTRUCTION); if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* Removing any roadbit in the bridge axis removes the roadtype (that's the behaviour remove-long-roads needs) */ - if ((AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) & pieces) == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); + if ((AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) & pieces) == ROAD_NONE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); TileIndex other_end = GetOtherTunnelBridgeEnd(tile); /* Pay for *every* tile of the bridge or tunnel */ uint len = GetTunnelBridgeLength(other_end, tile) + 2; - cost.AddCost(len * 2 * _price[PR_CLEAR_ROAD]); + cost.AddCost(len * 2 * RoadClearCost(existing_rt)); if (flags & DC_EXEC) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; - DirtyCompanyInfrastructureWindows(c->index); - } + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); - SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt)); - SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt)); + SetRoadType(other_end, rtt, INVALID_ROADTYPE); + SetRoadType(tile, rtt, INVALID_ROADTYPE); /* If the owner of the bridge sells all its road, also move the ownership * to the owner of the other roadtype, unless the bridge owner is a town. */ - RoadType other_rt = (rt == ROADTYPE_ROAD) ? ROADTYPE_TRAM : ROADTYPE_ROAD; - Owner other_owner = GetRoadOwner(tile, other_rt); + Owner other_owner = GetRoadOwner(tile, OtherRoadTramType(rtt)); if (!IsTileOwner(tile, other_owner) && !IsTileOwner(tile, OWNER_TOWN)) { SetTileOwner(tile, other_owner); SetTileOwner(other_end, other_owner); @@ -255,15 +407,11 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec } } else { assert(IsDriveThroughStopTile(tile)); - cost.AddCost(_price[PR_CLEAR_ROAD] * 2); + cost.AddCost(RoadClearCost(existing_rt) * 2); if (flags & DC_EXEC) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[rt] -= 2; - DirtyCompanyInfrastructureWindows(c->index); - } - SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt)); + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -2); + SetRoadType(tile, rtt, INVALID_ROADTYPE); MarkTileDirtyByTile(tile); } } @@ -279,8 +427,8 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec tileh = SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)); } - RoadBits present = GetRoadBits(tile, rt); - const RoadBits other = GetOtherRoadBits(tile, rt); + RoadBits present = GetRoadBits(tile, rtt); + const RoadBits other = GetRoadBits(tile, OtherRoadTramType(rtt)); const Foundation f = GetRoadFoundation(tileh, present); if (HasRoadWorks(tile) && _current_company != OWNER_WATER) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); @@ -295,7 +443,7 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec /* limit the bits to delete to the existing bits. */ pieces &= present; - if (pieces == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); + if (pieces == ROAD_NONE) return_cmd_error((rtt == RTT_TRAM) ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); /* Now set present what it will be after the remove */ present ^= pieces; @@ -318,38 +466,34 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec } } - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - c->infrastructure.road[rt] -= CountBits(pieces); - DirtyCompanyInfrastructureWindows(c->index); - } + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -(int)CountBits(pieces)); if (present == ROAD_NONE) { - RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); - if (rts == ROADTYPES_NONE) { + /* No other road type, just clear tile. */ + if (GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) { /* Includes MarkTileDirtyByTile() */ DoClearSquare(tile); } else { - if (rt == ROADTYPE_ROAD && IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) { + if (rtt == RTT_ROAD && IsRoadOwner(tile, rtt, OWNER_TOWN)) { /* Update nearest-town index */ const Town *town = CalcClosestTownFromTile(tile); - SetTownIndex(tile, town == NULL ? INVALID_TOWN : town->index); + SetTownIndex(tile, town == nullptr ? INVALID_TOWN : town->index); } - SetRoadBits(tile, ROAD_NONE, rt); - SetRoadTypes(tile, rts); + SetRoadBits(tile, ROAD_NONE, rtt); + SetRoadType(tile, rtt, INVALID_ROADTYPE); MarkTileDirtyByTile(tile); } } else { /* When bits are removed, you *always* end up with something that * is not a complete straight road tile. However, trams do not have * onewayness, so they cannot remove it either. */ - if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE); - SetRoadBits(tile, present, rt); + if (rtt == RTT_ROAD) SetDisallowedRoadDirections(tile, DRD_NONE); + SetRoadBits(tile, present, rtt); MarkTileDirtyByTile(tile); } } - CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * _price[PR_CLEAR_ROAD]); + CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * RoadClearCost(existing_rt)); /* If we build a foundation we have to pay for it. */ if (f == FOUNDATION_NONE && GetRoadFoundation(tileh, present) != FOUNDATION_NONE) cost.AddCost(_price[PR_BUILD_FOUNDATION]); @@ -361,21 +505,12 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec return CMD_ERROR; } - /* Don't allow road to be removed from the crossing when there is tram; - * we can't draw the crossing without roadbits ;) */ - if (rt == ROADTYPE_ROAD && HasTileRoadType(tile, ROADTYPE_TRAM) && (flags & DC_EXEC || crossing_check)) return CMD_ERROR; - if (flags & DC_EXEC) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[rt] -= 2; - DirtyCompanyInfrastructureWindows(c->index); - } + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(existing_rt, GetRoadOwner(tile, rtt), -2); Track railtrack = GetCrossingRailTrack(tile); - RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); - if (rts == ROADTYPES_NONE) { + if (GetRoadType(tile, OtherRoadTramType(rtt)) == INVALID_ROADTYPE) { TrackBits tracks = GetCrossingRailBits(tile); bool reserved = HasCrossingReservation(tile); MakeRailNormal(tile, GetTileOwner(tile), tracks, GetRailType(tile)); @@ -383,18 +518,18 @@ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits piec /* Update rail count for level crossings. The plain track should still be accounted * for, so only subtract the difference to the level crossing cost. */ - c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + Company *c = Company::GetIfValid(GetTileOwner(tile)); + if (c != nullptr) { c->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR - 1; DirtyCompanyInfrastructureWindows(c->index); } } else { - SetRoadTypes(tile, rts); + SetRoadType(tile, rtt, INVALID_ROADTYPE); } MarkTileDirtyByTile(tile); YapfNotifyTrackLayoutChange(tile, railtrack); } - return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROAD] * 2); + return CommandCost(EXPENSES_CONSTRUCTION, RoadClearCost(existing_rt) * 2); } default: @@ -475,8 +610,8 @@ static CommandCost CheckRoadSlope(Slope tileh, RoadBits *pieces, RoadBits existi * @param tile tile where to build road * @param flags operation to perform * @param p1 bit 0..3 road pieces to build (RoadBits) - * bit 4..5 road type - * bit 6..7 disallowed directions to toggle + * bit 4..9 road type + * bit 11..12 disallowed directions to toggle * @param p2 the town that is building the road (0 if not applicable) * @param text unused * @return the cost of this operation or an error @@ -494,13 +629,13 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if ((Company::IsValidID(company) && p2 != 0) || (company == OWNER_TOWN && !Town::IsValidID(p2)) || (company == OWNER_DEITY && p2 != 0)) return CMD_ERROR; if (company != OWNER_TOWN) { const Town *town = CalcClosestTownFromTile(tile); - p2 = (town != NULL) ? town->index : INVALID_TOWN; + p2 = (town != nullptr) ? town->index : INVALID_TOWN; if (company == OWNER_DEITY) { company = OWNER_TOWN; /* If we are not within a town, we are not owned by the town */ - if (town == NULL || DistanceSquare(tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { + if (town == nullptr || DistanceSquare(tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { company = OWNER_NONE; } } @@ -511,12 +646,13 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* do not allow building 'zero' road bits, code wouldn't handle it */ if (pieces == ROAD_NONE) return CMD_ERROR; - RoadType rt = Extract(p1); - if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; + RoadType rt = Extract(p1); + if (!ValParamRoadType(rt)) return CMD_ERROR; - DisallowedRoadDirections toggle_drd = Extract(p1); + DisallowedRoadDirections toggle_drd = Extract(p1); Slope tileh = GetTileSlope(tile); + RoadTramType rtt = GetRoadTramType(rt); bool need_to_clear = false; switch (GetTileType(tile)) { @@ -525,21 +661,21 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 case ROAD_TILE_NORMAL: { if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); - other_bits = GetOtherRoadBits(tile, rt); - if (!HasTileRoadType(tile, rt)) break; + other_bits = GetRoadBits(tile, OtherRoadTramType(rtt)); + if (!HasTileRoadType(tile, rtt)) break; - existing = GetRoadBits(tile, rt); + existing = GetRoadBits(tile, rtt); bool crossing = !IsStraightRoad(existing | pieces); - if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) { + if (rtt == RTT_ROAD && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) { /* Junctions cannot be one-way */ return_cmd_error(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); } if ((existing & pieces) == pieces) { /* We only want to set the (dis)allowed road directions */ - if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM) { + if (toggle_drd != DRD_NONE && rtt == RTT_ROAD) { if (crossing) return_cmd_error(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); - Owner owner = GetRoadOwner(tile, ROADTYPE_ROAD); + Owner owner = GetRoadOwner(tile, rtt); if (owner != OWNER_NONE) { CommandCost ret = CheckOwnership(owner, tile); if (ret.Failed()) return ret; @@ -558,7 +694,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } /* Ignore half built tiles */ - if ((flags & DC_EXEC) && rt != ROADTYPE_TRAM && IsStraightRoad(existing)) { + if ((flags & DC_EXEC) && IsStraightRoad(existing)) { SetDisallowedRoadDirections(tile, dis_new); MarkTileDirtyByTile(tile); } @@ -568,8 +704,8 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ - if (rt == ROADTYPE_TRAM && HasExactlyOneBit(existing)) { - Owner owner = GetRoadOwner(tile, rt); + if (rtt == RTT_TRAM && HasExactlyOneBit(existing)) { + Owner owner = GetRoadOwner(tile, rtt); if (Company::IsValidID(owner)) { CommandCost ret = CheckOwnership(owner); if (ret.Failed()) return ret; @@ -579,15 +715,19 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } case ROAD_TILE_CROSSING: + if (RoadNoLevelCrossing(rt)) { + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + } + other_bits = GetCrossingRoadBits(tile); if (pieces & ComplementRoadBits(other_bits)) goto do_clear; pieces = other_bits; // we need to pay for both roadbits - if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); break; case ROAD_TILE_DEPOT: - if ((GetAnyRoadBits(tile, rt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); goto do_clear; default: NOT_REACHED(); @@ -606,8 +746,12 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear; + if (RoadNoLevelCrossing(rt)) { + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_ROAD); + } + if (RailNoLevelCrossings(GetRailType(tile))) { - return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); + return_cmd_error(STR_ERROR_CROSSING_DISALLOWED_RAIL); } Axis roaddir; @@ -632,39 +776,35 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Track railtrack = AxisToTrack(OtherAxis(roaddir)); YapfNotifyTrackLayoutChange(tile, railtrack); /* Update company infrastructure counts. A level crossing has two road bits. */ - Company *c = Company::GetIfValid(company); - if (c != NULL) { - c->infrastructure.road[rt] += 2; - if (rt != ROADTYPE_ROAD) c->infrastructure.road[ROADTYPE_ROAD] += 2; - DirtyCompanyInfrastructureWindows(company); - } + UpdateCompanyRoadInfrastructure(rt, company, 2); + /* Update rail count for level crossings. The plain track is already * counted, so only add the difference to the level crossing cost. */ - c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + Company *c = Company::GetIfValid(GetTileOwner(tile)); + if (c != nullptr) { c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR - 1; DirtyCompanyInfrastructureWindows(c->index); } /* Always add road to the roadtypes (can't draw without it) */ bool reserved = HasBit(GetRailReservationTrackBits(tile), railtrack); - MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), RoadTypeToRoadTypes(rt) | ROADTYPES_ROAD, p2); + MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), rtt == RTT_ROAD ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, p2); SetCrossingReservation(tile, reserved); UpdateLevelCrossing(tile, false); MarkTileDirtyByTile(tile); } - return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_ROAD] * (rt == ROADTYPE_ROAD ? 2 : 4)); + return CommandCost(EXPENSES_CONSTRUCTION, 2 * RoadBuildCost(rt)); } case MP_STATION: { - if ((GetAnyRoadBits(tile, rt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if ((GetAnyRoadBits(tile, rtt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); if (!IsDriveThroughStopTile(tile)) goto do_clear; RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile))); if (pieces & ~curbits) goto do_clear; pieces = curbits; // we need to pay for both roadbits - if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); break; } @@ -672,7 +812,7 @@ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) goto do_clear; /* Only allow building the outern roadbit, so building long roads stops at existing bridges */ if (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) goto do_clear; - if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); + if (HasTileRoadType(tile, rtt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); /* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */ CommandCost ret = TunnelBridgeIsFree(tile, GetOtherTunnelBridgeEnd(tile)); if (ret.Failed()) return ret; @@ -713,15 +853,10 @@ do_clear:; Slope slope = GetTileSlope(tile); Foundation found_new = GetRoadFoundation(slope, pieces | existing); - /* Test if all other roadtypes can be built at that foundation */ - for (RoadType rtest = ROADTYPE_ROAD; rtest < ROADTYPE_END; rtest++) { - if (rtest != rt) { // check only other road types - RoadBits bits = GetRoadBits(tile, rtest); - /* do not check if there are not road bits of given type */ - if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) { - return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); - } - } + RoadBits bits = GetRoadBits(tile, OtherRoadTramType(rtt)); + /* do not check if there are not road bits of given type */ + if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) { + return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } } } @@ -729,6 +864,23 @@ do_clear:; CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; + if (IsNormalRoadTile(tile)) { + /* If the road types don't match, try to convert only if vehicles of + * the new road type are not powered on the present road type and vehicles of + * the present road type are powered on the new road type. */ + RoadType existing_rt = GetRoadType(tile, rtt); + if (existing_rt != INVALID_ROADTYPE && existing_rt != rt) { + if (HasPowerOnRoad(rt, existing_rt)) { + rt = existing_rt; + } else if (HasPowerOnRoad(existing_rt, rt)) { + CommandCost ret = DoCommand(tile, tile, rt, flags, CMD_CONVERT_ROAD); + if (ret.Failed()) return ret; + cost.AddCost(ret); + } else { + return CMD_ERROR; + } + } + } } uint num_pieces = (!need_to_clear && IsTileType(tile, MP_TUNNELBRIDGE)) ? @@ -737,28 +889,28 @@ do_clear:; /* Count pieces */ CountBits(pieces); - cost.AddCost(num_pieces * _price[PR_BUILD_ROAD]); + cost.AddCost(num_pieces * RoadBuildCost(rt)); if (flags & DC_EXEC) { switch (GetTileType(tile)) { case MP_ROAD: { - RoadTileType rtt = GetRoadTileType(tile); - if (existing == ROAD_NONE || rtt == ROAD_TILE_CROSSING) { - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - SetRoadOwner(tile, rt, company); - if (rt == ROADTYPE_ROAD) SetTownIndex(tile, p2); + RoadTileType rttype = GetRoadTileType(tile); + if (existing == ROAD_NONE || rttype == ROAD_TILE_CROSSING) { + SetRoadType(tile, rtt, rt); + SetRoadOwner(tile, rtt, company); + if (rtt == RTT_ROAD) SetTownIndex(tile, p2); } - if (rtt != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rt); + if (rttype != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rtt); break; } case MP_TUNNELBRIDGE: { TileIndex other_end = GetOtherTunnelBridgeEnd(tile); - SetRoadTypes(other_end, GetRoadTypes(other_end) | RoadTypeToRoadTypes(rt)); - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - SetRoadOwner(other_end, rt, company); - SetRoadOwner(tile, rt, company); + SetRoadType(other_end, rtt, rt); + SetRoadType(tile, rtt, rt); + SetRoadOwner(other_end, rtt, company); + SetRoadOwner(tile, rtt, company); /* Mark tiles dirty that have been repaved */ if (IsBridge(tile)) { @@ -770,26 +922,23 @@ do_clear:; break; } - case MP_STATION: + case MP_STATION: { assert(IsDriveThroughStopTile(tile)); - SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); - SetRoadOwner(tile, rt, company); + SetRoadType(tile, rtt, rt); + SetRoadOwner(tile, rtt, company); break; + } default: - MakeRoadNormal(tile, pieces, RoadTypeToRoadTypes(rt), p2, company, company); + MakeRoadNormal(tile, pieces, (rtt == RTT_ROAD) ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, p2, company, company); break; } /* Update company infrastructure count. */ - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - if (IsTileType(tile, MP_TUNNELBRIDGE)) num_pieces *= TUNNELBRIDGE_TRACKBIT_FACTOR; - c->infrastructure.road[rt] += num_pieces; - DirtyCompanyInfrastructureWindows(c->index); - } + if (IsTileType(tile, MP_TUNNELBRIDGE)) num_pieces *= TUNNELBRIDGE_TRACKBIT_FACTOR; + UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), num_pieces); - if (rt != ROADTYPE_TRAM && IsNormalRoadTile(tile)) { + if (rtt == RTT_ROAD && IsNormalRoadTile(tile)) { existing |= pieces; SetDisallowedRoadDirections(tile, IsStraightRoad(existing) ? GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE); @@ -810,8 +959,14 @@ do_clear:; bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir) { tile += TileOffsByDiagDir(dir); - if (!IsValidTile(tile)) return false; - RoadBits bits = GetAnyRoadBits(tile, rt, false); + if (!IsValidTile(tile) || !MayHaveRoad(tile)) return false; + + RoadTramType rtt = GetRoadTramType(rt); + RoadType existing = GetRoadType(tile, rtt); + if (existing == INVALID_ROADTYPE) return false; + if (!HasPowerOnRoad(existing, rt) && !HasPowerOnRoad(rt, existing)) return false; + + RoadBits bits = GetAnyRoadBits(tile, rtt, false); return (bits & DiagDirToRoadBits(ReverseDiagDir(dir))) != 0; } @@ -824,9 +979,9 @@ bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir) * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1). Only used if bit 6 is set or if we are building a single tile * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2). Only used if bit 6 is set or if we are building a single tile * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) - * - p2 = (bit 3 + 4) - road type - * - p2 = (bit 5) - set road direction - * - p2 = (bit 6) - defines two different behaviors for this command: + * - p2 = (bit 3..8) - road type + * - p2 = (bit 10) - set road direction + * - p2 = (bit 11) - defines two different behaviors for this command: * - 0 = Build up to an obstacle. Do not build the first and last roadbits unless they can be connected to something, or if we are building a single tile * - 1 = Fail if an obstacle is found. Always take into account bit 0 and 1. This behavior is used for scripts * @param text unused @@ -837,10 +992,10 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p DisallowedRoadDirections drd = DRD_NORTHBOUND; if (p1 >= MapSize()) return CMD_ERROR; - TileIndex end_tile = p1; - RoadType rt = Extract(p2); - if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; + + RoadType rt = Extract(p2); + if (!ValParamRoadType(rt)) return CMD_ERROR; Axis axis = Extract(p2); /* Only drag in X or Y direction dictated by the direction variable */ @@ -861,7 +1016,7 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p * when you just 'click' on one tile to build them. */ if ((axis == AXIS_Y) == (start_tile == end_tile && HasBit(p2, 0) == HasBit(p2, 1))) drd ^= DRD_BOTH; /* No disallowed direction bits have to be toggled */ - if (!HasBit(p2, 5)) drd = DRD_NONE; + if (!HasBit(p2, 10)) drd = DRD_NONE; CommandCost cost(EXPENSES_CONSTRUCTION); CommandCost last_error = CMD_ERROR; @@ -869,7 +1024,7 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p bool had_bridge = false; bool had_tunnel = false; bool had_success = false; - bool is_ai = HasBit(p2, 6); + bool is_ai = HasBit(p2, 11); /* Start tile is the first tile clicked by the user. */ for (;;) { @@ -889,7 +1044,7 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p if (tile == start_tile && HasBit(p2, 0)) bits &= DiagDirToRoadBits(dir); } - CommandCost ret = DoCommand(tile, drd << 6 | rt << 4 | bits, 0, flags, CMD_BUILD_ROAD); + CommandCost ret = DoCommand(tile, drd << 11 | rt << 4 | bits, 0, flags, CMD_BUILD_ROAD); if (ret.Failed()) { last_error = ret; if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT) { @@ -933,7 +1088,7 @@ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) - * - p2 = (bit 3 + 4) - road type + * - p2 = (bit 3 - 8) - road type * @param text unused * @return the cost of this operation or an error */ @@ -944,8 +1099,8 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 if (p1 >= MapSize()) return CMD_ERROR; TileIndex end_tile = p1; - RoadType rt = Extract(p2); - if (!IsValidRoadType(rt)) return CMD_ERROR; + RoadType rt = Extract(p2); + if (!ValParamRoadType(rt)) return CMD_ERROR; Axis axis = Extract(p2); /* Only drag in X or Y direction dictated by the direction variable */ @@ -973,7 +1128,8 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 /* try to remove the halves. */ if (bits != 0) { - CommandCost ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rt, true); + RoadTramType rtt = GetRoadTramType(rt); + CommandCost ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rtt, true); if (ret.Succeeded()) { if (flags & DC_EXEC) { money -= ret.GetCost(); @@ -981,7 +1137,7 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 _additional_cash_required = DoCommand(start_tile, end_tile, p2, flags & ~DC_EXEC, CMD_REMOVE_LONG_ROAD).GetCost(); return cost; } - RemoveRoad(tile, flags, bits, rt, true, false); + RemoveRoad(tile, flags, bits, rtt, true, false); } cost.AddCost(ret); had_success = true; @@ -1004,7 +1160,7 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 * @param tile tile where to build the depot * @param flags operation to perform * @param p1 bit 0..1 entrance direction (DiagDirection) - * bit 2..3 road type + * bit 2..7 road type * @param p2 unused * @param text unused * @return the cost of this operation or an error @@ -1015,9 +1171,9 @@ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 CommandCost CmdBuildRoadDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { DiagDirection dir = Extract(p1); - RoadType rt = Extract(p1); - if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; + RoadType rt = Extract(p1); + if (!ValParamRoadType(rt)) return CMD_ERROR; CommandCost cost(EXPENSES_CONSTRUCTION); @@ -1041,8 +1197,7 @@ CommandCost CmdBuildRoadDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui dep->build_date = _date; /* A road depot has two road bits. */ - Company::Get(_current_company)->infrastructure.road[rt] += 2; - DirtyCompanyInfrastructureWindows(_current_company); + UpdateCompanyRoadInfrastructure(rt, _current_company, 2); MakeRoadDepot(tile, _current_company, dep->index, dir, rt); MarkTileDirtyByTile(tile); @@ -1064,9 +1219,11 @@ static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { Company *c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + if (c != nullptr) { /* A road depot has two road bits. */ - c->infrastructure.road[FIND_FIRST_BIT(GetRoadTypes(tile))] -= 2; + RoadType rt = GetRoadTypeRoad(tile); + if (rt == INVALID_ROADTYPE) rt = GetRoadTypeTram(tile); + c->infrastructure.road[rt] -= 2; DirtyCompanyInfrastructureWindows(c->index); } @@ -1084,11 +1241,12 @@ static CommandCost ClearTile_Road(TileIndex tile, DoCommandFlag flags) RoadBits b = GetAllRoadBits(tile); /* Clear the road if only one piece is on the tile OR we are not using the DC_AUTO flag */ - if ((HasExactlyOneBit(b) && GetRoadBits(tile, ROADTYPE_TRAM) == ROAD_NONE) || !(flags & DC_AUTO)) { + if ((HasExactlyOneBit(b) && GetRoadBits(tile, RTT_TRAM) == ROAD_NONE) || !(flags & DC_AUTO)) { CommandCost ret(EXPENSES_CONSTRUCTION); - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rt), rt, true); + FOR_ALL_ROADTRAMTYPES(rtt) { + if (!MayHaveRoad(tile) || GetRoadType(tile, rtt) == INVALID_ROADTYPE) continue; + + CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rtt), rtt, true); if (tmp_ret.Failed()) return tmp_ret; ret.AddCost(tmp_ret); } @@ -1098,21 +1256,19 @@ static CommandCost ClearTile_Road(TileIndex tile, DoCommandFlag flags) } case ROAD_TILE_CROSSING: { - RoadTypes rts = GetRoadTypes(tile); CommandCost ret(EXPENSES_CONSTRUCTION); if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST); /* Must iterate over the roadtypes in a reverse manner because * tram tracks must be removed before the road bits. */ - RoadType rt = ROADTYPE_TRAM; - do { - if (HasBit(rts, rt)) { - CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false); - if (tmp_ret.Failed()) return tmp_ret; - ret.AddCost(tmp_ret); - } - } while (rt-- != ROADTYPE_ROAD); + for (RoadTramType rtt : { RTT_TRAM, RTT_ROAD }) { + if (!MayHaveRoad(tile) || GetRoadType(tile, rtt) == INVALID_ROADTYPE) continue; + + CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rtt, false); + if (tmp_ret.Failed()) return tmp_ret; + ret.AddCost(tmp_ret); + } if (flags & DC_EXEC) { DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); @@ -1174,6 +1330,33 @@ const byte _road_sloped_sprites[14] = { 0, 0 }; +/** + * Get the sprite offset within a spritegroup. + * @param slope Slope + * @param bits Roadbits + * @return Offset for the sprite within the spritegroup. + */ +static uint GetRoadSpriteOffset(Slope slope, RoadBits bits) +{ + if (slope != SLOPE_FLAT) { + switch (slope) { + case SLOPE_NE: return 11; + case SLOPE_SE: return 12; + case SLOPE_SW: return 13; + case SLOPE_NW: return 14; + default: NOT_REACHED(); + } + } else { + static const uint offsets[] = { + 0, 18, 17, 7, + 16, 0, 10, 5, + 15, 8, 1, 4, + 9, 3, 6, 2 + }; + return offsets[bits]; + } +} + /** * Should the road be drawn as a unpaved snow/desert road? * By default, roads are always drawn as unpaved if they are on desert or @@ -1191,15 +1374,13 @@ static bool DrawRoadAsSnowDesert(TileIndex tile, Roadside roadside) } /** - * Draws the catenary for the given tile - * @param ti information about the tile (slopes, height etc) - * @param tram the roadbits for the tram + * Draws the catenary for the RoadType of the given tile + * @param ti information about the tile (slopes, height etc) + * @param rt road type to draw catenary for + * @param rb the roadbits for the tram */ -void DrawRoadCatenary(const TileInfo *ti, RoadBits tram) +void DrawRoadTypeCatenary(const TileInfo *ti, RoadType rt, RoadBits rb) { - /* Do not draw catenary if it is invisible */ - if (IsInvisibilitySet(TO_CATENARY)) return; - /* Don't draw the catenary under a low bridge */ if (IsBridgeAbove(ti->tile) && !IsTransparencySet(TO_CATENARY)) { int height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile)); @@ -1207,19 +1388,89 @@ void DrawRoadCatenary(const TileInfo *ti, RoadBits tram) if (height <= GetTileMaxZ(ti->tile) + 1) return; } - SpriteID front; - SpriteID back; + if (CountBits(rb) > 2) { + /* On junctions we check whether neighbouring tiles also have catenary, and possibly + * do not draw catenary towards those neighbours, which do not have catenary. */ + RoadBits rb_new = ROAD_NONE; + for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { + if (rb & DiagDirToRoadBits(dir)) { + TileIndex neighbour = TileAddByDiagDir(ti->tile, dir); + if (MayHaveRoad(neighbour)) { + RoadType rt_road = GetRoadTypeRoad(neighbour); + RoadType rt_tram = GetRoadTypeTram(neighbour); - if (ti->tileh != SLOPE_FLAT) { + if ((rt_road != INVALID_ROADTYPE && HasRoadCatenary(rt_road)) || + (rt_tram != INVALID_ROADTYPE && HasRoadCatenary(rt_tram))) { + rb_new |= DiagDirToRoadBits(dir); + } + } + } + } + if (CountBits(rb_new) >= 2) rb = rb_new; + } + + const RoadTypeInfo* rti = GetRoadTypeInfo(rt); + SpriteID front = GetCustomRoadSprite(rti, ti->tile, ROTSG_CATENARY_FRONT); + SpriteID back = GetCustomRoadSprite(rti, ti->tile, ROTSG_CATENARY_BACK); + + if (front != 0 || back != 0) { + if (front != 0) front += GetRoadSpriteOffset(ti->tileh, rb); + if (back != 0) back += GetRoadSpriteOffset(ti->tileh, rb); + } else if (ti->tileh != SLOPE_FLAT) { back = SPR_TRAMWAY_BACK_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1]; front = SPR_TRAMWAY_FRONT_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1]; } else { - back = SPR_TRAMWAY_BASE + _road_backpole_sprites_1[tram]; - front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[tram]; + back = SPR_TRAMWAY_BASE + _road_backpole_sprites_1[rb]; + front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[rb]; } - AddSortableSpriteToDraw(back, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); - AddSortableSpriteToDraw(front, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); + /* Catenary uses 1st company colour to help identify owner. + * For tiles with OWNER_TOWN or OWNER_NONE, recolour CC to grey as a neutral colour. */ + Owner owner = GetRoadOwner(ti->tile, GetRoadTramType(rt)); + PaletteID pal = (owner == OWNER_NONE || owner == OWNER_TOWN ? GENERAL_SPRITE_COLOUR(COLOUR_GREY) : COMPANY_SPRITE_COLOUR(owner)); + if (back != 0) AddSortableSpriteToDraw(back, pal, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); + if (front != 0) AddSortableSpriteToDraw(front, pal, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); +} + +/** + * Draws the catenary for the given tile + * @param ti information about the tile (slopes, height etc) + */ +void DrawRoadCatenary(const TileInfo *ti) +{ + RoadBits road = ROAD_NONE; + RoadBits tram = ROAD_NONE; + + if (IsTileType(ti->tile, MP_ROAD)) { + if (IsNormalRoad(ti->tile)) { + road = GetRoadBits(ti->tile, RTT_ROAD); + tram = GetRoadBits(ti->tile, RTT_TRAM); + } else if (IsLevelCrossing(ti->tile)) { + tram = road = (GetCrossingRailAxis(ti->tile) == AXIS_Y ? ROAD_X : ROAD_Y); + } + } else if (IsTileType(ti->tile, MP_STATION)) { + if (IsRoadStop(ti->tile)) { + if (IsDriveThroughStopTile(ti->tile)) { + Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; + tram = road = (axis == AXIS_X ? ROAD_X : ROAD_Y); + } else { + tram = road = DiagDirToRoadBits(GetRoadStopDir(ti->tile)); + } + } + } else { + // No road here, no catenary to draw + return; + } + + RoadType rt = GetRoadTypeRoad(ti->tile); + if (rt != INVALID_ROADTYPE && HasRoadCatenaryDrawn(rt)) { + DrawRoadTypeCatenary(ti, rt, road); + } + + rt = GetRoadTypeTram(ti->tile); + if (rt != INVALID_ROADTYPE && HasRoadCatenaryDrawn(rt)) { + DrawRoadTypeCatenary(ti, rt, tram); + } } /** @@ -1240,56 +1491,124 @@ static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int dx, int dy, int } /** - * Draw ground sprite and road pieces + * Draw road underlay and overlay sprites. * @param ti TileInfo + * @param road_rti Road road type information + * @param tram_rti Tram road type information + * @param road_offset Road sprite offset (based on road bits) + * @param tram_offset Tram sprite offset (based on road bits) */ -static void DrawRoadBits(TileInfo *ti) +void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rti, uint road_offset, uint tram_offset) { - RoadBits road = GetRoadBits(ti->tile, ROADTYPE_ROAD); - RoadBits tram = GetRoadBits(ti->tile, ROADTYPE_TRAM); - - SpriteID image = 0; - PaletteID pal = PAL_NONE; - - if (ti->tileh != SLOPE_FLAT) { - DrawFoundation(ti, GetRoadFoundation(ti->tileh, road | tram)); - - /* DrawFoundation() modifies ti. - * Default sloped sprites.. */ - if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + SPR_ROAD_SLOPE_START; + /* Road underlay takes precedence over tram */ + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_GROUND); + DrawGroundSprite(ground + road_offset, pal); + } + } else { + if (tram_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_GROUND); + DrawGroundSprite(ground + tram_offset, pal); + } else { + DrawGroundSprite(SPR_TRAMWAY_TRAM + tram_offset, pal); + } } - if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram]; + /* Draw road overlay */ + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_OVERLAY); + if (ground != 0) DrawGroundSprite(ground + road_offset, pal); + } + } - Roadside roadside = GetRoadside(ti->tile); + /* Draw tram overlay */ + if (tram_rti != nullptr) { + if (tram_rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_OVERLAY); + if (ground != 0) DrawGroundSprite(ground + tram_offset, pal); + } else if (road_rti != nullptr) { + DrawGroundSprite(SPR_TRAMWAY_OVERLAY + tram_offset, pal); + } + } +} +/** + * Get ground sprite to draw for a road tile. + * @param ti TileInof + * @param roadside Road side type + * @param rti Road type info + * @param offset Road sprite offset + * @param[out] pal Palette to draw. + */ +static SpriteID GetRoadGroundSprite(const TileInfo *ti, Roadside roadside, const RoadTypeInfo *rti, uint offset, PaletteID *pal) +{ + /* Draw bare ground sprite if no road or road uses overlay system. */ + if (rti == nullptr || rti->UsesOverlay()) { + if (DrawRoadAsSnowDesert(ti->tile, roadside)) { + return SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh); + } + + switch (roadside) { + case ROADSIDE_BARREN: *pal = PALETTE_TO_BARE_LAND; + return SPR_FLAT_GRASS_TILE + SlopeToSpriteOffset(ti->tileh); + case ROADSIDE_GRASS: + case ROADSIDE_GRASS_ROAD_WORKS: return SPR_FLAT_GRASS_TILE + SlopeToSpriteOffset(ti->tileh); + default: break; // Paved + } + } + + /* Draw original road base sprite */ + SpriteID image = SPR_ROAD_Y + offset; if (DrawRoadAsSnowDesert(ti->tile, roadside)) { image += 19; } else { switch (roadside) { - case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; + case ROADSIDE_BARREN: *pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; case ROADSIDE_GRASS_ROAD_WORKS: break; default: image -= 19; break; // Paved } } - DrawGroundSprite(image, pal); + return image; +} - /* For tram we overlay the road graphics with either tram tracks only - * (when there is actual road beneath the trams) or with tram tracks - * and some dirts which hides the road graphics */ - if (tram != ROAD_NONE) { - if (ti->tileh != SLOPE_FLAT) { - image = _road_sloped_sprites[ti->tileh - 1] + SPR_TRAMWAY_SLOPED_OFFSET; - } else { - image = _road_tile_sprites_1[tram] - SPR_ROAD_Y; - } - image += (road == ROAD_NONE) ? SPR_TRAMWAY_TRAM : SPR_TRAMWAY_OVERLAY; - DrawGroundSprite(image, pal); +/** + * Draw ground sprite and road pieces + * @param ti TileInfo + */ +static void DrawRoadBits(TileInfo *ti) +{ + RoadBits road = GetRoadBits(ti->tile, RTT_ROAD); + RoadBits tram = GetRoadBits(ti->tile, RTT_TRAM); + + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + if (ti->tileh != SLOPE_FLAT) { + DrawFoundation(ti, GetRoadFoundation(ti->tileh, road | tram)); + /* DrawFoundation() modifies ti. */ } - if (road != ROAD_NONE) { + /* Determine sprite offsets */ + uint road_offset = GetRoadSpriteOffset(ti->tileh, road); + uint tram_offset = GetRoadSpriteOffset(ti->tileh, tram); + + /* Draw baseset underlay */ + Roadside roadside = GetRoadside(ti->tile); + + PaletteID pal = PAL_NONE; + SpriteID image = GetRoadGroundSprite(ti, roadside, road_rti, road == ROAD_NONE ? tram_offset : road_offset, &pal); + DrawGroundSprite(image, pal); + + DrawRoadOverlays(ti, pal, road_rti, tram_rti, road_offset, tram_offset); + + /* Draw one way */ + if (road_rti != nullptr) { DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile); if (drd != DRD_NONE) { DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh)); @@ -1302,7 +1621,8 @@ static void DrawRoadBits(TileInfo *ti) return; } - if (tram != ROAD_NONE) DrawRoadCatenary(ti, tram); + /* Draw road, tram catenary */ + DrawRoadCatenary(ti); /* Return if full detail is disabled, or we are zoomed fully out. */ if (!HasBit(_display_opt, DO_FULL_DETAIL) || _cur_dpi->zoom > ZOOM_LVL_DETAIL) return; @@ -1337,41 +1657,38 @@ static void DrawTile_Road(TileInfo *ti) case ROAD_TILE_CROSSING: { if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); - PaletteID pal = PAL_NONE; + Axis axis = GetCrossingRailAxis(ti->tile); + const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + PaletteID pal = PAL_NONE; + + /* Draw base ground */ if (rti->UsesOverlay()) { - Axis axis = GetCrossingRailAxis(ti->tile); - SpriteID road = SPR_ROAD_Y + axis; + SpriteID image = SPR_ROAD_Y + axis; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowDesert(ti->tile, roadside)) { - road += 19; + image += 19; } else { switch (roadside) { case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; - default: road -= 19; break; // Paved + default: image -= 19; break; // Paved } } - DrawGroundSprite(road, pal); - - SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis; - /* Draw tracks, but draw PBS reserved tracks darker. */ - pal = (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile)) ? PALETTE_CRASH : PAL_NONE; - DrawGroundSprite(rail, pal); - - DrawRailTileSeq(ti, &_crossing_layout, TO_CATENARY, rail, 0, PAL_NONE); + DrawGroundSprite(image, pal); } else { - SpriteID image = rti->base_sprites.crossing; - - if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++; + SpriteID image = rti->base_sprites.crossing + axis; if (IsCrossingBarred(ti->tile)) image += 2; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowDesert(ti->tile, roadside)) { image += 8; } else { @@ -1383,18 +1700,31 @@ static void DrawTile_Road(TileInfo *ti) } DrawGroundSprite(image, pal); - - /* PBS debugging, draw reserved tracks darker */ - if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile)) { - DrawGroundSprite(GetCrossingRoadAxis(ti->tile) == AXIS_Y ? GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_x : GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_y, PALETTE_CRASH); - } } - if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) { - DrawGroundSprite(SPR_TRAMWAY_OVERLAY + (GetCrossingRoadAxis(ti->tile) ^ 1), pal); - DrawRoadCatenary(ti, GetCrossingRoadBits(ti->tile)); + DrawRoadOverlays(ti, pal, road_rti, tram_rti, axis, axis); + + /* Draw rail/PBS overlay */ + bool draw_pbs = _game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile); + if (rti->UsesOverlay()) { + PaletteID pal = draw_pbs ? PALETTE_CRASH : PAL_NONE; + SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis; + DrawGroundSprite(rail, pal); + + DrawRailTileSeq(ti, &_crossing_layout, TO_CATENARY, rail, 0, PAL_NONE); + } else if (draw_pbs || tram_rti != nullptr || road_rti->UsesOverlay()) { + /* Add another rail overlay, unless there is only the base road sprite. */ + PaletteID pal = draw_pbs ? PALETTE_CRASH : PAL_NONE; + SpriteID rail = GetCrossingRoadAxis(ti->tile) == AXIS_Y ? GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_x : GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_y; + DrawGroundSprite(rail, pal); } + + /* Draw road, tram catenary */ + DrawRoadCatenary(ti); + + /* Draw rail catenary */ if (HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti); + break; } @@ -1404,15 +1734,42 @@ static void DrawTile_Road(TileInfo *ti) PaletteID palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)); - const DrawTileSprites *dts; - if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) { - dts = &_tram_depot[GetRoadDepotDirection(ti->tile)]; + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt == INVALID_ROADTYPE ? tram_rt : road_rt); + + int relocation = GetCustomRoadSprite(rti, ti->tile, ROTSG_DEPOT); + bool default_gfx = relocation == 0; + if (default_gfx) { + if (HasBit(rti->flags, ROTF_CATENARY)) { + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK && road_rt == INVALID_ROADTYPE && !rti->UsesOverlay()) { + /* Sprites with track only work for default tram */ + relocation = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_ROAD_DEPOT; + default_gfx = false; + } else { + /* Sprites without track are always better, if provided */ + relocation = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_ROAD_DEPOT; + } + } } else { - dts = &_road_depot[GetRoadDepotDirection(ti->tile)]; + relocation -= SPR_ROAD_DEPOT; } + DiagDirection dir = GetRoadDepotDirection(ti->tile); + const DrawTileSprites *dts = &_road_depot[dir]; DrawGroundSprite(dts->ground.sprite, PAL_NONE); - DrawOrigTileSeq(ti, dts, TO_BUILDINGS, palette); + + if (default_gfx) { + uint offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(dir)); + if (rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, ti->tile, ROTSG_OVERLAY); + if (ground != 0) DrawGroundSprite(ground + offset, PAL_NONE); + } else if (road_rt == INVALID_ROADTYPE) { + DrawGroundSprite(SPR_TRAMWAY_OVERLAY + offset, PAL_NONE); + } + } + + DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, palette); break; } } @@ -1429,10 +1786,39 @@ static void DrawTile_Road(TileInfo *ti) void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt) { PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); - const DrawTileSprites *dts = (rt == ROADTYPE_TRAM) ? &_tram_depot[dir] : &_road_depot[dir]; + const RoadTypeInfo* rti = GetRoadTypeInfo(rt); + int relocation = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_DEPOT); + bool default_gfx = relocation == 0; + if (default_gfx) { + if (HasBit(rti->flags, ROTF_CATENARY)) { + if (_loaded_newgrf_features.tram == TRAMWAY_REPLACE_DEPOT_WITH_TRACK && RoadTypeIsTram(rt) && !rti->UsesOverlay()) { + /* Sprites with track only work for default tram */ + relocation = SPR_TRAMWAY_DEPOT_WITH_TRACK - SPR_ROAD_DEPOT; + default_gfx = false; + } else { + /* Sprites without track are always better, if provided */ + relocation = SPR_TRAMWAY_DEPOT_NO_TRACK - SPR_ROAD_DEPOT; + } + } + } else { + relocation -= SPR_ROAD_DEPOT; + } + + const DrawTileSprites *dts = &_road_depot[dir]; DrawSprite(dts->ground.sprite, PAL_NONE, x, y); - DrawOrigTileSeqInGUI(x, y, dts, palette); + + if (default_gfx) { + uint offset = GetRoadSpriteOffset(SLOPE_FLAT, DiagDirToRoadBits(dir)); + if (rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY); + if (ground != 0) DrawSprite(ground + offset, PAL_NONE, x, y); + } else if (RoadTypeIsTram(rt)) { + DrawSprite(SPR_TRAMWAY_OVERLAY + offset, PAL_NONE, x, y); + } + } + + DrawRailTileSeqInGUI(x, y, dts, relocation, 0, palette); } /** @@ -1449,7 +1835,7 @@ void UpdateNearestTownForRoadTiles(bool invalidate) TownID tid = INVALID_TOWN; if (!invalidate) { const Town *town = CalcClosestTownFromTile(t); - if (town != NULL) tid = town->index; + if (town != nullptr) tid = town->index; } SetTownIndex(t, tid); } @@ -1522,7 +1908,7 @@ static void TileLoop_Road(TileIndex tile) if (!HasRoadWorks(tile)) { HouseZonesBits grp = HZB_TOWN_EDGE; - if (t != NULL) { + if (t != nullptr) { grp = GetTownRadiusGroup(t, tile); /* Show an animation to indicate road work */ @@ -1570,11 +1956,19 @@ static void TileLoop_Road(TileIndex tile) if (_settings_game.economy.mod_road_rebuild) { /* Generate a nicer town surface */ - const RoadBits old_rb = GetAnyRoadBits(tile, ROADTYPE_ROAD); + const RoadBits old_rb = GetAnyRoadBits(tile, RTT_ROAD); const RoadBits new_rb = CleanUpRoadBits(tile, old_rb); if (old_rb != new_rb) { - RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), ROADTYPE_ROAD, true); + RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), RTT_ROAD, true); + } + } + + /* Possibly change road type */ + if (GetRoadOwner(tile, RTT_ROAD) == OWNER_TOWN) { + RoadType rt = GetTownRoadType(t); + if (rt != GetRoadTypeRoad(tile)) { + SetRoadType(tile, RTT_ROAD, rt); } } @@ -1619,18 +2013,18 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u if (IsLevelCrossing(tile)) trackdirbits = TrackBitsToTrackdirBits(GetCrossingRailBits(tile)); break; - case TRANSPORT_ROAD: - if ((GetRoadTypes(tile) & sub_mode) == 0) break; + case TRANSPORT_ROAD: { + RoadTramType rtt = (RoadTramType)sub_mode; + if (!HasTileRoadType(tile, rtt)) break; switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 }; - RoadType rt = (RoadType)FindFirstBit(sub_mode); - RoadBits bits = GetRoadBits(tile, rt); + RoadBits bits = GetRoadBits(tile, rtt); /* no roadbit at this side of tile, return 0 */ if (side != INVALID_DIAGDIR && (DiagDirToRoadBits(side) & bits) == 0) break; - uint multiplier = drd_to_multiplier[rt == ROADTYPE_TRAM ? DRD_NONE : GetDisallowedRoadDirections(tile)]; + uint multiplier = drd_to_multiplier[(rtt == RTT_TRAM) ? DRD_NONE : GetDisallowedRoadDirections(tile)]; if (!HasRoadWorks(tile)) trackdirbits = (TrackdirBits)(_road_trackbits[bits] * multiplier); break; } @@ -1656,6 +2050,7 @@ static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, u } } break; + } default: break; } @@ -1679,13 +2074,25 @@ static void GetTileDesc_Road(TileIndex tile, TileDesc *td) Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } + switch (GetRoadTileType(tile)) { case ROAD_TILE_CROSSING: { td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING; - RoadTypes rts = GetRoadTypes(tile); rail_owner = GetTileOwner(tile); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); td->railtype = rti->strings.name; @@ -1696,15 +2103,11 @@ static void GetTileDesc_Road(TileIndex tile, TileDesc *td) case ROAD_TILE_DEPOT: td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT; - road_owner = GetTileOwner(tile); // Tile has only one owner, roadtype does not matter td->build_date = Depot::GetByTile(tile)->build_date; break; default: { - RoadTypes rts = GetRoadTypes(tile); - td->str = (HasBit(rts, ROADTYPE_ROAD) ? _road_tile_strings[GetRoadside(tile)] : STR_LAI_ROAD_DESCRIPTION_TRAMWAY); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + td->str = (road_rt != INVALID_ROADTYPE ? _road_tile_strings[GetRoadside(tile)] : STR_LAI_ROAD_DESCRIPTION_TRAMWAY); break; } } @@ -1751,7 +2154,7 @@ static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int rv->state = RVSB_IN_DEPOT; rv->vehstatus |= VS_HIDDEN; rv->direction = ReverseDir(rv->direction); - if (rv->Next() == NULL) VehicleEnterDepot(rv->First()); + if (rv->Next() == nullptr) VehicleEnterDepot(rv->First()); rv->tile = tile; InvalidateWindowData(WC_VEHICLE_DEPOT, rv->tile); @@ -1774,14 +2177,15 @@ static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owne DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); } else { /* A road depot has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ - RoadType rt = (RoadType)FIND_FIRST_BIT(GetRoadTypes(tile)); + RoadType rt = GetRoadTypeRoad(tile); + if (rt == INVALID_ROADTYPE) rt = GetRoadTypeTram(tile); Company::Get(old_owner)->infrastructure.road[rt] -= 2; Company::Get(new_owner)->infrastructure.road[rt] += 2; SetTileOwner(tile, new_owner); - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { - if (GetRoadOwner(tile, rt) == old_owner) { - SetRoadOwner(tile, rt, new_owner); + FOR_ALL_ROADTRAMTYPES(rtt) { + if (GetRoadOwner(tile, rtt) == old_owner) { + SetRoadOwner(tile, rtt, new_owner); } } } @@ -1789,17 +2193,18 @@ static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owne return; } - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* Update all roadtypes, no matter if they are present */ - if (GetRoadOwner(tile, rt) == old_owner) { - if (HasTileRoadType(tile, rt)) { + if (GetRoadOwner(tile, rtt) == old_owner) { + RoadType rt = GetRoadType(tile, rtt); + if (rt != INVALID_ROADTYPE) { /* A level crossing has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ - uint num_bits = IsLevelCrossing(tile) ? 2 : CountBits(GetRoadBits(tile, rt)); + uint num_bits = IsLevelCrossing(tile) ? 2 : CountBits(GetRoadBits(tile, rtt)); Company::Get(old_owner)->infrastructure.road[rt] -= num_bits; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_bits; } - SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } @@ -1858,19 +2263,244 @@ static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlag flags, int z return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } +/** Update power of road vehicle under which is the roadtype being converted */ +static Vehicle *UpdateRoadVehPowerProc(Vehicle *v, void *data) +{ + if (v->type != VEH_ROAD) return nullptr; + + RoadVehicleList *affected_rvs = static_cast(data); + include(*affected_rvs, RoadVehicle::From(v)->First()); + + return nullptr; +} + +/** + * Checks the tile and returns whether the current player is allowed to convert the roadtype to another roadtype + * @param owner the tile owner. + * @param rtt Road/tram type. + * @return whether the road is convertible + */ +static bool CanConvertRoadType(Owner owner, RoadTramType rtt) +{ + return (owner == OWNER_NONE || (owner == OWNER_TOWN && rtt == RTT_ROAD)); +} + +/** + * Convert the ownership of the RoadType of the tile if applyable + * @param tile the tile of which convert ownership + * @param num_pieces the count of the roadbits to assign to the new owner + * @param owner the current owner of the RoadType + * @param from_type the old road type + * @param to_type the new road type + */ +static void ConvertRoadTypeOwner(TileIndex tile, uint num_pieces, Owner owner, RoadType from_type, RoadType to_type) +{ + // Scenario editor, maybe? Don't touch the owners when converting roadtypes... + if (_current_company >= MAX_COMPANIES) return; + + // We can't get a company from invalid owners but we can get ownership of roads without an owner + if (owner >= MAX_COMPANIES && owner != OWNER_NONE) return; + + Company *c; + + switch (owner) { + case OWNER_NONE: + SetRoadOwner(tile, GetRoadTramType(to_type), (Owner)_current_company); + UpdateCompanyRoadInfrastructure(to_type, _current_company, num_pieces); + break; + + default: + c = Company::Get(owner); + c->infrastructure.road[from_type] -= num_pieces; + c->infrastructure.road[to_type] += num_pieces; + DirtyCompanyInfrastructureWindows(c->index); + break; + } +} + +/** + * Convert one road subtype to another. + * Not meant to convert from road to tram. + * + * @param tile end tile of road conversion drag + * @param flags operation to perform + * @param p1 start tile of drag + * @param p2 various bitstuffed elements: + * - p2 = (bit 0..5) new roadtype to convert to. + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + RoadType to_type = Extract(p2); + + TileIndex area_start = p1; + TileIndex area_end = tile; + + if (!ValParamRoadType(to_type)) return CMD_ERROR; + if (area_start >= MapSize()) return CMD_ERROR; + + RoadVehicleList affected_rvs; + RoadTramType rtt = GetRoadTramType(to_type); + + CommandCost cost(EXPENSES_CONSTRUCTION); + CommandCost error = CommandCost((rtt == RTT_TRAM) ? STR_ERROR_NO_SUITABLE_TRAMWAY : STR_ERROR_NO_SUITABLE_ROAD); // by default, there is no road to convert. + bool found_convertible_road = false; // whether we actually did convert any road/tram (see bug #7633) + + TileIterator *iter = new OrthogonalTileIterator(area_start, area_end); + for (; (tile = *iter) != INVALID_TILE; ++(*iter)) { + /* Is road present on tile? */ + if (!MayHaveRoad(tile)) continue; + + /* Converting to the same subtype? */ + RoadType from_type = GetRoadType(tile, rtt); + if (from_type == INVALID_ROADTYPE || from_type == to_type) continue; + + /* Check if there is any infrastructure on tile */ + TileType tt = GetTileType(tile); + switch (tt) { + case MP_STATION: + if (!IsRoadStop(tile)) continue; + break; + case MP_ROAD: + if (IsLevelCrossing(tile) && RoadNoLevelCrossing(to_type)) { + error.MakeError(STR_ERROR_CROSSING_DISALLOWED_ROAD); + continue; + } + break; + case MP_TUNNELBRIDGE: + if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) continue; + break; + default: continue; + } + + /* Trying to convert other's road */ + Owner owner = GetRoadOwner(tile, rtt); + if (!CanConvertRoadType(owner, rtt)) { + CommandCost ret = CheckOwnership(owner, tile); + if (ret.Failed()) { + error = ret; + continue; + } + } + + /* Vehicle on the tile when not converting normal <-> powered + * Tunnels and bridges have special check later */ + if (tt != MP_TUNNELBRIDGE) { + if (!HasPowerOnRoad(from_type, to_type)) { + CommandCost ret = EnsureNoVehicleOnGround(tile); + if (ret.Failed()) { + error = ret; + continue; + } + + if (rtt == RTT_ROAD && owner == OWNER_TOWN) { + error.MakeError(STR_ERROR_INCOMPATIBLE_ROAD); + continue; + } + } + + uint num_pieces = CountBits(GetAnyRoadBits(tile, rtt));; + found_convertible_road = true; + cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type)); + + if (flags & DC_EXEC) { // we can safely convert, too + /* Update the company infrastructure counters. */ + if (!IsRoadStopTile(tile) && CanConvertRoadType(owner, rtt) && owner != OWNER_TOWN) { + ConvertRoadTypeOwner(tile, num_pieces, owner, from_type, to_type); + } + + /* Perform the conversion */ + SetRoadType(tile, rtt, to_type); + MarkTileDirtyByTile(tile); + + /* update power of train on this tile */ + FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); + + if (IsRoadDepotTile(tile)) { + /* Update build vehicle window related to this depot */ + InvalidateWindowData(WC_VEHICLE_DEPOT, tile); + InvalidateWindowData(WC_BUILD_VEHICLE, tile); + } + } + } else { + TileIndex endtile = GetOtherTunnelBridgeEnd(tile); + + /* If both ends of tunnel/bridge are in the range, do not try to convert twice - + * it would cause assert because of different test and exec runs */ + if (endtile < tile) { + if (OrthogonalTileArea(area_start, area_end).Contains(endtile)) continue; + } + + /* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */ + if (!HasPowerOnRoad(from_type, to_type)) { + CommandCost ret = TunnelBridgeIsFree(tile, endtile); + if (ret.Failed()) { + error = ret; + continue; + } + + if (rtt == RTT_ROAD && owner == OWNER_TOWN) { + error.MakeError(STR_ERROR_INCOMPATIBLE_ROAD); + continue; + } + } + + /* There are 2 pieces on *every* tile of the bridge or tunnel */ + uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * 2; + found_convertible_road = true; + cost.AddCost(num_pieces * RoadConvertCost(from_type, to_type)); + + if (flags & DC_EXEC) { + /* Update the company infrastructure counters. */ + if (CanConvertRoadType(owner, rtt) && owner != OWNER_TOWN) { + ConvertRoadTypeOwner(tile, num_pieces, owner, from_type, to_type); + ConvertRoadTypeOwner(endtile, num_pieces, owner, from_type, to_type); + SetTunnelBridgeOwner(tile, endtile, _current_company); + } + + /* Perform the conversion */ + SetRoadType(tile, rtt, to_type); + SetRoadType(endtile, rtt, to_type); + + FindVehicleOnPos(tile, &affected_rvs, &UpdateRoadVehPowerProc); + FindVehicleOnPos(endtile, &affected_rvs, &UpdateRoadVehPowerProc); + + if (IsBridge(tile)) { + MarkBridgeDirty(tile); + } else { + MarkTileDirtyByTile(tile); + MarkTileDirtyByTile(endtile); + } + } + } + } + + if (flags & DC_EXEC) { + /* Roadtype changed, update roadvehicles as when entering different track */ + for (RoadVehicle *v : affected_rvs) { + v->CargoChanged(); + } + } + + delete iter; + return found_convertible_road ? cost : error; +} + + /** Tile callback functions for road tiles */ extern const TileTypeProcs _tile_type_road_procs = { DrawTile_Road, // draw_tile_proc GetSlopePixelZ_Road, // get_slope_z_proc ClearTile_Road, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_Road, // get_tile_desc_proc GetTileTrackStatus_Road, // get_tile_track_status_proc ClickTile_Road, // click_tile_proc - NULL, // animate_tile_proc + nullptr, // animate_tile_proc TileLoop_Road, // tile_loop_proc ChangeTileOwner_Road, // change_tile_owner_proc - NULL, // add_produced_cargo_proc + nullptr, // add_produced_cargo_proc VehicleEnter_Road, // vehicle_enter_tile_proc GetFoundation_Road, // get_foundation_proc TerraformTile_Road, // terraform_tile_proc diff --git a/src/road_func.h b/src/road_func.h index 59e97c4d6b..913660d8d6 100644 --- a/src/road_func.h +++ b/src/road_func.h @@ -13,29 +13,9 @@ #define ROAD_FUNC_H #include "core/bitmath_func.hpp" -#include "road_type.h" +#include "road.h" #include "economy_func.h" - -/** - * Iterate through each set RoadType in a RoadTypes value. - * For more informations see FOR_EACH_SET_BIT_EX. - * - * @param var Loop index variable that stores fallowing set road type. Must be of type RoadType. - * @param road_types The value to iterate through (any expression). - * - * @see FOR_EACH_SET_BIT_EX - */ -#define FOR_EACH_SET_ROADTYPE(var, road_types) FOR_EACH_SET_BIT_EX(RoadType, var, RoadTypes, road_types) - -/** - * Whether the given roadtype is valid. - * @param rt the roadtype to check for validness - * @return true if and only if valid - */ -static inline bool IsValidRoadType(RoadType rt) -{ - return rt == ROADTYPE_ROAD || rt == ROADTYPE_TRAM; -} +#include "transparency.h" /** * Whether the given roadtype is valid. @@ -47,32 +27,6 @@ static inline bool IsValidRoadBits(RoadBits r) return r < ROAD_END; } -/** - * Maps a RoadType to the corresponding RoadTypes value - * - * @param rt the roadtype to get the roadtypes from - * @return the roadtypes with the given roadtype - */ -static inline RoadTypes RoadTypeToRoadTypes(RoadType rt) -{ - assert(IsValidRoadType(rt)); - return (RoadTypes)(1 << rt); -} - -/** - * Returns the RoadTypes which are not present in the given RoadTypes - * - * This function returns the complement of a given RoadTypes. - * - * @param r The given RoadTypes - * @return The complement of the given RoadTypes - */ -static inline RoadTypes ComplementRoadTypes(RoadTypes r) -{ - return (RoadTypes)(ROADTYPES_ALL ^ r); -} - - /** * Calculate the complement of a RoadBits value * @@ -167,19 +121,45 @@ static inline RoadBits AxisToRoadBits(Axis a) * Calculates the maintenance cost of a number of road bits. * @param roadtype Road type to get the cost for. * @param num Number of road bits. + * @param total_num Total number of road bits of all road/tram-types. * @return Total cost. */ -static inline Money RoadMaintenanceCost(RoadType roadtype, uint32 num) +static inline Money RoadMaintenanceCost(RoadType roadtype, uint32 num, uint32 total_num) { - assert(IsValidRoadType(roadtype)); - return (_price[PR_INFRASTRUCTURE_ROAD] * (roadtype == ROADTYPE_TRAM ? 3 : 2) * num * (1 + IntSqrt(num))) >> 9; // 2 bits fraction for the multiplier and 7 bits scaling. + assert(roadtype < ROADTYPE_END); + return (_price[PR_INFRASTRUCTURE_ROAD] * GetRoadTypeInfo(roadtype)->maintenance_multiplier * num * (1 + IntSqrt(total_num))) >> 12; } -bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts); -bool ValParamRoadType(const RoadType rt); -RoadTypes GetCompanyRoadtypes(const CompanyID company); +/** + * Test if a road type has catenary + * @param roadtype Road type to test + */ +static inline bool HasRoadCatenary(RoadType roadtype) +{ + assert(roadtype < ROADTYPE_END); + return HasBit(GetRoadTypeInfo(roadtype)->flags, ROTF_CATENARY); +} + +/** + * Test if we should draw road catenary + * @param roadtype Road type to test + */ +static inline bool HasRoadCatenaryDrawn(RoadType roadtype) +{ + return HasRoadCatenary(roadtype) && !IsInvisibilitySet(TO_CATENARY); +} + +bool HasRoadTypeAvail(CompanyID company, RoadType roadtype); +bool ValParamRoadType(RoadType roadtype); +RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces = true); +RoadTypes GetRoadTypes(bool introduces); +RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, Date date); void UpdateLevelCrossing(TileIndex tile, bool sound = true); +void UpdateCompanyRoadInfrastructure(RoadType rt, Owner o, int count); + +struct TileInfo; +void DrawRoadOverlays(const TileInfo *ti, PaletteID pal, const RoadTypeInfo *road_rti, const RoadTypeInfo *tram_rit, uint road_offset, uint tram_offset); bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir); diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 1926a566c6..fbdd56947d 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -32,6 +32,11 @@ #include "road_gui.h" #include "zoom_func.h" #include "industry.h" +#include "engine_base.h" +#include "strings_func.h" +#include "core/geometry_func.hpp" +#include "date_func.h" + #include "widgets/road_widget.h" #include "table/strings.h" @@ -113,52 +118,6 @@ void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p } } -/** Structure holding information per roadtype for several functions */ -struct RoadTypeInfo { - StringID err_build_road; ///< Building a normal piece of road - StringID err_remove_road; ///< Removing a normal piece of road - StringID err_depot; ///< Building a depot - StringID err_build_station[2]; ///< Building a bus or truck station - StringID err_remove_station[2]; ///< Removing of a bus or truck station - - StringID picker_title[2]; ///< Title for the station picker for bus or truck stations - StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations - - SpriteID cursor_nesw; ///< Cursor for building NE and SW bits - SpriteID cursor_nwse; ///< Cursor for building NW and SE bits - SpriteID cursor_autoroad; ///< Cursor for building autoroad -}; - -/** What errors/cursors must be shown for several types of roads */ -static const RoadTypeInfo _road_type_infos[] = { - { - STR_ERROR_CAN_T_BUILD_ROAD_HERE, - STR_ERROR_CAN_T_REMOVE_ROAD_FROM, - STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, - { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, - { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, - { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, - { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, - - SPR_CURSOR_ROAD_NESW, - SPR_CURSOR_ROAD_NWSE, - SPR_CURSOR_AUTOROAD, - }, - { - STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, - STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, - STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, - { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, - { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, - { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, - { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, - - SPR_CURSOR_TRAMWAY_NESW, - SPR_CURSOR_TRAMWAY_NWSE, - SPR_CURSOR_AUTOTRAM, - }, -}; - /** * If required, connects a new structure to an existing road or tram by building the missing roadbit. * @param tile Tile containing the structure to connect. @@ -169,7 +128,7 @@ void ConnectRoadToStructure(TileIndex tile, DiagDirection direction) tile += TileOffsByDiagDir(direction); /* if there is a roadpiece just outside of the station entrance, build a connecting route */ if (IsNormalRoadTile(tile)) { - if (GetRoadBits(tile, _cur_roadtype) != ROAD_NONE) { + if (GetRoadBits(tile, GetRoadTramType(_cur_roadtype)) != ROAD_NONE) { DoCommandP(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, CMD_BUILD_ROAD); } } @@ -193,9 +152,10 @@ void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2 * bit 8..15: Length of the road stop. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 1: 0 For normal stops, 1 for drive-through. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. - * bit 6..7: Entrance direction (#DiagDirection). + * bit 2: Allow stations directly adjacent to other stations. + * bit 3..4: Entrance direction (#DiagDirection) for normal stops. + * bit 3: #Axis of the road for drive-through stops. + * bit 5..9: The roadtype. * bit 16..31: Station ID to join (NEW_STATION if build new one). * @param cmd Unused. * @see CmdBuildRoadStop @@ -204,7 +164,7 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, { if (result.Failed()) return; - DiagDirection dir = (DiagDirection)GB(p2, 6, 2); + DiagDirection dir = (DiagDirection)GB(p2, 3, 2); if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); TileArea roadstop_area(tile, GB(p1, 0, 8), GB(p1, 8, 8)); @@ -219,10 +179,11 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, static RoadBits FindRoadsToConnect(TileIndex tile) { RoadBits bits = ROAD_NONE; DiagDirection ddir; + auto cur_rtt = GetRoadTramType(_cur_roadtype); // Prioritize roadbits that head in this direction for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { TileIndex cur_tile = TileAddByDiagDir(tile, ddir); - if (GetAnyRoadBits(cur_tile, _cur_roadtype, true) & + if (GetAnyRoadBits(cur_tile, cur_rtt, true) & DiagDirToRoadBits(ReverseDiagDir(ddir))) { bits |= DiagDirToRoadBits(ddir); @@ -234,7 +195,7 @@ static RoadBits FindRoadsToConnect(TileIndex tile) { // Try to connect to any road passing by for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { TileIndex cur_tile = TileAddByDiagDir(tile, ddir); - if (HasTileRoadType(cur_tile, _cur_roadtype) && (GetTileType(cur_tile) == MP_ROAD) && + if (GetTileType(cur_tile) == MP_ROAD && HasTileRoadType(cur_tile, cur_rtt) && (GetRoadTileType(cur_tile) == ROAD_TILE_NORMAL)) { bits |= DiagDirToRoadBits(ddir); } @@ -320,8 +281,8 @@ static DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area) { * @param start_tile First tile of the area. * @param end_tile Last tile of the area. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. + * bit 2: Allow stations directly adjacent to other stations. + * bit 5..10: The roadtypes. * @param cmd Command to use. * @see CcRoadStop() */ @@ -352,7 +313,7 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u ddir = AutodetectDriveThroughRoadStopDirection(ta); } } - p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. + p2 |= ddir << 3; // Set the DiagDirecion into p2 bits 3 and 4. CommandContainer cmdcont = { ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop, "" }; ShowSelectStationIfNeeded(cmdcont, ta); @@ -418,7 +379,7 @@ static bool RoadToolbar_CtrlChanged(Window *w) if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false; /* allow ctrl to switch remove mode only for these widgets */ - for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_FULLROAD; i++) { + for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) { if (w->GetWidget(i) && w->IsWidgetLowered(i)) { ToggleRoadButton_Remove(w); return true; @@ -430,15 +391,20 @@ static bool RoadToolbar_CtrlChanged(Window *w) /** Road toolbar window handler. */ struct BuildRoadToolbarWindow : Window { - int last_started_action; ///< Last started user action. + RoadType roadtype; ///< Road type to build. + const RoadTypeInfo *rti; ///< Information about current road type + int last_started_action; ///< Last started user action. BuildRoadToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { + this->Initialize(_cur_roadtype); this->InitNested(window_number); - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetupRoadToolbar(); + this->SetWidgetDisabledState(WID_ROT_REMOVE, true); + + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, true); + } this->OnInvalidateData(); this->last_started_action = WIDGET_LIST_END; @@ -448,6 +414,7 @@ struct BuildRoadToolbarWindow : Window { ~BuildRoadToolbarWindow() { + if (_game_mode == GM_NORMAL && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -456,11 +423,12 @@ struct BuildRoadToolbarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; - bool can_build = CanBuildVehicleInfrastructure(VEH_ROAD); + if (_game_mode != GM_EDITOR && !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) delete this; + bool can_build = _game_mode != GM_EDITOR; this->SetWidgetsDisabledState(!can_build, WID_ROT_DEPOT, WID_ROT_BUS_STATION, @@ -473,6 +441,53 @@ struct BuildRoadToolbarWindow : Window { } } + void Initialize(RoadType roadtype) + { + assert(roadtype < ROADTYPE_END); + this->roadtype = roadtype; + this->rti = GetRoadTypeInfo(this->roadtype); + } + + /** + * Configures the road toolbar for roadtype given + * @param roadtype the roadtype to display + */ + void SetupRoadToolbar() + { + this->GetWidget(WID_ROT_ROAD_X)->widget_data = rti->gui_sprites.build_x_road; + this->GetWidget(WID_ROT_ROAD_Y)->widget_data = rti->gui_sprites.build_y_road; + this->GetWidget(WID_ROT_AUTOROAD)->widget_data = rti->gui_sprites.auto_road; + if (_game_mode != GM_EDITOR) { + this->GetWidget(WID_ROT_DEPOT)->widget_data = rti->gui_sprites.build_depot; + } + this->GetWidget(WID_ROT_CONVERT_ROAD)->widget_data = rti->gui_sprites.convert_road; + this->GetWidget(WID_ROT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel; + } + + /** + * Switch to another road type. + * @param roadtype New road type. + */ + void ModifyRoadType(RoadType roadtype) + { + this->Initialize(roadtype); + this->SetupRoadToolbar(); + this->ReInit(); + } + + void SetStringParameters(int widget) const override + { + if (widget == WID_ROT_CAPTION) { + if (this->rti->max_speed > 0) { + SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY); + SetDParam(1, this->rti->strings.toolbar_caption); + SetDParam(2, this->rti->max_speed / 2); + } else { + SetDParam(0, this->rti->strings.toolbar_caption); + } + } + } + /** * Update the remove button lowered state of the road toolbar * @@ -485,8 +500,11 @@ struct BuildRoadToolbarWindow : Window { * Both are only valid if they are able to apply as options. */ switch (clicked_widget) { case WID_ROT_REMOVE: - this->RaiseWidget(WID_ROT_ONE_WAY); - this->SetWidgetDirty(WID_ROT_ONE_WAY); + if (RoadTypeIsRoad(this->roadtype)) { + this->RaiseWidget(WID_ROT_ONE_WAY); + this->SetWidgetDirty(WID_ROT_ONE_WAY); + } + break; case WID_ROT_ONE_WAY: @@ -496,73 +514,51 @@ struct BuildRoadToolbarWindow : Window { case WID_ROT_BUS_STATION: case WID_ROT_TRUCK_STATION: - this->DisableWidget(WID_ROT_ONE_WAY); + if (RoadTypeIsRoad(this->roadtype)) this->DisableWidget(WID_ROT_ONE_WAY); this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); break; case WID_ROT_ROAD_X: case WID_ROT_ROAD_Y: case WID_ROT_AUTOROAD: - case WID_ROT_FULLROAD: - this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget), - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, !this->IsWidgetLowered(clicked_widget)); + } break; default: /* When any other buttons than road/station, raise and * disable the removal button */ - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); - this->SetWidgetsLoweredState(false, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetWidgetDisabledState(WID_ROT_REMOVE, true); + this->SetWidgetLoweredState(WID_ROT_REMOVE, false); + + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, true); + this->SetWidgetLoweredState(WID_ROT_ONE_WAY, false); + } + break; } } - virtual void DrawWidget(const Rect &r, int widget) const + void OnClick(Point pt, int widget, int click_count) override { - if (widget == WID_ROT_FULLROAD) { - Dimension d = GetSpriteSize(SPR_BLOT); - uint offset = this->IsWidgetLowered(WID_ROT_FULLROAD) ? 1 : 0; - DrawSprite(SPR_BLOT, PALETTE_TO_GREY, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset); - } - } - - - virtual void OnClick(Point pt, int widget, int click_count) - { - static bool fullroad_warned = false; _remove_button_clicked = false; _one_way_button_clicked = false; switch (widget) { case WID_ROT_ROAD_X: - HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT); + HandlePlacePushButton(this, WID_ROT_ROAD_X, this->rti->cursor.road_nwse, HT_RECT); this->last_started_action = widget; break; case WID_ROT_ROAD_Y: - HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT); + HandlePlacePushButton(this, WID_ROT_ROAD_Y, this->rti->cursor.road_swne, HT_RECT); this->last_started_action = widget; break; case WID_ROT_AUTOROAD: - HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); - this->last_started_action = widget; - break; - - case WID_ROT_FULLROAD: - HandlePlacePushButton(this, WID_ROT_FULLROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); - if (!fullroad_warned) { - ShowGoalQuestion(0, 2 /* WARNING */, 2 /* OK */, "Full-tile autoroad tool is deprecated and will be removed in next release.\n Use regular autoroad tool instead."); - fullroad_warned = true; - } - + HandlePlacePushButton(this, WID_ROT_AUTOROAD, this->rti->cursor.autoroad, HT_RECT); this->last_started_action = widget; break; @@ -572,15 +568,15 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_DEPOT: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; - if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) { + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) return; + if (HandlePlacePushButton(this, WID_ROT_DEPOT, this->rti->cursor.depot, HT_RECT)) { ShowRoadDepotPicker(this); this->last_started_action = widget; } break; case WID_ROT_BUS_STATION: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) return; if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) { ShowRVStationPicker(this, ROADSTOP_BUS); this->last_started_action = widget; @@ -588,7 +584,7 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_TRUCK_STATION: - if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; + if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD, GetRoadTramType(this->roadtype))) return; if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) { ShowRVStationPicker(this, ROADSTOP_TRUCK); this->last_started_action = widget; @@ -608,7 +604,7 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_BUILD_TUNNEL: - HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL); + HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, this->rti->cursor.tunnel, HT_SPECIAL); this->last_started_action = widget; break; @@ -620,23 +616,28 @@ struct BuildRoadToolbarWindow : Window { if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; + case WID_ROT_CONVERT_ROAD: + HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD, this->rti->cursor.convert_road, HT_RECT); + this->last_started_action = widget; + break; + default: NOT_REACHED(); } this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget); if (_ctrl_pressed) RoadToolbar_CtrlChanged(this); } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection return Window::OnHotkey(hotkey); } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { DiagDirection ddir; _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); - _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); + _one_way_button_clicked = RoadTypeIsRoad(this->roadtype) ? this->IsWidgetLowered(WID_ROT_ONE_WAY) : false; switch (this->last_started_action) { case WID_ROT_ROAD_X: _place_road_flag = RF_DIR_X; @@ -657,13 +658,6 @@ struct BuildRoadToolbarWindow : Window { VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD); break; - case WID_ROT_FULLROAD: - _place_road_flag = RF_NONE; - if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; - if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; - VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_FULLROAD); - break; - case WID_ROT_DEMOLISH: PlaceProc_DemolishArea(tile); break; @@ -674,7 +668,7 @@ struct BuildRoadToolbarWindow : Window { ddir = AutodetectRoadObjectDirection(tile); } DoCommandP(tile, _cur_roadtype << 2 | ddir, 0, - CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); + CMD_BUILD_ROAD_DEPOT | CMD_MSG(this->rti->strings.err_depot), CcRoadDepot); if (_ctrl_pressed == _settings_client.gui.persistent_depottools) ResetObjectToPlace(); break; @@ -692,23 +686,30 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_BUILD_TUNNEL: - DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, + DoCommandP(tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); break; + case WID_ROT_CONVERT_ROAD: + VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_ROAD); + break; + default: NOT_REACHED(); } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { + if (_game_mode != GM_EDITOR && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); + this->RaiseButtons(); - this->SetWidgetsDisabledState(true, - WID_ROT_REMOVE, - WID_ROT_ONE_WAY, - WIDGET_LIST_END); + this->SetWidgetDisabledState(WID_ROT_REMOVE, true); this->SetWidgetDirty(WID_ROT_REMOVE); - this->SetWidgetDirty(WID_ROT_ONE_WAY); + + if (RoadTypeIsRoad(this->roadtype)) { + this->SetWidgetDisabledState(WID_ROT_ONE_WAY, true); + this->SetWidgetDirty(WID_ROT_ONE_WAY); + } DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD); DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD); @@ -717,7 +718,7 @@ struct BuildRoadToolbarWindow : Window { DeleteWindowByClass(WC_BUILD_BRIDGE); } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { /* Here we update the end tile flags * of the road placement actions. @@ -735,7 +736,6 @@ struct BuildRoadToolbarWindow : Window { break; case DDSP_PLACE_AUTOROAD: - case DDSP_PLACE_FULLROAD: _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X); if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; @@ -775,14 +775,14 @@ struct BuildRoadToolbarWindow : Window { } } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1) { switch (select_proc) { default: NOT_REACHED(); case DDSP_BUILD_BRIDGE: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); - ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); + ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, _cur_roadtype); break; case DDSP_DEMOLISH_AREA: @@ -796,36 +796,16 @@ struct BuildRoadToolbarWindow : Window { * Use the first three bits (0x07) if dir == Y * else use the last 2 bits (X dir has * not the 3rd bit set) */ + + /* Even if _cur_roadtype_id is a uint8 we only use 5 bits so + * we could ignore the last 3 bits and reuse them for other + * flags */ _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); - DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), + DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 10), _remove_button_clicked ? - CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : - CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound_SPLAT_OTHER); - break; - - case DDSP_PLACE_FULLROAD: - if (start_tile == end_tile || _remove_button_clicked) { - _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); - DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), - _remove_button_clicked ? - CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : - CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound_SPLAT_OTHER); - } else { - _place_road_flag &= RF_DIR_Y; - RoadBits road_dir = _place_road_flag ? ROAD_Y : ROAD_X; - // if (start_tile > end_tile) Swap(start_tile, end_tile); - RoadBits start_extra_rb = GetAnyRoadBits(start_tile, _cur_roadtype, false) & ~road_dir; - RoadBits end_extra_rb = GetAnyRoadBits(end_tile, _cur_roadtype, false) & ~road_dir; - this->TryToRemoveExtraRoadBits(start_tile, start_extra_rb); - this->TryToRemoveExtraRoadBits(end_tile, end_extra_rb); - if ((bool)start_extra_rb != (start_tile > end_tile)) _place_road_flag |= RF_START_HALFROAD_Y; - if (!end_extra_rb != (start_tile > end_tile)) _place_road_flag |= RF_END_HALFROAD_Y; - DoCommandP(start_tile, end_tile, - _place_road_flag | (_cur_roadtype << 3) | - (_one_way_button_clicked << 5) | (1 << 6), - CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound_SPLAT_OTHER); - } + CMD_REMOVE_LONG_ROAD | CMD_MSG(this->rti->strings.err_remove_road) : + CMD_BUILD_LONG_ROAD | CMD_MSG(this->rti->strings.err_build_road), CcPlaySound_SPLAT_OTHER); break; case DDSP_BUILD_BUSSTOP: @@ -833,9 +813,9 @@ struct BuildRoadToolbarWindow : Window { if (this->IsWidgetLowered(WID_ROT_BUS_STATION)) { if (_remove_button_clicked) { TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound_SPLAT_OTHER); + DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_BUS]), CcPlaySound_SPLAT_OTHER); } else { - PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS])); + PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_BUS])); } } break; @@ -845,56 +825,62 @@ struct BuildRoadToolbarWindow : Window { if (this->IsWidgetLowered(WID_ROT_TRUCK_STATION)) { if (_remove_button_clicked) { TileArea ta(start_tile, end_tile); - DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_SPLAT_OTHER); + DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(this->rti->strings.err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_SPLAT_OTHER); } else { - PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_TRUCK])); + PlaceRoadStop(start_tile, end_tile, _cur_roadtype << 5 | (_ctrl_pressed << 2) | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(this->rti->strings.err_build_station[ROADSTOP_TRUCK])); } } break; + + case DDSP_CONVERT_ROAD: + DoCommandP(end_tile, start_tile, _cur_roadtype, CMD_CONVERT_ROAD | CMD_MSG(rti->strings.err_convert_road), CcPlaySound_SPLAT_OTHER); + break; } } } - virtual void OnPlacePresize(Point pt, TileIndex tile) + void OnPlacePresize(Point pt, TileIndex tile) override { - DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); + DoCommand(tile, _cur_roadtype | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); } - virtual EventState OnCTRLStateChange() + EventState OnCTRLStateChange() override { if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED; return ES_NOT_HANDLED; } - static HotkeyList hotkeys; + static HotkeyList road_hotkeys; + static HotkeyList tram_hotkeys; }; /** * Handler for global hotkeys of the BuildRoadToolbarWindow. * @param hotkey Hotkey + * @param last_build Last build road type * @return ES_HANDLED if hotkey was accepted. */ +static EventState RoadTramToolbarGlobalHotkeys(int hotkey, RoadType last_build) +{ + Window *w = (_game_mode == GM_NORMAL) ? ShowBuildRoadToolbar(last_build) : ShowBuildRoadScenToolbar(last_build); + if (w == nullptr) return ES_NOT_HANDLED; + return w->OnHotkey(hotkey); +} + static EventState RoadToolbarGlobalHotkeys(int hotkey) { - Window *w = NULL; - switch (_game_mode) { - case GM_NORMAL: { - extern RoadType _last_built_roadtype; - w = ShowBuildRoadToolbar(_last_built_roadtype); - break; - } + if (_game_mode == GM_NORMAL && !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_ROAD)) return ES_NOT_HANDLED; - case GM_EDITOR: - w = ShowBuildRoadScenToolbar(); - break; + extern RoadType _last_built_roadtype; + return RoadTramToolbarGlobalHotkeys(hotkey, _last_built_roadtype); +} - default: - break; - } - - if (w == NULL) return ES_NOT_HANDLED; - return w->OnHotkey(hotkey); +static EventState TramToolbarGlobalHotkeys(int hotkey) +{ + if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM)) return ES_NOT_HANDLED; + extern RoadType _last_built_tramtype; + return RoadTramToolbarGlobalHotkeys(hotkey, _last_built_tramtype); } static Hotkey roadtoolbar_hotkeys[] = { @@ -906,19 +892,35 @@ static Hotkey roadtoolbar_hotkeys[] = { Hotkey('6', "bus_station", WID_ROT_BUS_STATION), Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), Hotkey('8', "oneway", WID_ROT_ONE_WAY), - Hotkey('9', "fullroad", WID_ROT_FULLROAD), Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), Hotkey('R', "remove", WID_ROT_REMOVE), + Hotkey('C', "convert", WID_ROT_CONVERT_ROAD), HOTKEY_LIST_END }; -HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); +HotkeyList BuildRoadToolbarWindow::road_hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); + +static Hotkey tramtoolbar_hotkeys[] = { + Hotkey('1', "build_x", WID_ROT_ROAD_X), + Hotkey('2', "build_y", WID_ROT_ROAD_Y), + Hotkey('3', "autoroad", WID_ROT_AUTOROAD), + Hotkey('4', "demolish", WID_ROT_DEMOLISH), + Hotkey('5', "depot", WID_ROT_DEPOT), + Hotkey('6', "bus_station", WID_ROT_BUS_STATION), + Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), + Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), + Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), + Hotkey('R', "remove", WID_ROT_REMOVE), + Hotkey('C', "convert", WID_ROT_CONVERT_ROAD), + HOTKEY_LIST_END +}; +HotkeyList BuildRoadToolbarWindow::tram_hotkeys("tramtoolbar", tramtoolbar_hotkeys, TramToolbarGlobalHotkeys); static const NWidgetPart _nested_build_road_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -939,14 +941,14 @@ static const NWidgetPart _nested_build_road_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), - NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_FULLROAD), - SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_FULLROAD), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD), EndContainer(), }; @@ -955,13 +957,13 @@ static WindowDesc _build_road_desc( WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_widgets, lengthof(_nested_build_road_widgets), - &BuildRoadToolbarWindow::hotkeys + &BuildRoadToolbarWindow::road_hotkeys ); static const NWidgetPart _nested_build_tramway_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -980,13 +982,14 @@ static const NWidgetPart _nested_build_tramway_widgets[] = { NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), - NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM), EndContainer(), }; @@ -995,7 +998,7 @@ static WindowDesc _build_tramway_desc( WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets), - &BuildRoadToolbarWindow::hotkeys + &BuildRoadToolbarWindow::tram_hotkeys ); /** @@ -1003,21 +1006,23 @@ static WindowDesc _build_tramway_desc( * * If the terraform toolbar is linked to the toolbar, that window is also opened. * - * @return newly opened road toolbar, or NULL if the toolbar could not be opened. + * @return newly opened road toolbar, or nullptr if the toolbar could not be opened. */ Window *ShowBuildRoadToolbar(RoadType roadtype) { - if (!Company::IsValidID(_local_company)) return NULL; - _cur_roadtype = roadtype; + if (!Company::IsValidID(_local_company)) return nullptr; + if (!ValParamRoadType(roadtype)) return nullptr; DeleteWindowByClass(WC_BUILD_TOOLBAR); - return AllocateWindowDescFront(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); + _cur_roadtype = roadtype; + + return AllocateWindowDescFront(RoadTypeIsRoad(_cur_roadtype) ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); } static const NWidgetPart _nested_build_road_scen_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), - NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -1038,6 +1043,8 @@ static const NWidgetPart _nested_build_road_scen_widgets[] = { SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD), EndContainer(), }; @@ -1046,17 +1053,54 @@ static WindowDesc _build_road_scen_desc( WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets), - &BuildRoadToolbarWindow::hotkeys + &BuildRoadToolbarWindow::road_hotkeys +); + +static const NWidgetPart _nested_build_tramway_scen_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), + NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_ROT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), + NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), + SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), + NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_CONVERT_ROAD), + SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM), + EndContainer(), +}; + +static WindowDesc _build_tramway_scen_desc( + WDP_AUTO, "toolbar_tram_scen", 0, 0, + WC_SCEN_BUILD_TOOLBAR, WC_NONE, + WDF_CONSTRUCTION, + _nested_build_tramway_scen_widgets, lengthof(_nested_build_tramway_scen_widgets), + &BuildRoadToolbarWindow::tram_hotkeys ); /** * Show the road building toolbar in the scenario editor. - * @return The just opened toolbar, or \c NULL if the toolbar was already open. + * @return The just opened toolbar, or \c nullptr if the toolbar was already open. */ -Window *ShowBuildRoadScenToolbar() +Window *ShowBuildRoadScenToolbar(RoadType roadtype) { - _cur_roadtype = ROADTYPE_ROAD; - return AllocateWindowDescFront(&_build_road_scen_desc, TRANSPORT_ROAD); + DeleteWindowById(WC_SCEN_BUILD_TOOLBAR, TRANSPORT_ROAD); + _cur_roadtype = roadtype; + + return AllocateWindowDescFront(RoadTypeIsRoad(_cur_roadtype) ? &_build_road_scen_desc : &_build_tramway_scen_desc, TRANSPORT_ROAD); } struct BuildRoadDepotWindow : public PickerWindowBase { @@ -1065,7 +1109,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { this->CreateNestedTree(); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); - if ( _cur_roadtype == ROADTYPE_TRAM) { + if (RoadTypeIsTram(_cur_roadtype)) { this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_AUTO; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; } @@ -1073,7 +1117,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { this->FinishInitNested(TRANSPORT_ROAD); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BROD_DEPOT_NW: @@ -1091,14 +1135,14 @@ struct BuildRoadDepotWindow : public PickerWindowBase { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return; DrawRoadDepotSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), (DiagDirection)(widget - WID_BROD_DEPOT_NE + DIAGDIR_NE), _cur_roadtype); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BROD_DEPOT_NW: @@ -1156,7 +1200,7 @@ static const NWidgetPart _nested_build_road_depot_widgets[] = { }; static WindowDesc _build_road_depot_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_road_depot_widgets, lengthof(_nested_build_road_depot_widgets) @@ -1173,16 +1217,17 @@ struct BuildRoadStationWindow : public PickerWindowBase { this->CreateNestedTree(); /* Trams don't have non-drivethrough stations */ - if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) { + if (RoadTypeIsTram(_cur_roadtype) && _road_station_picker_orientation < DIAGDIR_END) { _road_station_picker_orientation = DIAGDIR_END; } - if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation == (DiagDirection)(DIAGDIR_END + 2)) { + if (RoadTypeIsTram(_cur_roadtype) && _road_station_picker_orientation == (DiagDirection)(DIAGDIR_END + 2)) { _road_station_picker_orientation = (DiagDirection)(DIAGDIR_END + 3); } + const RoadTypeInfo *rti = GetRoadTypeInfo(_cur_roadtype); + this->GetWidget(WID_BROS_CAPTION)->widget_data = rti->strings.picker_title[rs]; - this->GetWidget(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs]; - for (uint i = (_cur_roadtype == ROADTYPE_TRAM ? WID_BROS_STATION_X : WID_BROS_STATION_NE); i < WID_BROS_STATION_AUTO; i++) { - this->GetWidget(i)->tool_tip = _road_type_infos[_cur_roadtype].picker_tooltip[rs]; + for (uint i = RoadTypeIsTram(_cur_roadtype) ? WID_BROS_STATION_X : WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) { + this->GetWidget(i)->tool_tip = rti->strings.picker_tooltip[rs]; } this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); @@ -1198,7 +1243,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { DeleteWindowById(WC_SELECT_STATION, 0); } - virtual void OnPaint() + void OnPaint() override { this->DrawWidgets(); @@ -1225,7 +1270,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_BROS_STATION_NE: @@ -1241,7 +1286,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { size->width = ScaleGUITrad(128) + 6; break; case WID_BROS_STATION_XY_AUTO: - if (_cur_roadtype == ROADTYPE_TRAM) + if (RoadTypeIsTram(_cur_roadtype)) size->width = ScaleGUITrad(128) + 6; else size->width = ScaleGUITrad(64) + 2; @@ -1251,15 +1296,15 @@ struct BuildRoadStationWindow : public PickerWindowBase { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK; - StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); + StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, _cur_roadtype, widget - WID_BROS_STATION_NE); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BROS_STATION_NE: @@ -1292,7 +1337,7 @@ struct BuildRoadStationWindow : public PickerWindowBase { } } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { CheckRedrawStationCoverage(this); } @@ -1346,7 +1391,7 @@ static const NWidgetPart _nested_road_station_picker_widgets[] = { }; static WindowDesc _road_station_picker_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUS_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_road_station_picker_widgets, lengthof(_nested_road_station_picker_widgets) @@ -1390,7 +1435,7 @@ static const NWidgetPart _nested_tram_station_picker_widgets[] = { }; static WindowDesc _tram_station_picker_desc( - WDP_AUTO, NULL, 0, 0, + WDP_AUTO, nullptr, 0, 0, WC_BUS_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_tram_station_picker_widgets, lengthof(_nested_tram_station_picker_widgets) @@ -1398,7 +1443,7 @@ static WindowDesc _tram_station_picker_desc( static void ShowRVStationPicker(Window *parent, RoadStopType rs) { - new BuildRoadStationWindow(_cur_roadtype == ROADTYPE_ROAD ? &_road_station_picker_desc : &_tram_station_picker_desc, parent, rs); + new BuildRoadStationWindow(RoadTypeIsRoad(_cur_roadtype) ? &_road_station_picker_desc : &_tram_station_picker_desc, parent, rs); } void InitializeRoadGui() @@ -1406,3 +1451,118 @@ void InitializeRoadGui() _road_depot_orientation = (DiagDirection)(DIAGDIR_NW + 1); _road_station_picker_orientation = (DiagDirection)(DIAGDIR_END + 3); } + +/** + * I really don't know why rail_gui.cpp has this too, shouldn't be included in the other one? + */ +void InitializeRoadGUI() +{ + BuildRoadToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_ROAD)); + if (w != nullptr) w->ModifyRoadType(_cur_roadtype); +} + +DropDownList GetRoadTypeDropDownList(RoadTramTypes rtts, bool for_replacement, bool all_option) +{ + RoadTypes used_roadtypes; + RoadTypes avail_roadtypes; + + const Company *c = Company::Get(_local_company); + + /* Find the used roadtypes. */ + if (for_replacement) { + avail_roadtypes = GetCompanyRoadTypes(c->index, false); + used_roadtypes = GetRoadTypes(false); + } else { + avail_roadtypes = c->avail_roadtypes; + used_roadtypes = GetRoadTypes(true); + } + + /* Filter listed road types */ + if (!HasBit(rtts, RTT_ROAD)) used_roadtypes &= _roadtypes_type; + if (!HasBit(rtts, RTT_TRAM)) used_roadtypes &= ~_roadtypes_type; + + DropDownList list; + + if (all_option) { + list.emplace_back(new DropDownListStringItem(STR_REPLACE_ALL_ROADTYPE, INVALID_ROADTYPE, false)); + } + + Dimension d = { 0, 0 }; + RoadType rt; + /* Get largest icon size, to ensure text is aligned on each menu item. */ + if (!for_replacement) { + FOR_ALL_SORTED_ROADTYPES(rt) { + if (!HasBit(used_roadtypes, rt)) continue; + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_road)); + } + } + + FOR_ALL_SORTED_ROADTYPES(rt) { + /* If it's not used ever, don't show it to the user. */ + if (!HasBit(used_roadtypes, rt)) continue; + + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + + DropDownListParamStringItem *item; + if (for_replacement) { + item = new DropDownListParamStringItem(rti->strings.replace_text, rt, !HasBit(avail_roadtypes, rt)); + } else { + StringID str = rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING; + DropDownListIconItem *iconitem = new DropDownListIconItem(rti->gui_sprites.build_x_road, PAL_NONE, str, rt, !HasBit(avail_roadtypes, rt)); + iconitem->SetDimension(d); + item = iconitem; + } + item->SetParam(0, rti->strings.menu_text); + item->SetParam(1, rti->max_speed / 2); + list.emplace_back(item); + } + + if (list.size() == 0) { + /* Empty dropdowns are not allowed */ + list.emplace_back(new DropDownListStringItem(STR_NONE, INVALID_ROADTYPE, true)); + } + + return list; +} + +DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts) +{ + RoadTypes avail_roadtypes = GetRoadTypes(false); + avail_roadtypes = AddDateIntroducedRoadTypes(avail_roadtypes, _date); + RoadTypes used_roadtypes = GetRoadTypes(true); + + /* Filter listed road types */ + if (!HasBit(rtts, RTT_ROAD)) used_roadtypes &= _roadtypes_type; + if (!HasBit(rtts, RTT_TRAM)) used_roadtypes &= ~_roadtypes_type; + + DropDownList list; + + /* If it's not used ever, don't show it to the user. */ + Dimension d = { 0, 0 }; + RoadType rt; + FOR_ALL_SORTED_ROADTYPES(rt) { + if (!HasBit(used_roadtypes, rt)) continue; + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_road)); + } + FOR_ALL_SORTED_ROADTYPES(rt) { + if (!HasBit(used_roadtypes, rt)) continue; + + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + + StringID str = rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING; + DropDownListIconItem *item = new DropDownListIconItem(rti->gui_sprites.build_x_road, PAL_NONE, str, rt, !HasBit(avail_roadtypes, rt)); + item->SetDimension(d); + item->SetParam(0, rti->strings.menu_text); + item->SetParam(1, rti->max_speed); + list.emplace_back(item); + } + + if (list.size() == 0) { + /* Empty dropdowns are not allowed */ + list.emplace_back(new DropDownListStringItem(STR_NONE, -1, true)); + } + + return list; +} diff --git a/src/road_gui.h b/src/road_gui.h index c56443c375..3f0b8f9006 100644 --- a/src/road_gui.h +++ b/src/road_gui.h @@ -15,9 +15,13 @@ #include "road_type.h" #include "tile_type.h" #include "direction_type.h" +#include "widgets/dropdown_type.h" struct Window *ShowBuildRoadToolbar(RoadType roadtype); -struct Window *ShowBuildRoadScenToolbar(); +struct Window *ShowBuildRoadScenToolbar(RoadType roadtype); void ConnectRoadToStructure(TileIndex tile, DiagDirection direction); +DropDownList GetRoadTypeDropDownList(RoadTramTypes rtts, bool for_replacement = false, bool all_option = false); +DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts); +void InitializeRoadGUI(); #endif /* ROAD_GUI_H */ diff --git a/src/road_internal.h b/src/road_internal.h index 8da909e94a..79782e3bba 100644 --- a/src/road_internal.h +++ b/src/road_internal.h @@ -17,8 +17,8 @@ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb); -CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check = true); +CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadTramType rtt, DoCommandFlag flags, bool town_check = true); -void DrawRoadCatenary(const TileInfo *ti, RoadBits tram); +void DrawRoadCatenary(const TileInfo *ti); #endif /* ROAD_INTERNAL_H */ diff --git a/src/road_map.cpp b/src/road_map.cpp index 4984117bab..1ab95043ad 100644 --- a/src/road_map.cpp +++ b/src/road_map.cpp @@ -32,15 +32,15 @@ * @param straight_tunnel_bridge_entrance whether to return straight road bits for tunnels/bridges. * @return the road bits of the given tile */ -RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance) +RoadBits GetAnyRoadBits(TileIndex tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance) { - if (!HasTileRoadType(tile, rt)) return ROAD_NONE; + if (!MayHaveRoad(tile) || !HasTileRoadType(tile, rtt)) return ROAD_NONE; switch (GetTileType(tile)) { case MP_ROAD: switch (GetRoadTileType(tile)) { default: - case ROAD_TILE_NORMAL: return GetRoadBits(tile, rt); + case ROAD_TILE_NORMAL: return GetRoadBits(tile, rtt); case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile); case ROAD_TILE_DEPOT: return DiagDirToRoadBits(GetRoadDepotDirection(tile)); } diff --git a/src/road_map.h b/src/road_map.h index 49526d37f2..f5600d590d 100644 --- a/src/road_map.h +++ b/src/road_map.h @@ -26,6 +26,24 @@ enum RoadTileType { ROAD_TILE_DEPOT, ///< Depot (one entrance) }; +/** + * Test whether a tile can have road/tram types. + * @param t Tile to query. + * @return true if tile can be queried about road/tram types. + */ +static inline bool MayHaveRoad(TileIndex t) +{ + switch (GetTileType(t)) { + case MP_ROAD: + case MP_STATION: + case MP_TUNNELBRIDGE: + return true; + + default: + return false; + } +} + /** * Get the type of the road tile. * @param t Tile to query. @@ -108,26 +126,11 @@ static inline bool IsRoadDepotTile(TileIndex t) * @pre IsNormalRoad(t) * @return The present road bits for the road type. */ -static inline RoadBits GetRoadBits(TileIndex t, RoadType rt) +static inline RoadBits GetRoadBits(TileIndex t, RoadTramType rtt) { assert(IsNormalRoad(t)); - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: return (RoadBits)GB(_m[t].m5, 0, 4); - case ROADTYPE_TRAM: return (RoadBits)GB(_m[t].m3, 0, 4); - } -} - -/** - * Get all RoadBits set on a tile except from the given RoadType - * - * @param t The tile from which we want to get the RoadBits - * @param rt The RoadType which we exclude from the querry - * @return all set RoadBits of the tile which are not from the given RoadType - */ -static inline RoadBits GetOtherRoadBits(TileIndex t, RoadType rt) -{ - return GetRoadBits(t, rt == ROADTYPE_ROAD ? ROADTYPE_TRAM : ROADTYPE_ROAD); + if (rtt == RTT_TRAM) return (RoadBits)GB(_m[t].m3, 0, 4); + return (RoadBits)GB(_m[t].m5, 0, 4); } /** @@ -138,7 +141,7 @@ static inline RoadBits GetOtherRoadBits(TileIndex t, RoadType rt) */ static inline RoadBits GetAllRoadBits(TileIndex tile) { - return GetRoadBits(tile, ROADTYPE_ROAD) | GetRoadBits(tile, ROADTYPE_TRAM); + return GetRoadBits(tile, RTT_ROAD) | GetRoadBits(tile, RTT_TRAM); } /** @@ -148,96 +151,125 @@ static inline RoadBits GetAllRoadBits(TileIndex tile) * @param rt Road type. * @pre IsNormalRoad(t) */ -static inline void SetRoadBits(TileIndex t, RoadBits r, RoadType rt) +static inline void SetRoadBits(TileIndex t, RoadBits r, RoadTramType rtt) { assert(IsNormalRoad(t)); // XXX incomplete - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: SB(_m[t].m5, 0, 4, r); break; - case ROADTYPE_TRAM: SB(_m[t].m3, 0, 4, r); break; + if (rtt == RTT_TRAM) { + SB(_m[t].m3, 0, 4, r); + } else { + SB(_m[t].m5, 0, 4, r); } } +static inline RoadType GetRoadTypeRoad(TileIndex t) +{ + assert(MayHaveRoad(t)); + return (RoadType)GB(_m[t].m4, 0, 6); +} + +static inline RoadType GetRoadTypeTram(TileIndex t) +{ + assert(MayHaveRoad(t)); + return (RoadType)GB(_me[t].m8, 6, 6); +} + +static inline RoadType GetRoadType(TileIndex t, RoadTramType rtt) +{ + return (rtt == RTT_TRAM) ? GetRoadTypeTram(t) : GetRoadTypeRoad(t); +} + /** * Get the present road types of a tile. * @param t The tile to query. * @return Present road types. */ -static inline RoadTypes GetRoadTypes(TileIndex t) +static inline RoadTypes GetPresentRoadTypes(TileIndex t) { - return (RoadTypes)GB(_me[t].m7, 6, 2); + RoadTypes result = ROADTYPES_NONE; + if (MayHaveRoad(t)) { + if (GetRoadTypeRoad(t) != INVALID_ROADTYPE) SetBit(result, GetRoadTypeRoad(t)); + if (GetRoadTypeTram(t) != INVALID_ROADTYPE) SetBit(result, GetRoadTypeTram(t)); + } + return result; +} + +static inline bool HasRoadTypeRoad(TileIndex t) +{ + return GetRoadTypeRoad(t) != INVALID_ROADTYPE; +} + +static inline bool HasRoadTypeTram(TileIndex t) +{ + return GetRoadTypeTram(t) != INVALID_ROADTYPE; } /** - * Set the present road types of a tile. - * @param t The tile to change. - * @param rt The new road types. - */ -static inline void SetRoadTypes(TileIndex t, RoadTypes rt) -{ - assert(IsTileType(t, MP_ROAD) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)); - SB(_me[t].m7, 6, 2, rt); -} - -/** - * Check if a tile has a specific road type. + * Check if a tile has a road or a tram road type. * @param t The tile to check. - * @param rt Road type to check. + * @param tram True to check tram, false to check road. * @return True if the tile has the specified road type. */ -static inline bool HasTileRoadType(TileIndex t, RoadType rt) +static inline bool HasTileRoadType(TileIndex t, RoadTramType rtt) { - return HasBit(GetRoadTypes(t), rt); + return GetRoadType(t, rtt) != INVALID_ROADTYPE; +} + +/** + * Check if a tile has one of the specified road types. + * @param t The tile to check. + * @param rts Allowed road types. + * @return True if the tile has one of the specified road types. + */ +static inline bool HasTileAnyRoadType(TileIndex t, RoadTypes rts) +{ + if (!MayHaveRoad(t)) return false; + return (GetPresentRoadTypes(t) & rts); } /** * Get the owner of a specific road type. * @param t The tile to query. - * @param rt The road type to get the owner of. + * @param rtt RoadTramType. * @return Owner of the given road type. */ -static inline Owner GetRoadOwner(TileIndex t, RoadType rt) +static inline Owner GetRoadOwner(TileIndex t, RoadTramType rtt) { - assert(IsTileType(t, MP_ROAD) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)); - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: return (Owner)GB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5); - case ROADTYPE_TRAM: { - /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE - * to OWNER_TOWN makes it use one bit less */ - Owner o = (Owner)GB(_m[t].m3, 4, 4); - return o == OWNER_TOWN ? OWNER_NONE : o; - } - } + assert(MayHaveRoad(t)); + if (rtt == RTT_ROAD) return (Owner)GB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5); + + /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE + * to OWNER_TOWN makes it use one bit less */ + Owner o = (Owner)GB(_m[t].m3, 4, 4); + return o == OWNER_TOWN ? OWNER_NONE : o; } /** * Set the owner of a specific road type. * @param t The tile to change. - * @param rt The road type to change the owner of. + * @param rtt RoadTramType. * @param o New owner of the given road type. */ -static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) +static inline void SetRoadOwner(TileIndex t, RoadTramType rtt, Owner o) { - switch (rt) { - default: NOT_REACHED(); - case ROADTYPE_ROAD: SB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5, o); break; - case ROADTYPE_TRAM: SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); break; + if (rtt == RTT_ROAD) { + SB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5, o); + } else { + SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); } } /** * Check if a specific road type is owned by an owner. * @param t The tile to query. - * @param rt The road type to compare the owner of. + * @param tram True to check tram, false to check road. * @param o Owner to compare with. * @pre HasTileRoadType(t, rt) * @return True if the road type is owned by the given owner. */ -static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o) +static inline bool IsRoadOwner(TileIndex t, RoadTramType rtt, Owner o) { - assert(HasTileRoadType(t, rt)); - return (GetRoadOwner(t, rt) == o); + assert(HasTileRoadType(t, rtt)); + return (GetRoadOwner(t, rtt) == o); } /** @@ -248,7 +280,7 @@ static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o) */ static inline bool HasTownOwnedRoad(TileIndex t) { - return HasTileRoadType(t, ROADTYPE_ROAD) && IsRoadOwner(t, ROADTYPE_ROAD, OWNER_TOWN); + return HasTileRoadType(t, RTT_ROAD) && IsRoadOwner(t, RTT_ROAD, OWNER_TOWN); } /** Which directions are disallowed ? */ @@ -539,29 +571,80 @@ static inline DiagDirection GetRoadDepotDirection(TileIndex t) } -RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance = false); +RoadBits GetAnyRoadBits(TileIndex tile, RoadTramType rtt, bool straight_tunnel_bridge_entrance = false); +/** + * Set the road road type of a tile. + * @param t The tile to change. + * @param rt The road type to set. + */ +static inline void SetRoadTypeRoad(TileIndex t, RoadType rt) +{ + assert(MayHaveRoad(t)); + assert(rt == INVALID_ROADTYPE || RoadTypeIsRoad(rt)); + SB(_m[t].m4, 0, 6, rt); +} + +/** + * Set the tram road type of a tile. + * @param t The tile to change. + * @param rt The road type to set. + */ +static inline void SetRoadTypeTram(TileIndex t, RoadType rt) +{ + assert(MayHaveRoad(t)); + assert(rt == INVALID_ROADTYPE || RoadTypeIsTram(rt)); + SB(_me[t].m8, 6, 6, rt); +} + +/** + * Set the road type of a tile. + * @param t The tile to change. + * @param rtt Set road or tram type. + * @param rt The road type to set. + */ +static inline void SetRoadType(TileIndex t, RoadTramType rtt, RoadType rt) +{ + if (rtt == RTT_TRAM) { + SetRoadTypeTram(t, rt); + } else { + SetRoadTypeRoad(t, rt); + } +} + +/** + * Set the present road types of a tile. + * @param t The tile to change. + * @param road_rt The road roadtype to set for the tile. + * @param tram_rt The tram roadtype to set for the tile. + */ +static inline void SetRoadTypes(TileIndex t, RoadType road_rt, RoadType tram_rt) +{ + SetRoadTypeRoad(t, road_rt); + SetRoadTypeTram(t, tram_rt); +} /** * Make a normal road tile. - * @param t Tile to make a normal road. - * @param bits Road bits to set for all present road types. - * @param rot New present road types. - * @param town Town ID if the road is a town-owned road. - * @param road New owner of road. - * @param tram New owner of tram tracks. + * @param t Tile to make a normal road. + * @param bits Road bits to set for all present road types. + * @param road_rt The road roadtype to set for the tile. + * @param tram_rt The tram roadtype to set for the tile. + * @param town Town ID if the road is a town-owned road. + * @param road New owner of road. + * @param tram New owner of tram tracks. */ -static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadTypes rot, TownID town, Owner road, Owner tram) +static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadType road_rt, RoadType tram_rt, TownID town, Owner road, Owner tram) { SetTileType(t, MP_ROAD); SetTileOwner(t, road); _m[t].m2 = town; - _m[t].m3 = (HasBit(rot, ROADTYPE_TRAM) ? bits : 0); - _m[t].m4 = 0; - _m[t].m5 = (HasBit(rot, ROADTYPE_ROAD) ? bits : 0) | ROAD_TILE_NORMAL << 6; + _m[t].m3 = (tram_rt != INVALID_ROADTYPE ? bits : 0); + _m[t].m5 = (road_rt != INVALID_ROADTYPE ? bits : 0) | ROAD_TILE_NORMAL << 6; SB(_me[t].m6, 2, 4, 0); - _me[t].m7 = rot << 6; - SetRoadOwner(t, ROADTYPE_TRAM, tram); + _me[t].m7 = 0; + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_TRAM, tram); } /** @@ -572,21 +655,23 @@ static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadTypes rot, Tow * @param rail New owner of the rail track. * @param roaddir Axis of the road. * @param rat New rail type. - * @param rot New present road types. + * @param road_rt The road roadtype to set for the tile. + * @param tram_rt The tram roadtype to set for the tile. * @param town Town ID if the road is a town-owned road. */ -static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner rail, Axis roaddir, RailType rat, RoadTypes rot, uint town) +static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner rail, Axis roaddir, RailType rat, RoadType road_rt, RoadType tram_rt, uint town) { SetTileType(t, MP_ROAD); SetTileOwner(t, rail); _m[t].m2 = town; _m[t].m3 = 0; - _m[t].m4 = 0; + _m[t].m4 = INVALID_ROADTYPE; _m[t].m5 = ROAD_TILE_CROSSING << 6 | roaddir; SB(_me[t].m6, 2, 4, 0); - _me[t].m7 = rot << 6 | road; - _me[t].m8 = rat; - SetRoadOwner(t, ROADTYPE_TRAM, tram); + _me[t].m7 = road; + _me[t].m8 = INVALID_ROADTYPE << 6 | rat; + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_TRAM, tram); } /** @@ -594,7 +679,7 @@ static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner r * @param t Tile to make a level crossing. * @param owner New owner of the depot. * @param did New depot ID. - * @param dir Direction of the depot exit. + * @param dir Direction of the depot exit.* * @param rt Road type of the depot. */ static inline void MakeRoadDepot(TileIndex t, Owner owner, DepotID did, DiagDirection dir, RoadType rt) @@ -603,11 +688,13 @@ static inline void MakeRoadDepot(TileIndex t, Owner owner, DepotID did, DiagDire SetTileOwner(t, owner); _m[t].m2 = did; _m[t].m3 = 0; - _m[t].m4 = 0; + _m[t].m4 = INVALID_ROADTYPE; _m[t].m5 = ROAD_TILE_DEPOT << 6 | dir; SB(_me[t].m6, 2, 4, 0); - _me[t].m7 = RoadTypeToRoadTypes(rt) << 6 | owner; - SetRoadOwner(t, ROADTYPE_TRAM, owner); + _me[t].m7 = owner; + _me[t].m8 = INVALID_ROADTYPE << 6; + SetRoadType(t, GetRoadTramType(rt), rt); + SetRoadOwner(t, RTT_TRAM, owner); } #endif /* ROAD_MAP_H */ diff --git a/src/road_type.h b/src/road_type.h index 5251a53923..f01d1d0353 100644 --- a/src/road_type.h +++ b/src/road_type.h @@ -14,37 +14,37 @@ #include "core/enum_type.hpp" +typedef uint32 RoadTypeLabel; + +static const RoadTypeLabel ROADTYPE_ROAD_LABEL = 'ROAD'; +static const RoadTypeLabel ROADTYPE_TRAM_LABEL = 'TRAM'; + /** * The different roadtypes we support * * @note currently only ROADTYPE_ROAD and ROADTYPE_TRAM are supported. */ enum RoadType { - ROADTYPE_BEGIN = 0, ///< Used for iterations - ROADTYPE_ROAD = 0, ///< Basic road type - ROADTYPE_TRAM = 1, ///< Trams - ROADTYPE_END, ///< Used for iterations - INVALID_ROADTYPE = 0xFF, ///< flag for invalid roadtype + ROADTYPE_BEGIN = 0, ///< Used for iterations + ROADTYPE_ROAD = 0, ///< Basic road type + ROADTYPE_TRAM = 1, ///< Trams + ROADTYPE_END = 63, ///< Used for iterations + INVALID_ROADTYPE = 63, ///< flag for invalid roadtype }; DECLARE_POSTFIX_INCREMENT(RoadType) -template <> struct EnumPropsT : MakeEnumPropsT {}; +template <> struct EnumPropsT : MakeEnumPropsT {}; /** - * The different roadtypes we support, but then a bitmask of them - * @note currently only roadtypes with ROADTYPE_ROAD and ROADTYPE_TRAM are supported. + * The different roadtypes we support, but then a bitmask of them. + * @note Must be treated as a uint64 type, narrowing it causes bit membership tests to give wrong results. */ -enum RoadTypes { +enum RoadTypes : uint64 { ROADTYPES_NONE = 0, ///< No roadtypes ROADTYPES_ROAD = 1 << ROADTYPE_ROAD, ///< Road ROADTYPES_TRAM = 1 << ROADTYPE_TRAM, ///< Trams - ROADTYPES_ALL = ROADTYPES_ROAD | ROADTYPES_TRAM, ///< Road + trams - ROADTYPES_END, ///< Used for iterations? - INVALID_ROADTYPES = 0xFF, ///< Invalid roadtypes + INVALID_ROADTYPES = UINT64_MAX, ///< Invalid roadtypes }; DECLARE_ENUM_AS_BIT_SET(RoadTypes) -template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef SimpleTinyEnumT RoadTypesByte; - /** * Enumeration for the road parts on a tile. diff --git a/src/roadstop.cpp b/src/roadstop.cpp index ca049979ca..694e33f0dd 100644 --- a/src/roadstop.cpp +++ b/src/roadstop.cpp @@ -43,9 +43,9 @@ RoadStop::~RoadStop() */ RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const { - for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) { + for (RoadStop *rs = this->next; rs != nullptr; rs = rs->next) { /* The vehicle cannot go to this roadstop (different roadtype) */ - if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue; + if (!HasTileAnyRoadType(rs->xy, v->compatible_roadtypes)) continue; /* The vehicle is articulated and can therefore not go to a standard road stop. */ if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue; @@ -53,7 +53,7 @@ RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const return rs; } - return NULL; + return nullptr; } /** @@ -63,7 +63,7 @@ RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const */ void RoadStop::MakeDriveThrough() { - assert(this->east == NULL && this->west == NULL); + assert(this->east == nullptr && this->west == nullptr); RoadStopType rst = GetRoadStopType(this->xy); DiagDirection dir = GetRoadStopDir(this->xy); @@ -73,21 +73,21 @@ void RoadStop::MakeDriveThrough() /* Information about the tile north of us */ TileIndex north_tile = this->xy - offset; bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile); - RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL; + RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : nullptr; /* Information about the tile south of us */ TileIndex south_tile = this->xy + offset; bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile); - RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL; + RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : nullptr; /* Amount of road stops that will be added to the 'northern' head */ int added = 1; - if (north && rs_north->east != NULL) { // (east != NULL) == (west != NULL) + if (north && rs_north->east != nullptr) { // (east != nullptr) == (west != nullptr) /* There is a more northern one, so this can join them */ this->east = rs_north->east; this->west = rs_north->west; - if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL) + if (south && rs_south->east != nullptr) { // (east != nullptr) == (west != nullptr) /* There more southern tiles too, they must 'join' us too */ ClrBit(rs_south->status, RSSFB_BASE_ENTRY); this->east->occupied += rs_south->east->occupied; @@ -100,13 +100,13 @@ void RoadStop::MakeDriveThrough() /* Make all 'children' of the southern tile take the new master */ for (; IsDriveThroughRoadStopContinuation(this->xy, south_tile); south_tile += offset) { rs_south = RoadStop::GetByTile(south_tile, rst); - if (rs_south->east == NULL) break; + if (rs_south->east == nullptr) break; rs_south->east = rs_north->east; rs_south->west = rs_north->west; added++; } } - } else if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL) + } else if (south && rs_south->east != nullptr) { // (east != nullptr) == (west != nullptr) /* There is one to the south, but not to the north... so we become 'parent' */ this->east = rs_south->east; this->west = rs_south->west; @@ -131,7 +131,7 @@ void RoadStop::MakeDriveThrough() */ void RoadStop::ClearDriveThrough() { - assert(this->east != NULL && this->west != NULL); + assert(this->east != nullptr && this->west != nullptr); RoadStopType rst = GetRoadStopType(this->xy); DiagDirection dir = GetRoadStopDir(this->xy); @@ -141,12 +141,12 @@ void RoadStop::ClearDriveThrough() /* Information about the tile north of us */ TileIndex north_tile = this->xy - offset; bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile); - RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL; + RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : nullptr; /* Information about the tile south of us */ TileIndex south_tile = this->xy + offset; bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile); - RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL; + RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : nullptr; /* Must only be cleared after we determined which neighbours are * part of our little entry 'queue' */ @@ -207,8 +207,8 @@ void RoadStop::ClearDriveThrough() /* Make sure we don't get used for something 'incorrect' */ ClrBit(this->status, RSSFB_BASE_ENTRY); - this->east = NULL; - this->west = NULL; + this->east = nullptr; + this->west = nullptr; } /** @@ -271,7 +271,7 @@ bool RoadStop::Enter(RoadVehicle *rv) for (RoadStop *rs = st->GetPrimaryRoadStop(type);; rs = rs->next) { if (rs->xy == tile) return rs; - assert(rs->next != NULL); + assert(rs->next != nullptr); } } @@ -325,25 +325,25 @@ struct RoadStopEntryRebuilderHelper { * Add road vehicles to the station's list if needed. * @param v the found vehicle * @param data the extra data used to make our decision - * @return always NULL + * @return always nullptr */ Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data) { RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data; /* Not a RV or not in the right direction or crashed :( */ - if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return NULL; + if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return nullptr; RoadVehicle *rv = RoadVehicle::From(v); /* Don't add ones not in a road stop */ - if (rv->state < RVSB_IN_ROAD_STOP) return NULL; + if (rv->state < RVSB_IN_ROAD_STOP) return nullptr; /* Do not add duplicates! */ for (RVList::iterator it = rserh->vehicles.begin(); it != rserh->vehicles.end(); it++) { - if (rv == *it) return NULL; + if (rv == *it) return nullptr; } rserh->vehicles.push_back(rv); - return NULL; + return nullptr; } /** diff --git a/src/roadveh.h b/src/roadveh.h index ca069b7acf..02eb48c8c2 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -16,8 +16,10 @@ #include "engine_base.h" #include "cargotype.h" #include "track_func.h" -#include "road_type.h" +#include "road.h" +#include "road_map.h" #include "newgrf_engine.h" +#include struct RoadVehicle; @@ -82,10 +84,30 @@ static const byte RV_OVERTAKE_TIMEOUT = 35; void RoadVehUpdateCache(RoadVehicle *v, bool same_length = false); void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); +struct RoadVehPathCache { + std::deque td; + std::deque tile; + + inline bool empty() const { return this->td.empty(); } + + inline size_t size() const + { + assert(this->td.size() == this->tile.size()); + return this->td.size(); + } + + inline void clear() + { + this->td.clear(); + this->tile.clear(); + } +}; + /** * Buses, trucks and trams belong to this class. */ struct RoadVehicle FINAL : public GroundVehicle { + RoadVehPathCache path; ///< Cached path. byte state; ///< @see RoadVehicleStates byte frame; uint16 blocked_ctr; @@ -94,8 +116,8 @@ struct RoadVehicle FINAL : public GroundVehicle { uint16 crashed_ctr; ///< Animation counter when the vehicle has crashed. @see RoadVehIsCrashed byte reverse_ctr; - RoadType roadtype; - RoadTypes compatible_roadtypes; + RoadType roadtype; //!< Roadtype of this vehicle. + RoadTypes compatible_roadtypes; //!< Roadtypes this consist is powered on. /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ RoadVehicle() : GroundVehicleBase() {} @@ -112,7 +134,7 @@ struct RoadVehicle FINAL : public GroundVehicle { int GetDisplaySpeed() const { return this->gcache.last_speed / 2; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; } Money GetRunningCost() const; - int GetDisplayImageWidth(Point *offset = NULL) const; + int GetDisplayImageWidth(Point *offset = nullptr) const; bool IsInDepot() const { return this->state == RVSB_IN_DEPOT; } bool Tick(); void OnNewDay(); @@ -125,6 +147,7 @@ struct RoadVehicle FINAL : public GroundVehicle { int GetCurrentMaxSpeed() const; int UpdateSpeed(); + void SetDestTile(TileIndex tile); protected: // These functions should not be called outside acceleration code. @@ -222,7 +245,7 @@ protected: // These functions should not be called outside acceleration code. { /* Trams have a slightly greater friction coefficient than trains. * The rest of road vehicles have bigger values. */ - uint32 coeff = (this->roadtype == ROADTYPE_TRAM) ? 40 : 75; + uint32 coeff = RoadTypeIsTram(this->roadtype) ? 40 : 75; /* The friction coefficient increases with speed in a way that * it doubles at 128 km/h, triples at 256 km/h and so on. */ return coeff * (128 + this->GetCurrentSpeed()) / 128; @@ -252,7 +275,7 @@ protected: // These functions should not be called outside acceleration code. */ inline uint16 GetMaxTrackSpeed() const { - return 0; + return GetRoadTypeInfo(GetRoadType(this->tile, GetRoadTramType(this->roadtype)))->max_speed; } /** @@ -261,7 +284,7 @@ protected: // These functions should not be called outside acceleration code. */ inline bool TileMayHaveSlopedTrack() const { - TrackStatus ts = GetTileTrackStatus(this->tile, TRANSPORT_ROAD, this->compatible_roadtypes); + TrackStatus ts = GetTileTrackStatus(this->tile, TRANSPORT_ROAD, GetRoadTramType(this->roadtype)); TrackBits trackbits = TrackStatusToTrackBits(ts); return trackbits == TRACK_BIT_X || trackbits == TRACK_BIT_Y; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 68ba372352..8bf47b06d8 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -86,14 +86,14 @@ bool RoadVehicle::IsBus() const /** * Get the width of a road vehicle image in the GUI. - * @param offset Additional offset for positioning the sprite; set to NULL if not needed + * @param offset Additional offset for positioning the sprite; set to nullptr if not needed * @return Width in pixels */ int RoadVehicle::GetDisplayImageWidth(Point *offset) const { int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH; - if (offset != NULL) { + if (offset != nullptr) { offset->x = ScaleGUITrad(reference_width) / 2; offset->y = 0; } @@ -192,7 +192,7 @@ static uint GetRoadVehLength(const RoadVehicle *v) uint length = VEHICLE_LENGTH; uint16 veh_len = CALLBACK_FAILED; - if (e->GetGRF() != NULL && e->GetGRF()->grf_version >= 8) { + if (e->GetGRF() != nullptr && e->GetGRF()->grf_version >= 8) { /* Use callback 36 */ veh_len = GetVehicleProperty(v, PROP_ROADVEH_SHORTEN_FACTOR, CALLBACK_FAILED); if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len); @@ -223,7 +223,7 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length) v->gcache.cached_total_length = 0; - for (RoadVehicle *u = v; u != NULL; u = u->Next()) { + for (RoadVehicle *u = v; u != nullptr; u = u->Next()) { /* Check the v->first cache. */ assert(u->First() == v); @@ -260,7 +260,10 @@ void RoadVehUpdateCache(RoadVehicle *v, bool same_length) */ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) { - if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE); + /* Check that the vehicle can drive on the road in question */ + RoadType rt = e->u.road.roadtype; + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + if (!HasTileAnyRoadType(tile, rti->powered_roadtypes)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE); if (flags & DC_EXEC) { const RoadVehicleInfo *rvi = &e->u.road; @@ -304,8 +307,8 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin v->random_bits = VehicleRandomBits(); v->SetFrontEngine(); - v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; - v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype); + v->roadtype = rt; + v->compatible_roadtypes = rti->powered_roadtypes; v->gcache.cached_veh_length = VEHICLE_LENGTH; if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); @@ -315,7 +318,7 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin v->InvalidateNewGRFCacheOfChain(); /* Call various callbacks after the whole consist has been constructed */ - for (RoadVehicle *u = v; u != NULL; u = u->Next()) { + for (RoadVehicle *u = v; u != nullptr; u = u->Next()) { u->cargo_cap = u->GetEngine()->DetermineCapacity(u); u->refit_cap = 0; v->InvalidateNewGRFCache(); @@ -350,8 +353,8 @@ bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destinati FindDepotData rfdd = FindClosestRoadDepot(this, 0); if (rfdd.best_length == UINT_MAX) return false; - if (location != NULL) *location = rfdd.tile; - if (destination != NULL) *destination = GetDepotIndex(rfdd.tile); + if (location != nullptr) *location = rfdd.tile; + if (destination != nullptr) *destination = GetDepotIndex(rfdd.tile); return true; } @@ -368,7 +371,7 @@ bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destinati CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { RoadVehicle *v = RoadVehicle::GetIfValid(p1); - if (v == NULL) return CMD_ERROR; + if (v == nullptr) return CMD_ERROR; if (!v->IsPrimaryVehicle()) return CMD_ERROR; @@ -397,7 +400,7 @@ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 void RoadVehicle::MarkDirty() { - for (RoadVehicle *v = this; v != NULL; v = v->Next()) { + for (RoadVehicle *v = this; v != nullptr; v = v->Next()) { v->colourmap = PAL_NONE; v->UpdateViewport(true, false); } @@ -437,16 +440,16 @@ void RoadVehicle::UpdateDeltaXY() */ inline int RoadVehicle::GetCurrentMaxSpeed() const { - int max_speed = this->vcache.cached_max_speed; + int max_speed = this->gcache.cached_max_track_speed; /* Limit speed to 50% while reversing, 75% in curves. */ - for (const RoadVehicle *u = this; u != NULL; u = u->Next()) { + for (const RoadVehicle *u = this; u != nullptr; u = u->Next()) { if (_settings_game.vehicle.roadveh_acceleration_model == AM_REALISTIC) { if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) { - max_speed = this->vcache.cached_max_speed / 2; + max_speed = this->gcache.cached_max_track_speed / 2; break; } else if ((u->direction & 1) == 0) { - max_speed = this->vcache.cached_max_speed * 3 / 4; + max_speed = this->gcache.cached_max_track_speed * 3 / 4; } } @@ -467,8 +470,8 @@ static void DeleteLastRoadVeh(RoadVehicle *v) { RoadVehicle *first = v->First(); Vehicle *u = v; - for (; v->Next() != NULL; v = v->Next()) u = v; - u->SetNext(NULL); + for (; v->Next() != nullptr; v = v->Next()) u = v; + u->SetNext(nullptr); v->last_station_visited = first->last_station_visited; // for PreDestructor /* Only leave the road stop when we're really gone. */ @@ -488,7 +491,7 @@ static void RoadVehSetRandomDirection(RoadVehicle *v) v->direction = ChangeDir(v->direction, delta[r & 3]); v->UpdateViewport(true, true); - } while ((v = v->Next()) != NULL); + } while ((v = v->Next()) != nullptr); } /** @@ -504,7 +507,7 @@ static bool RoadVehIsCrashed(RoadVehicle *v) } else if (v->crashed_ctr <= 45) { if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v); } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) { - bool ret = v->Next() != NULL; + bool ret = v->Next() != nullptr; DeleteLastRoadVeh(v); return ret; } @@ -516,7 +519,7 @@ static bool RoadVehIsCrashed(RoadVehicle *v) * Check routine whether a road and a train vehicle have collided. * @param v %Train vehicle to test. * @param data Road vehicle to test. - * @return %Train vehicle if the vehicles collided, else \c NULL. + * @return %Train vehicle if the vehicles collided, else \c nullptr. */ static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data) { @@ -525,7 +528,7 @@ static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data) return (v->type == VEH_TRAIN && abs(v->z_pos - u->z_pos) <= 6 && abs(v->x_pos - u->x_pos) <= 4 && - abs(v->y_pos - u->y_pos) <= 4) ? v : NULL; + abs(v->y_pos - u->y_pos) <= 4) ? v : nullptr; } uint RoadVehicle::Crash(bool flooded) @@ -564,7 +567,7 @@ static void RoadVehCrash(RoadVehicle *v) static bool RoadVehCheckTrainCrash(RoadVehicle *v) { - for (RoadVehicle *u = v; u != NULL; u = u->Next()) { + for (RoadVehicle *u = v; u != nullptr; u = u->Next()) { if (u->state == RVSB_WORMHOLE) continue; TileIndex tile = u->tile; @@ -641,7 +644,7 @@ static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) } } - return NULL; + return nullptr; } static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true) @@ -649,7 +652,7 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d RoadVehFindData rvf; RoadVehicle *front = v->First(); - if (front->reverse_ctr != 0) return NULL; + if (front->reverse_ctr != 0) return nullptr; rvf.x = x; rvf.y = y; @@ -670,10 +673,10 @@ static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction d * It can be disabled. */ if (rvf.best_diff == UINT_MAX) { front->blocked_ctr = 0; - return NULL; + return nullptr; } - if (update_blocked_ctr && ++front->blocked_ctr > 1480) return NULL; + if (update_blocked_ctr && ++front->blocked_ctr > 1480) return nullptr; return RoadVehicle::From(rvf.best); } @@ -691,7 +694,7 @@ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st) st->had_vehicle_of_type |= HVOT_BUS; SetDParam(0, st->index); AddVehicleNewsItem( - v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, + RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index @@ -705,7 +708,7 @@ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st) st->had_vehicle_of_type |= HVOT_TRUCK; SetDParam(0, st->index); AddVehicleNewsItem( - v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, + RoadTypeIsRoad(v->roadtype) ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index @@ -772,7 +775,7 @@ static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) { const OvertakeData *od = (OvertakeData*)data; - return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : NULL; + return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : nullptr; } /** @@ -783,7 +786,8 @@ static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) */ static bool CheckRoadBlockedForOvertaking(OvertakeData *od) { - TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes); + if (!HasTileAnyRoadType(od->tile, od->v->compatible_roadtypes)) return true; + TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, GetRoadTramType(od->v->roadtype)); TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts); TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits); @@ -803,7 +807,7 @@ static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) od.u = u; /* Trams can't overtake other trams */ - if (v->roadtype == ROADTYPE_TRAM) return; + if (RoadTypeIsTram(v->roadtype)) return; /* Don't overtake in stations */ if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return; @@ -855,7 +859,7 @@ static void RoadZPosAffectSpeed(RoadVehicle *v, int old_z) v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10% } else { uint16 spd = v->cur_speed + 2; - if (spd <= v->vcache.cached_max_speed) v->cur_speed = spd; + if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd; } } @@ -884,12 +888,12 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection Trackdir best_track; bool path_found = true; - TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes); + TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, GetRoadTramType(v->roadtype)); TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts); if (IsTileType(tile, MP_ROAD)) { - if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) { + if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir)) { /* Road depot owned by another company or with the wrong orientation */ trackdirs = TRACKDIR_BIT_NONE; } @@ -924,16 +928,18 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection /* Remove tracks unreachable from the enter dir */ trackdirs &= DiagdirReachesTrackdirs(enterdir); if (trackdirs == TRACKDIR_BIT_NONE) { + /* If vehicle expected a path, it no longer exists, so invalidate it. */ + if (!v->path.empty()) v->path.clear(); /* No reachable tracks, so we'll reverse */ return_track(_road_reverse_table[enterdir]); } if (v->reverse_ctr != 0) { bool reverse = true; - if (v->roadtype == ROADTYPE_TRAM) { + if (RoadTypeIsTram(v->roadtype)) { /* Trams may only reverse on a tile if it contains at least the straight * trackbits or when it is a valid turning tile (i.e. one roadbit) */ - RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM); + RoadBits rb = GetAnyRoadBits(tile, RTT_TRAM); RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir)); reverse = ((rb & straight) == straight) || (rb == DiagDirToRoadBits(enterdir)); @@ -954,12 +960,35 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection /* Only one track to choose between? */ if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) { + if (!v->path.empty() && v->path.tile.front() == tile) { + /* Vehicle expected a choice here, invalidate its path. */ + v->path.clear(); + } return_track(FindFirstBit2x64(trackdirs)); } + /* Attempt to follow cached path. */ + if (!v->path.empty()) { + if (v->path.tile.front() != tile) { + /* Vehicle didn't expect a choice here, invalidate its path. */ + v->path.clear(); + } else { + Trackdir trackdir = v->path.td.front(); + + if (HasBit(trackdirs, trackdir)) { + v->path.td.pop_front(); + v->path.tile.pop_front(); + return_track(trackdir); + } + + /* Vehicle expected a choice which is no longer available. */ + v->path.clear(); + } + } + switch (_settings_game.pf.pathfinder_for_roadvehs) { case VPF_NPF: best_track = NPFRoadVehicleChooseTrack(v, tile, enterdir, path_found); break; - case VPF_YAPF: best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break; + case VPF_YAPF: best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found, v->path); break; default: NOT_REACHED(); } @@ -981,7 +1010,7 @@ struct RoadDriveEntry { static bool RoadVehLeaveDepot(RoadVehicle *v, bool first) { /* Don't leave unless v and following wagons are in the depot. */ - for (const RoadVehicle *u = v; u != NULL; u = u->Next()) { + for (const RoadVehicle *u = v; u != nullptr; u = u->Next()) { if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false; } @@ -989,7 +1018,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first) v->direction = DiagDirToDir(dir); Trackdir tdir = DiagDirToDiagTrackdir(dir); - const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir]; int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF); int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF); @@ -1001,7 +1030,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first) return true; } - if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true; + if (RoadVehFindCloseTo(v, x, y, v->direction, false) != nullptr) return true; VehicleServiceInDepot(v); @@ -1084,7 +1113,7 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl }; RoadBits required = required_roadbits[dir & 0x07]; - if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) { + if ((required & GetAnyRoadBits(tile, GetRoadTramType(v->roadtype), true)) == ROAD_NONE) { dir = INVALID_TRACKDIR; } @@ -1095,15 +1124,16 @@ static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicl * Can a tram track build without destruction on the given tile? * @param c the company that would be building the tram tracks * @param t the tile to build on. + * @param rt the tram type to build. * @param r the road bits needed. * @return true when a track track can be build on 't' */ -static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r) +static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadType rt, RoadBits r) { /* The 'current' company is not necessarily the owner of the vehicle. */ - Backup cur_company(_current_company, c, FILE_LINE); + Backup cur_company(_current_company, c, FILE_LINE); - CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NO_WATER, CMD_BUILD_ROAD); + CommandCost ret = DoCommand(t, rt << 4 | r, 0, DC_NO_WATER, CMD_BUILD_ROAD); cur_company.Restore(); return ret.Succeeded(); @@ -1136,7 +1166,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) if (v->IsFrontEngine()) { const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction); - if (u != NULL) { + if (u != nullptr) { v->cur_speed = u->First()->cur_speed; return false; } @@ -1161,7 +1191,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) /* Get move position data for next frame. * For a drive-through road stop use 'straight road' move data. * In this case v->state is masked to give the road stop entry direction. */ - RoadDriveEntry rd = _road_drive_data[v->roadtype][( + RoadDriveEntry rd = _road_drive_data[GetRoadTramType(v->roadtype)][( (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1]; @@ -1171,7 +1201,11 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) if (v->IsFrontEngine()) { /* If this is the front engine, look for the right path. */ - dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3)); + if (HasTileAnyRoadType(tile, v->compatible_roadtypes)) { + dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3)); + } else { + dir = _road_reverse_table[(DiagDirection)(rd.x & 3)]; + } } else { dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false); } @@ -1189,7 +1223,7 @@ again: v->overtaking = 0; /* Turning around */ - if (v->roadtype == ROADTYPE_TRAM) { + if (RoadTypeIsTram(v->roadtype)) { /* Determine the road bits the tram needs to be able to turn around * using the 'big' corner loop. */ RoadBits needed; @@ -1200,9 +1234,10 @@ again: case TRACKDIR_RVREV_SW: needed = ROAD_NE; break; case TRACKDIR_RVREV_NW: needed = ROAD_SE; break; } - if ((v->Previous() != NULL && v->Previous()->tile == tile) || + if ((v->Previous() != nullptr && v->Previous()->tile == tile) || (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) && - (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) { + HasTileAnyRoadType(tile, v->compatible_roadtypes) && + (needed & GetRoadBits(tile, RTT_TRAM)) != ROAD_NONE)) { /* * Taking the 'big' corner for trams only happens when: * - The previous vehicle in this (articulated) tram chain is @@ -1213,7 +1248,7 @@ again: * going to cause the tram to split up. * - Or the front of the tram can drive over the next tile. */ - } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) { + } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, v->roadtype, needed) || ((~needed & GetAnyRoadBits(v->tile, RTT_TRAM, false)) == ROAD_NONE)) { /* * Taking the 'small' corner for trams only happens when: * - We are not the from vehicle of an articulated tram. @@ -1241,7 +1276,7 @@ again: } /* Get position data for first frame on the new tile */ - const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking]; int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x; int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y; @@ -1249,7 +1284,7 @@ again: Direction new_dir = RoadVehGetSlidingDirection(v, x, y); if (v->IsFrontEngine()) { Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir); - if (u != NULL) { + if (u != nullptr) { v->cur_speed = u->First()->cur_speed; return false; } @@ -1293,9 +1328,18 @@ again: } if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { + TileIndex old_tile = v->tile; + v->tile = tile; v->state = (byte)dir; v->frame = start_frame; + RoadTramType rtt = GetRoadTramType(v->roadtype); + if (GetRoadType(old_tile, rtt) != GetRoadType(tile, rtt)) { + if (v->IsFrontEngine()) { + RoadVehUpdateCache(v); + } + v->First()->CargoChanged(); + } } if (new_dir != v->direction) { v->direction = new_dir; @@ -1313,7 +1357,7 @@ again: Trackdir dir; uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME; - if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) { + if (RoadTypeIsTram(v->roadtype) && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, RTT_TRAM, true))) { /* * The tram is turning around with one tram 'roadbit'. This means that * it is using the 'big' corner 'drive data'. However, to support the @@ -1345,13 +1389,13 @@ again: return false; } - const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir]; + const RoadDriveEntry *rdp = _road_drive_data[GetRoadTramType(v->roadtype)][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir]; int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x; int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y; Direction new_dir = RoadVehGetSlidingDirection(v, x, y); - if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false; + if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != nullptr) return false; uint32 r = VehicleEnterTile(v, v->tile, x, y); if (HasBit(r, VETS_CANNOT_ENTER)) { @@ -1377,7 +1421,7 @@ again: /* This vehicle is not in a wormhole and it hasn't entered a new tile. If * it's on a depot tile, check if it's time to activate the next vehicle in * the chain yet. */ - if (v->Next() != NULL && IsRoadDepotTile(v->tile)) { + if (v->Next() != nullptr && IsRoadDepotTile(v->tile)) { if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) { RoadVehLeaveDepot(v->Next(), false); } @@ -1394,7 +1438,7 @@ again: * Check for another vehicle to overtake */ RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir); - if (u != NULL) { + if (u != nullptr) { u = u->First(); /* There is a vehicle in front overtake it if possible */ if (v->overtaking == 0) RoadVehCheckOvertake(v, u); @@ -1453,7 +1497,7 @@ again: TileIndex next_tile = TileAddByDir(v->tile, v->direction); /* Check if next inline bay is free and has compatible road. */ - if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) { + if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && HasTileAnyRoadType(next_tile, v->compatible_roadtypes)) { v->frame++; v->x_pos = x; v->y_pos = y; @@ -1544,7 +1588,7 @@ static bool RoadVehController(RoadVehicle *v) j -= adv_spd; RoadVehicle *u = v; - for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) { + for (RoadVehicle *prev = nullptr; u != nullptr; prev = u, u = u->Next()) { if (!IndividualRoadVehicleController(u, prev)) { blocked = true; break; @@ -1561,7 +1605,7 @@ static bool RoadVehController(RoadVehicle *v) v->SetLastSpeed(); - for (RoadVehicle *u = v; u != NULL; u = u->Next()) { + for (RoadVehicle *u = v; u != nullptr; u = u->Next()) { if ((u->vehstatus & VS_HIDDEN) != 0) continue; u->UpdateViewport(false, false); @@ -1600,6 +1644,13 @@ bool RoadVehicle::Tick() return true; } +void RoadVehicle::SetDestTile(TileIndex tile) +{ + if (tile == this->dest_tile) return; + this->path.clear(); + this->dest_tile = tile; +} + static void CheckIfRoadVehNeedsService(RoadVehicle *v) { /* If we already got a slot at a stop, use that FIRST, and go to a depot later */ diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index 63e0549582..1c96c29e91 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -47,7 +47,7 @@ void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y) memset(subtype_text, 0, sizeof(subtype_text)); - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { max_cargo[u->cargo_type] += u->cargo_cap; if (u->cargo_cap > 0) { StringID text = GetCargoSubtypeText(u); @@ -80,7 +80,7 @@ void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y) DrawString(left, right, y + FONT_HEIGHT_NORMAL + y_offset, capacity, TC_BLUE); - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { if (u->cargo_cap == 0) continue; str = STR_VEHICLE_DETAILS_CARGO_EMPTY; @@ -143,7 +143,7 @@ void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID se _cur_dpi = &tmp_dpi; int px = rtl ? max_width + skip : -skip; - for (; u != NULL && (rtl ? px > 0 : px < max_width); u = u->Next()) { + for (; u != nullptr && (rtl ? px > 0 : px < max_width); u = u->Next()) { Point offset; int width = u->GetDisplayImageWidth(&offset); diff --git a/src/safeguards.h b/src/safeguards.h index f447627e68..157730fbee 100644 --- a/src/safeguards.h +++ b/src/safeguards.h @@ -12,7 +12,7 @@ * * Unsafe methods are, for example, strndup and strncpy because they may leave the * string without a null termination, but also strdup and strndup because they can - * return NULL and then all strdups would need to be guarded against that instead + * return nullptr and then all strdups would need to be guarded against that instead * of using the current MallocT/ReallocT/CallocT technique of just giving the user * an error that too much memory was used instead of spreading that code though * the whole code base. diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index bad5f1654b..53e39c0852 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -19,6 +19,7 @@ #include "../network/network_func.h" #include "../gfxinit.h" #include "../viewport_func.h" +#include "../viewport_kdtree.h" #include "../industry.h" #include "../clear_map.h" #include "../vehicle_func.h" @@ -56,6 +57,7 @@ #include "../error.h" #include "../disaster_vehicle.h" #include "../ship.h" +#include "../water.h" #include "../story_base.h" #include "../game/game_text.hpp" @@ -224,6 +226,7 @@ void UpdateAllVirtCoords() UpdateAllStationVirtCoords(); UpdateAllSignVirtCoords(); UpdateAllTownVirtCoords(); + RebuildViewportKdtree(); } /** @@ -231,7 +234,7 @@ void UpdateAllVirtCoords() * This is not done directly in AfterLoadGame because these * functions require that all saveload conversions have been * done. As people tend to add savegame conversion stuff after - * the intialization of the windows and caches quite some bugs + * the initialization of the windows and caches quite some bugs * had been made. * Moving this out of there is both cleaner and less bug-prone. */ @@ -264,14 +267,14 @@ static void InitializeWindowsAndCaches() /* Identify owners of persistent storage arrays */ Industry *i; FOR_ALL_INDUSTRIES(i) { - if (i->psa != NULL) { + if (i->psa != nullptr) { i->psa->feature = GSF_INDUSTRIES; i->psa->tile = i->location.tile; } } Station *s; FOR_ALL_STATIONS(s) { - if (s->airport.psa != NULL) { + if (s->airport.psa != nullptr) { s->airport.psa->feature = GSF_AIRPORTS; s->airport.psa->tile = s->airport.tile; } @@ -283,12 +286,17 @@ static void InitializeWindowsAndCaches() (*it)->tile = t->xy; } } + RoadVehicle *rv; + FOR_ALL_ROADVEHICLES(rv) { + if (rv->IsFrontEngine()) { + rv->CargoChanged(); + } + } RecomputePrices(); GroupStatistics::UpdateAfterLoad(); - Station::RecomputeIndustriesNearForAll(); RebuildSubsidisedSourceAndDestinationCache(); /* Towns have a noise controlled number of airports system @@ -305,9 +313,9 @@ static void InitializeWindowsAndCaches() } typedef void (CDECL *SignalHandlerPointer)(int); -static SignalHandlerPointer _prev_segfault = NULL; -static SignalHandlerPointer _prev_abort = NULL; -static SignalHandlerPointer _prev_fpe = NULL; +static SignalHandlerPointer _prev_segfault = nullptr; +static SignalHandlerPointer _prev_abort = nullptr; +static SignalHandlerPointer _prev_fpe = nullptr; static void CDECL HandleSavegameLoadCrash(int signum); @@ -377,7 +385,7 @@ static void CDECL HandleSavegameLoadCrash(int signum) char *p = buffer; p += seprintf(p, lastof(buffer), "Loading your savegame caused OpenTTD to crash.\n"); - for (const GRFConfig *c = _grfconfig; !_saveload_crash_with_missing_newgrfs && c != NULL; c = c->next) { + for (const GRFConfig *c = _grfconfig; !_saveload_crash_with_missing_newgrfs && c != nullptr; c = c->next) { _saveload_crash_with_missing_newgrfs = HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND; } @@ -395,7 +403,7 @@ static void CDECL HandleSavegameLoadCrash(int signum) "Please load the savegame with the appropriate NewGRFs installed.\n" "The missing/compatible NewGRFs are:\n"); - for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (HasBit(c->flags, GCF_COMPATIBLE)) { const GRFIdentifier *replaced = GetOverriddenIdentifier(c); char buf[40]; @@ -416,14 +424,14 @@ static void CDECL HandleSavegameLoadCrash(int signum) ShowInfo(buffer); - SignalHandlerPointer call = NULL; + SignalHandlerPointer call = nullptr; switch (signum) { case SIGSEGV: call = _prev_segfault; break; case SIGABRT: call = _prev_abort; break; case SIGFPE: call = _prev_fpe; break; default: NOT_REACHED(); } - if (call != NULL) call(signum); + if (call != nullptr) call(signum); } /** @@ -436,7 +444,7 @@ static void FixOwnerOfRailTrack(TileIndex t) assert(!Company::IsValidID(GetTileOwner(t)) && (IsLevelCrossingTile(t) || IsPlainRailTile(t))); /* remove leftover rail piece from crossing (from very old savegames) */ - Train *v = NULL, *w; + Train *v = nullptr, *w; FOR_ALL_TRAINS(w) { if (w->tile == t) { v = w; @@ -444,7 +452,7 @@ static void FixOwnerOfRailTrack(TileIndex t) } } - if (v != NULL) { + if (v != nullptr) { /* when there is a train on crossing (it could happen in TTD), set owner of crossing to train owner */ SetTileOwner(t, v->owner); return; @@ -463,8 +471,19 @@ static void FixOwnerOfRailTrack(TileIndex t) if (IsLevelCrossingTile(t)) { /* else change the crossing to normal road (road vehicles won't care) */ - MakeRoadNormal(t, GetCrossingRoadBits(t), GetRoadTypes(t), GetTownIndex(t), - GetRoadOwner(t, ROADTYPE_ROAD), GetRoadOwner(t, ROADTYPE_TRAM)); + Owner road = GetRoadOwner(t, RTT_ROAD); + Owner tram = GetRoadOwner(t, RTT_TRAM); + RoadBits bits = GetCrossingRoadBits(t); + bool hasroad = HasBit(_me[t].m7, 6); + bool hastram = HasBit(_me[t].m7, 7); + + /* MakeRoadNormal */ + SetTileType(t, MP_ROAD); + SetTileOwner(t, road); + _m[t].m3 = (hasroad ? bits : 0); + _m[t].m5 = (hastram ? bits : 0) | ROAD_TILE_NORMAL << 6; + SB(_me[t].m6, 2, 4, 0); + SetRoadOwner(t, RTT_TRAM, tram); return; } @@ -530,17 +549,17 @@ void AfterLoadFindBTProCBInfo() { char *p = buf; int pn; p += Utf8Encode(p, SCC_ENCODED); - for (uint i = 0; i < _current_data->raw_strings.Length(); i++) { - auto ls = _current_data->raw_strings[i]; + for (uint i = 0; i < _current_data->raw_strings.size(); i++) { + auto ls = _current_data->raw_strings[i].get(); if (!ls) continue; int string_id = 0; - for (uint j = 0; j < ls->lines.Length(); j++) { - auto s = ls->lines[j]; - if (!s || *s == ';' || *s == '#' || *s == ' ' || *s == '\0') continue; - if (strncmp(s, "STR_TOWN_CLAIMED_CARGOS", strlen("STR_TOWN_CLAIMED_CARGOS")) == 0 || - strncmp(s, "STR_TOWN_CARGOS_NEEDED_CB", strlen("STR_TOWN_CARGOS_NEEDED_CB")) == 0) { + for (uint j = 0; j < ls->lines.size(); j++) { + auto &s = ls->lines[j]; + if (!s.size() || s[0] == ';' || s[0] == '#' || s[0] == ' ' || s[0] == '\0') continue; + if (strncmp(s.c_str(), "STR_TOWN_CLAIMED_CARGOS", strlen("STR_TOWN_CLAIMED_CARGOS")) == 0 || + strncmp(s.c_str(), "STR_TOWN_CARGOS_NEEDED_CB", strlen("STR_TOWN_CARGOS_NEEDED_CB")) == 0) { pn = p - buf + seprintf(p, lastof(buf), "%X:", string_id); - bool with_decay = (strncmp(s, "STR_TOWN_CLAIMED_CARGOS_DECAY", + bool with_decay = (strncmp(s.c_str(), "STR_TOWN_CLAIMED_CARGOS_DECAY", strlen("STR_TOWN_CLAIMED_CARGOS_DECAY")) == 0); FOR_ALL_STORY_PAGE_ELEMENTS(se) { // DEBUG(misc, 0, "SE: %s", se->text); @@ -583,6 +602,12 @@ bool AfterLoadGame() GamelogTestRevision(); GamelogTestMode(); + RebuildTownKdtree(); + RebuildStationKdtree(); + /* This needs to be done even before conversion, because some conversions will destroy objects + * that otherwise won't exist in the tree. */ + RebuildViewportKdtree(); + if (IsSavegameVersionBefore(SLV_98)) GamelogGRFAddList(_grfconfig); if (IsSavegameVersionBefore(SLV_119)) { @@ -670,22 +695,22 @@ bool AfterLoadGame() Company *c; FOR_ALL_COMPANIES(c) { c->name = CopyFromOldName(c->name_1); - if (c->name != NULL) c->name_1 = STR_SV_UNNAMED; + if (c->name != nullptr) c->name_1 = STR_SV_UNNAMED; c->president_name = CopyFromOldName(c->president_name_1); - if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME; + if (c->president_name != nullptr) c->president_name_1 = SPECSTR_PRESIDENT_NAME; } Station *st; FOR_ALL_STATIONS(st) { st->name = CopyFromOldName(st->string_id); /* generating new name would be too much work for little effect, use the station name fallback */ - if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK; + if (st->name != nullptr) st->string_id = STR_SV_STNAME_FALLBACK; } Town *t; FOR_ALL_TOWNS(t) { t->name = CopyFromOldName(t->townnametype); - if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; + if (t->name != nullptr) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; } } @@ -697,7 +722,6 @@ bool AfterLoadGame() Station *st; FOR_ALL_STATIONS(st) { if (st->airport.tile == 0) st->airport.tile = INVALID_TILE; - if (st->dock_tile == 0) st->dock_tile = INVALID_TILE; if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE; } @@ -715,7 +739,7 @@ bool AfterLoadGame() /* Check if all NewGRFs are present, we are very strict in MP mode */ GRFListCompatibility gcf_res = IsGoodGRFConfigList(_grfconfig); - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (c->status == GCS_NOT_FOUND) { GamelogGRFRemove(c->ident.grfid); } else if (HasBit(c->flags, GCF_COMPATIBLE)) { @@ -826,7 +850,7 @@ bool AfterLoadGame() { Company *c; FOR_ALL_COMPANIES(c) { - if (c->is_ai && c->ai_instance == NULL) AI::StartNew(c->index); + if (c->is_ai && c->ai_instance == nullptr) AI::StartNew(c->index); } } @@ -1026,7 +1050,7 @@ bool AfterLoadGame() if (IsSavegameVersionBefore(SLV_16)) { Company *c; FOR_ALL_COMPANIES(c) { - c->engine_renew_list = NULL; + c->engine_renew_list = nullptr; c->settings.engine_renew = false; c->settings.engine_renew_months = 6; c->settings.engine_renew_money = 100000; @@ -1039,7 +1063,7 @@ bool AfterLoadGame() * companies are 'invalid'. */ c = Company::GetIfValid(COMPANY_FIRST); - if (!_network_dedicated && c != NULL) { + if (!_network_dedicated && c != nullptr) { c->settings = _settings_client.company; } } @@ -1091,18 +1115,18 @@ bool AfterLoadGame() break; case ROAD_TILE_DEPOT: break; } - SetRoadTypes(t, ROADTYPES_ROAD); + SB(_me[t].m7, 6, 2, 1); // Set pre-NRT road type bits for conversion later. break; case MP_STATION: - if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); + if (IsRoadStop(t)) SB(_me[t].m7, 6, 2, 1); break; case MP_TUNNELBRIDGE: /* Middle part of "old" bridges */ if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { - SetRoadTypes(t, ROADTYPES_ROAD); + SB(_me[t].m7, 6, 2, 1); // Set pre-NRT road type bits for conversion later. } break; @@ -1118,7 +1142,7 @@ bool AfterLoadGame() for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_ROAD: - if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_me[t].m7, 5, 3)); + if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_me[t].m7, 5, 3)); SB(_me[t].m7, 5, 1, GB(_m[t].m3, 7, 1)); // snow/desert switch (GetRoadTileType(t)) { default: SlErrorCorrupt("Invalid road tile type"); @@ -1143,7 +1167,7 @@ bool AfterLoadGame() } if (!IsRoadDepot(t) && !HasTownOwnedRoad(t)) { const Town *town = CalcClosestTownFromTile(t); - if (town != NULL) SetTownIndex(t, town->index); + if (town != nullptr) SetTownIndex(t, town->index); } _m[t].m4 = 0; break; @@ -1151,7 +1175,7 @@ bool AfterLoadGame() case MP_STATION: if (!IsRoadStop(t)) break; - if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); + if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_m[t].m3, 0, 3)); SB(_me[t].m7, 0, 5, HasBit(_me[t].m6, 2) ? OWNER_TOWN : GetTileOwner(t)); SB(_m[t].m3, 4, 4, _m[t].m1); _m[t].m4 = 0; @@ -1160,7 +1184,7 @@ bool AfterLoadGame() case MP_TUNNELBRIDGE: if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { - if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); + if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_m[t].m3, 0, 3)); Owner o = GetTileOwner(t); SB(_me[t].m7, 0, 5, o); // road owner @@ -1230,13 +1254,14 @@ bool AfterLoadGame() } else { TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0; - MakeRoadNormal( - t, - axis == AXIS_X ? ROAD_Y : ROAD_X, - ROADTYPES_ROAD, - town, - GetTileOwner(t), OWNER_NONE - ); + /* MakeRoadNormal */ + SetTileType(t, MP_ROAD); + _m[t].m2 = town; + _m[t].m3 = 0; + _m[t].m5 = (axis == AXIS_X ? ROAD_Y : ROAD_X) | ROAD_TILE_NORMAL << 6; + SB(_me[t].m6, 2, 4, 0); + _me[t].m7 = 1 << 6; + SetRoadOwner(t, RTT_TRAM, OWNER_NONE); } } else { if (GB(_m[t].m5, 3, 2) == 0) { @@ -1291,6 +1316,35 @@ bool AfterLoadGame() } } + if (IsSavegameVersionBefore(SLV_ROAD_TYPES)) { + /* Add road subtypes */ + for (TileIndex t = 0; t < map_size; t++) { + bool has_road = false; + switch (GetTileType(t)) { + case MP_ROAD: + has_road = true; + break; + case MP_STATION: + has_road = IsRoadStop(t); + break; + case MP_TUNNELBRIDGE: + has_road = GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD; + break; + default: + break; + } + + if (has_road) { + RoadType road_rt = HasBit(_me[t].m7, 6) ? ROADTYPE_ROAD : INVALID_ROADTYPE; + RoadType tram_rt = HasBit(_me[t].m7, 7) ? ROADTYPE_TRAM : INVALID_ROADTYPE; + + assert(road_rt != INVALID_ROADTYPE || tram_rt != INVALID_ROADTYPE); + SetRoadTypes(t, road_rt, tram_rt); + SB(_me[t].m7, 6, 2, 0); // Clear pre-NRT road type bits. + } + } + } + /* Elrails got added in rev 24 */ if (IsSavegameVersionBefore(SLV_24)) { RailType min_rail = RAILTYPE_ELECTRIC; @@ -1414,7 +1468,7 @@ bool AfterLoadGame() Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = GetCompanyRailtypes(c->index); - c->avail_roadtypes = GetCompanyRoadtypes(c->index); + c->avail_roadtypes = GetCompanyRoadTypes(c->index); } if (!IsSavegameVersionBefore(SLV_27)) AfterLoadStations(); @@ -1750,9 +1804,9 @@ bool AfterLoadGame() Vehicle *v; FOR_ALL_VEHICLES(v) { - if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && v->orders.list->GetFirstOrder()->IsType(OT_NOTHING)) { + if (v->orders.list != nullptr && v->orders.list->GetFirstOrder() != nullptr && v->orders.list->GetFirstOrder()->IsType(OT_NOTHING)) { v->orders.list->FreeChain(); - v->orders.list = NULL; + v->orders.list = nullptr; } v->current_order.ConvertFromOldSavegame(); @@ -1874,7 +1928,7 @@ bool AfterLoadGame() if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { Owner o = GetTileOwner(t); if (o < MAX_COMPANIES && !Company::IsValidID(o)) { - Backup cur_company(_current_company, o, FILE_LINE); + Backup cur_company(_current_company, o, FILE_LINE); ChangeTileOwner(t, o, INVALID_OWNER); cur_company.Restore(); } @@ -1885,10 +1939,10 @@ bool AfterLoadGame() } } else if (IsTileType(t, MP_ROAD)) { /* works for all RoadTileType */ - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* update even non-existing road types to update tile owner too */ - Owner o = GetRoadOwner(t, rt); - if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rt, OWNER_NONE); + Owner o = GetRoadOwner(t, rtt); + if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rtt, OWNER_NONE); } if (IsLevelCrossing(t)) { if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); @@ -1914,7 +1968,7 @@ bool AfterLoadGame() if (_settings_game.pf.yapf.ship_use_yapf) { _settings_game.pf.pathfinder_for_ships = VPF_YAPF; } else { - _settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); + _settings_game.pf.pathfinder_for_ships = VPF_NPF; } } @@ -2150,7 +2204,7 @@ bool AfterLoadGame() _settings_game.economy.town_layout = TL_BETTER_ROADS; } else { _settings_game.economy.allow_town_roads = true; - _settings_game.economy.town_layout = _settings_game.economy.town_layout - 1; + _settings_game.economy.town_layout = static_cast(_settings_game.economy.town_layout - 1); } /* Initialize layout of all towns. Older versions were using different @@ -2169,7 +2223,7 @@ bool AfterLoadGame() case 5: layout = 1; break; case 0: layout = 2; break; } - t->layout = layout - 1; + t->layout = static_cast(layout - 1); } } @@ -2205,7 +2259,7 @@ bool AfterLoadGame() FOR_ALL_DISASTERVEHICLES(v) { if (v->subtype == 2 /* ST_SMALL_UFO */ && v->current_order.GetDestination() != 0) { const Vehicle *u = Vehicle::GetIfValid(v->dest_tile); - if (u == NULL || u->type != VEH_ROAD || !RoadVehicle::From(u)->IsFrontEngine()) { + if (u == nullptr || u->type != VEH_ROAD || !RoadVehicle::From(u)->IsFrontEngine()) { delete v; } } @@ -2226,7 +2280,7 @@ bool AfterLoadGame() assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); assert(CargoPayment::CanAllocateItem()); Vehicle *v = *iter; - if (v->cargo_payment == NULL) v->cargo_payment = new CargoPayment(v); + if (v->cargo_payment == nullptr) v->cargo_payment = new CargoPayment(v); } } } @@ -2235,14 +2289,14 @@ bool AfterLoadGame() /* Animated tiles would sometimes not be actually animated or * in case of old savegames duplicate. */ - extern SmallVector _animated_tiles; + extern std::vector _animated_tiles; - for (TileIndex *tile = _animated_tiles.Begin(); tile < _animated_tiles.End(); /* Nothing */) { + for (auto tile = _animated_tiles.begin(); tile < _animated_tiles.end(); /* Nothing */) { /* Remove if tile is not animated */ - bool remove = _tile_type_procs[GetTileType(*tile)]->animate_tile_proc == NULL; + bool remove = _tile_type_procs[GetTileType(*tile)]->animate_tile_proc == nullptr; /* and remove if duplicate */ - for (TileIndex *j = _animated_tiles.Begin(); !remove && j < tile; j++) { + for (auto j = _animated_tiles.begin(); !remove && j < tile; j++) { remove = *tile == *j; } @@ -2311,7 +2365,7 @@ bool AfterLoadGame() /* Town -> Town */ const Station *ss = Station::GetIfValid(s->src); const Station *sd = Station::GetIfValid(s->dst); - if (ss != NULL && sd != NULL && ss->owner == sd->owner && + if (ss != nullptr && sd != nullptr && ss->owner == sd->owner && Company::IsValidID(ss->owner)) { s->src_type = s->dst_type = ST_TOWN; s->src = ss->town->index; @@ -2486,13 +2540,13 @@ bool AfterLoadGame() FOR_ALL_AIRCRAFT(v) { if (!v->IsNormalAircraft()) continue; Station *st = GetTargetAirportIfValid(v); - if (st == NULL && v->state != FLYING) { + if (st == nullptr && v->state != FLYING) { v->state = FLYING; UpdateAircraftCache(v); AircraftNextAirportPos_and_Order(v); /* get aircraft back on running altitude */ if ((v->vehstatus & VS_CRASHED) == 0) { - GetAircraftFlightLevelBounds(v, &v->z_pos, NULL); + GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr); SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v)); } } @@ -2554,11 +2608,11 @@ bool AfterLoadGame() * order they have in the pool. */ Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { - if (wp->name != NULL) wp->town_cn = UINT16_MAX; + if (wp->name != nullptr) wp->town_cn = UINT16_MAX; } FOR_ALL_WAYPOINTS(wp) { - if (wp->name != NULL) MakeDefaultName(wp); + if (wp->name != nullptr) MakeDefaultName(wp); } } @@ -2701,7 +2755,7 @@ bool AfterLoadGame() if (rv->state == RVSB_IN_DEPOT || rv->state == RVSB_WORMHOLE) break; - TrackStatus ts = GetTileTrackStatus(rv->tile, TRANSPORT_ROAD, rv->compatible_roadtypes); + TrackStatus ts = GetTileTrackStatus(rv->tile, TRANSPORT_ROAD, GetRoadTramType(rv->roadtype)); TrackBits trackbits = TrackStatusToTrackBits(ts); /* Only X/Y tracks can be sloped. */ @@ -2790,7 +2844,7 @@ bool AfterLoadGame() if (!IsSavegameVersionBefore(SLV_76)) { Industry *ind; FOR_ALL_INDUSTRIES(ind) { - assert(ind->psa != NULL); + assert(ind->psa != nullptr); /* Check if the old storage was empty. */ bool is_empty = true; @@ -2805,7 +2859,7 @@ bool AfterLoadGame() ind->psa->grfid = _industry_mngr.GetGRFID(ind->type); } else { delete ind->psa; - ind->psa = NULL; + ind->psa = nullptr; } } } @@ -2814,7 +2868,7 @@ bool AfterLoadGame() Station *st; FOR_ALL_STATIONS(st) { if (!(st->facilities & FACIL_AIRPORT)) continue; - assert(st->airport.psa != NULL); + assert(st->airport.psa != nullptr); /* Check if the old storage was empty. */ bool is_empty = true; @@ -2829,7 +2883,7 @@ bool AfterLoadGame() st->airport.psa->grfid = _airport_mngr.GetGRFID(st->airport.type); } else { delete st->airport.psa; - st->airport.psa = NULL; + st->airport.psa = nullptr; } } @@ -2869,12 +2923,12 @@ bool AfterLoadGame() /* Set the default cargo requirement for town growth */ switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: - if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER; + if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER; break; case LT_TROPIC: - if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT; - if (FindFirstCargoWithTownEffect(TE_WATER) != NULL) t->goal[TE_WATER] = TOWN_GROWTH_DESERT; + if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT; + if (FindFirstCargoWithTownEffect(TE_WATER) != nullptr) t->goal[TE_WATER] = TOWN_GROWTH_DESERT; break; } } @@ -2882,7 +2936,7 @@ bool AfterLoadGame() if (IsSavegameVersionBefore(SLV_165)) { /* Adjust zoom level to account for new levels */ - _saved_scrollpos_zoom = _saved_scrollpos_zoom + ZOOM_LVL_SHIFT; + _saved_scrollpos_zoom = static_cast(_saved_scrollpos_zoom + ZOOM_LVL_SHIFT); _saved_scrollpos_x *= ZOOM_LVL_BASE; _saved_scrollpos_y *= ZOOM_LVL_BASE; } @@ -2910,8 +2964,8 @@ bool AfterLoadGame() for (TileIndex t = 0; t < map_size; t++) { if (!IsStandardRoadStopTile(t)) continue; Owner o = GetTileOwner(t); - SetRoadOwner(t, ROADTYPE_ROAD, o); - SetRoadOwner(t, ROADTYPE_TRAM, o); + SetRoadOwner(t, RTT_ROAD, o); + SetRoadOwner(t, RTT_TRAM, o); } } @@ -2987,14 +3041,14 @@ bool AfterLoadGame() * So, make articulated parts catch up. */ RoadVehicle *v; bool roadside = _settings_game.vehicle.road_side == 1; - SmallVector skip_frames; + std::vector skip_frames; FOR_ALL_ROADVEHICLES(v) { if (!v->IsFrontEngine()) continue; - skip_frames.Clear(); + skip_frames.clear(); TileIndex prev_tile = v->tile; uint prev_tile_skip = 0; uint cur_skip = 0; - for (RoadVehicle *u = v; u != NULL; u = u->Next()) { + for (RoadVehicle *u = v; u != nullptr; u = u->Next()) { if (u->tile != prev_tile) { prev_tile_skip = cur_skip; prev_tile = u->tile; @@ -3002,24 +3056,24 @@ bool AfterLoadGame() cur_skip = prev_tile_skip; } - uint *this_skip = skip_frames.Append(); - *this_skip = prev_tile_skip; + /*C++17: uint &this_skip = */ skip_frames.push_back(prev_tile_skip); + uint &this_skip = skip_frames.back(); /* The following 3 curves now take longer than before */ switch (u->state) { case 2: cur_skip++; - if (u->frame <= (roadside ? 9 : 5)) *this_skip = cur_skip; + if (u->frame <= (roadside ? 9 : 5)) this_skip = cur_skip; break; case 4: cur_skip++; - if (u->frame <= (roadside ? 5 : 9)) *this_skip = cur_skip; + if (u->frame <= (roadside ? 5 : 9)) this_skip = cur_skip; break; case 5: cur_skip++; - if (u->frame <= (roadside ? 4 : 2)) *this_skip = cur_skip; + if (u->frame <= (roadside ? 4 : 2)) this_skip = cur_skip; break; default: @@ -3028,10 +3082,13 @@ bool AfterLoadGame() } while (cur_skip > skip_frames[0]) { RoadVehicle *u = v; - RoadVehicle *prev = NULL; - for (uint *it = skip_frames.Begin(); it != skip_frames.End(); ++it, prev = u, u = u->Next()) { + RoadVehicle *prev = nullptr; + for (uint sf : skip_frames) { extern bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev); - if (*it >= cur_skip) IndividualRoadVehicleController(u, prev); + if (sf >= cur_skip) IndividualRoadVehicleController(u, prev); + + prev = u; + u = u->Next(); } cur_skip--; } @@ -3135,13 +3192,61 @@ bool AfterLoadGame() } } - { - /* Update water class for trees for all current savegame versions. */ + if (IsSavegameVersionBefore(SLV_TOWN_CARGOGEN)) { + /* Ensure the original cargo generation mode is used */ + _settings_game.economy.town_cargogen_mode = TCGM_ORIGINAL; + } + + if (IsSavegameVersionBefore(SLV_SERVE_NEUTRAL_INDUSTRIES)) { + /* Ensure the original neutral industry/station behaviour is used */ + _settings_game.station.serve_neutral_industries = true; + + /* Link oil rigs to their industry and back. */ + Station *st; + FOR_ALL_STATIONS(st) { + if (IsTileType(st->xy, MP_STATION) && IsOilRig(st->xy)) { + /* Industry tile is always adjacent during construction by TileDiffXY(0, 1) */ + st->industry = Industry::GetByTile(st->xy + TileDiffXY(0, 1)); + st->industry->neutral_station = st; + } + } + } else { + /* Link neutral station back to industry, as this is not saved. */ + Industry *ind; + FOR_ALL_INDUSTRIES(ind) if (ind->neutral_station != nullptr) ind->neutral_station->industry = ind; + } + + if (IsSavegameVersionBefore(SLV_TREES_WATER_CLASS)) { + /* Update water class for trees. */ for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_TREES)) SetWaterClass(t, GetTreeGround(t) == TREE_GROUND_SHORE ? WATER_CLASS_SEA : WATER_CLASS_INVALID); } } + /* Update structures for multitile docks */ + if (IsSavegameVersionBefore(SLV_MULTITILE_DOCKS)) { + for (TileIndex t = 0; t < map_size; t++) { + /* Clear docking tile flag from relevant tiles as it + * was not previously cleared. */ + if (IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)) { + SetDockingTile(t, false); + } + /* Add docks and oilrigs to Station::ship_station. */ + if (IsTileType(t, MP_STATION)) { + if (IsDock(t) || IsOilRig(t)) Station::GetByTile(t)->ship_station.Add(t); + } + } + + /* Scan for docking tiles */ + Station *st; + FOR_ALL_STATIONS(st) { + if (st->ship_station.tile != INVALID_TILE) UpdateStationDockingTiles(st); + } + } + + /* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */ + Station::RecomputeCatchmentForAll(); + /* Station acceptance is some kind of cache */ if (IsSavegameVersionBefore(SLV_127)) { Station *st; diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp index 2492bb666a..336c773d50 100644 --- a/src/saveload/ai_sl.cpp +++ b/src/saveload/ai_sl.cpp @@ -53,7 +53,7 @@ static void SaveReal_AIPL(int *index_ptr) _ai_saveload_settings[0] = '\0'; config->SettingsToString(_ai_saveload_settings, lastof(_ai_saveload_settings)); - SlObject(NULL, _ai_company); + SlObject(nullptr, _ai_company); /* If the AI was active, store his data too */ if (Company::IsValidAiID(index)) AI::Save(index); } @@ -62,7 +62,7 @@ static void Load_AIPL() { /* Free all current data */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(NULL); + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(nullptr); } CompanyID index; @@ -71,7 +71,7 @@ static void Load_AIPL() _ai_saveload_is_random = 0; _ai_saveload_version = -1; - SlObject(NULL, _ai_company); + SlObject(nullptr, _ai_company); if (_networking && !_network_server) { if (Company::IsValidAiID(index)) AIInstance::LoadEmpty(); @@ -81,7 +81,7 @@ static void Load_AIPL() AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME); if (StrEmpty(_ai_saveload_name)) { /* A random AI. */ - config->Change(NULL, -1, false, true); + config->Change(nullptr, -1, false, true); } else { config->Change(_ai_saveload_name, _ai_saveload_version, false, _ai_saveload_is_random); if (!config->HasScript()) { @@ -125,5 +125,5 @@ static void Save_AIPL() } extern const ChunkHandler _ai_chunk_handlers[] = { - { 'AIPL', Save_AIPL, Load_AIPL, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'AIPL', Save_AIPL, Load_AIPL, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/airport_sl.cpp b/src/saveload/airport_sl.cpp index 1172d2593e..ef207bacb1 100644 --- a/src/saveload/airport_sl.cpp +++ b/src/saveload/airport_sl.cpp @@ -37,6 +37,6 @@ static void Load_ATID() } extern const ChunkHandler _airport_chunk_handlers[] = { - { 'ATID', Save_ATID, Load_ATID, NULL, NULL, CH_ARRAY }, - { 'APID', Save_APID, Load_APID, NULL, NULL, CH_ARRAY | CH_LAST }, + { 'ATID', Save_ATID, Load_ATID, nullptr, nullptr, CH_ARRAY }, + { 'APID', Save_APID, Load_APID, nullptr, nullptr, CH_ARRAY | CH_LAST }, }; diff --git a/src/saveload/animated_tile_sl.cpp b/src/saveload/animated_tile_sl.cpp index c54c4724ab..aab06f6670 100644 --- a/src/saveload/animated_tile_sl.cpp +++ b/src/saveload/animated_tile_sl.cpp @@ -18,15 +18,15 @@ #include "../safeguards.h" -extern SmallVector _animated_tiles; +extern std::vector _animated_tiles; /** * Save the ANIT chunk. */ static void Save_ANIT() { - SlSetLength(_animated_tiles.Length() * sizeof(*_animated_tiles.Begin())); - SlArray(_animated_tiles.Begin(), _animated_tiles.Length(), SLE_UINT32); + SlSetLength(_animated_tiles.size() * sizeof(_animated_tiles.front())); + SlArray(_animated_tiles.data(), _animated_tiles.size(), SLE_UINT32); } /** @@ -42,15 +42,15 @@ static void Load_ANIT() for (int i = 0; i < 256; i++) { if (anim_list[i] == 0) break; - *_animated_tiles.Append() = anim_list[i]; + _animated_tiles.push_back(anim_list[i]); } return; } - uint count = (uint)SlGetFieldLength() / sizeof(*_animated_tiles.Begin()); - _animated_tiles.Clear(); - _animated_tiles.Append(count); - SlArray(_animated_tiles.Begin(), count, SLE_UINT32); + uint count = (uint)SlGetFieldLength() / sizeof(_animated_tiles.front()); + _animated_tiles.clear(); + _animated_tiles.resize(_animated_tiles.size() + count); + SlArray(_animated_tiles.data(), count, SLE_UINT32); } /** @@ -58,5 +58,5 @@ static void Load_ANIT() * the animated tile table. */ extern const ChunkHandler _animated_tile_chunk_handlers[] = { - { 'ANIT', Save_ANIT, Load_ANIT, NULL, NULL, CH_RIFF | CH_LAST}, + { 'ANIT', Save_ANIT, Load_ANIT, nullptr, nullptr, CH_RIFF | CH_LAST}, }; diff --git a/src/saveload/autoreplace_sl.cpp b/src/saveload/autoreplace_sl.cpp index 1798df1ada..6493b6f452 100644 --- a/src/saveload/autoreplace_sl.cpp +++ b/src/saveload/autoreplace_sl.cpp @@ -63,5 +63,5 @@ static void Ptrs_ERNW() } extern const ChunkHandler _autoreplace_chunk_handlers[] = { - { 'ERNW', Save_ERNW, Load_ERNW, Ptrs_ERNW, NULL, CH_ARRAY | CH_LAST}, + { 'ERNW', Save_ERNW, Load_ERNW, Ptrs_ERNW, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/cargomonitor_sl.cpp b/src/saveload/cargomonitor_sl.cpp index 9a313970ff..97acc435e1 100644 --- a/src/saveload/cargomonitor_sl.cpp +++ b/src/saveload/cargomonitor_sl.cpp @@ -121,6 +121,6 @@ static void LoadPickup() /** Chunk definition of the cargomonitoring maps. */ extern const ChunkHandler _cargomonitor_chunk_handlers[] = { - { 'CMDL', SaveDelivery, LoadDelivery, NULL, NULL, CH_ARRAY}, - { 'CMPU', SavePickup, LoadPickup, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'CMDL', SaveDelivery, LoadDelivery, nullptr, nullptr, CH_ARRAY}, + { 'CMPU', SavePickup, LoadPickup, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/cargopacket_sl.cpp b/src/saveload/cargopacket_sl.cpp index e3f372e9a8..51cdf1cf16 100644 --- a/src/saveload/cargopacket_sl.cpp +++ b/src/saveload/cargopacket_sl.cpp @@ -139,5 +139,5 @@ static void Load_CAPA() /** Chunk handlers related to cargo packets. */ extern const ChunkHandler _cargopacket_chunk_handlers[] = { - { 'CAPA', Save_CAPA, Load_CAPA, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'CAPA', Save_CAPA, Load_CAPA, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/cheat_sl.cpp b/src/saveload/cheat_sl.cpp index 4616b7e852..e7b4735a9e 100644 --- a/src/saveload/cheat_sl.cpp +++ b/src/saveload/cheat_sl.cpp @@ -51,5 +51,5 @@ static void Load_CHTS() /** Chunk handlers related to cheats. */ extern const ChunkHandler _cheat_chunk_handlers[] = { - { 'CHTS', Save_CHTS, Load_CHTS, NULL, NULL, CH_RIFF | CH_LAST}, + { 'CHTS', Save_CHTS, Load_CHTS, nullptr, nullptr, CH_RIFF | CH_LAST}, }; diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp index a51f8081b0..f934848e9d 100644 --- a/src/saveload/company_sl.cpp +++ b/src/saveload/company_sl.cpp @@ -111,7 +111,7 @@ void AfterLoadCompanyStats() switch (GetTileType(tile)) { case MP_RAILWAY: c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + if (c != nullptr) { uint pieces = 1; if (IsPlainRail(tile)) { TrackBits bits = GetTrackBits(tile); @@ -127,36 +127,38 @@ void AfterLoadCompanyStats() case MP_ROAD: { if (IsLevelCrossing(tile)) { c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR; + if (c != nullptr) c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR; } /* Iterate all present road types as each can have a different owner. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rt)); + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + if (rt == INVALID_ROADTYPE) continue; + c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rtt)); /* A level crossings and depots have two road bits. */ - if (c != NULL) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rt)) : 2; + if (c != nullptr) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rtt)) : 2; } break; } case MP_STATION: c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL && GetStationType(tile) != STATION_AIRPORT && !IsBuoy(tile)) c->infrastructure.station++; + if (c != nullptr && GetStationType(tile) != STATION_AIRPORT && !IsBuoy(tile)) c->infrastructure.station++; switch (GetStationType(tile)) { case STATION_RAIL: case STATION_WAYPOINT: - if (c != NULL && !IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]++; + if (c != nullptr && !IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]++; break; case STATION_BUS: case STATION_TRUCK: { /* Iterate all present road types as each can have a different owner. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) c->infrastructure.road[rt] += 2; // A road stop has two road bits. + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + if (rt == INVALID_ROADTYPE) continue; + c = Company::GetIfValid(GetRoadOwner(tile, rtt)); + if (c != nullptr) c->infrastructure.road[rt] += 2; // A road stop has two road bits. } break; } @@ -164,7 +166,7 @@ void AfterLoadCompanyStats() case STATION_DOCK: case STATION_BUOY: if (GetWaterClass(tile) == WATER_CLASS_CANAL) { - if (c != NULL) c->infrastructure.water++; + if (c != nullptr) c->infrastructure.water++; } break; @@ -176,7 +178,7 @@ void AfterLoadCompanyStats() case MP_WATER: if (IsShipDepot(tile) || IsLock(tile)) { c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + if (c != nullptr) { if (IsShipDepot(tile)) c->infrastructure.water += LOCK_DEPOT_TILE_FACTOR; if (IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE) { /* The middle tile specifies the owner of the lock. */ @@ -190,7 +192,7 @@ void AfterLoadCompanyStats() case MP_OBJECT: if (GetWaterClass(tile) == WATER_CLASS_CANAL) { c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) c->infrastructure.water++; + if (c != nullptr) c->infrastructure.water++; } break; @@ -205,22 +207,23 @@ void AfterLoadCompanyStats() switch (GetTunnelBridgeTransportType(tile)) { case TRANSPORT_RAIL: c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += len; + if (c != nullptr) c->infrastructure.rail[GetRailType(tile)] += len; break; case TRANSPORT_ROAD: { /* Iterate all present road types as each can have a different owner. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) c->infrastructure.road[rt] += len * 2; // A full diagonal road has two road bits. + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + if (rt == INVALID_ROADTYPE) continue; + c = Company::GetIfValid(GetRoadOwner(tile, rtt)); + if (c != nullptr) c->infrastructure.road[rt] += len * 2; // A full diagonal road has two road bits. } break; } case TRANSPORT_WATER: c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) c->infrastructure.water += len; + if (c != nullptr) c->infrastructure.water += len; break; default: @@ -414,7 +417,7 @@ static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) int i; SlObject(cprops, _company_desc); - if (c != NULL) { + if (c != nullptr) { SlObject(c, _company_settings_desc); } else { char nothing; @@ -444,7 +447,7 @@ static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) /* Write each livery entry. */ int num_liveries = IsSavegameVersionBefore(SLV_63) ? LS_END - 4 : (IsSavegameVersionBefore(SLV_85) ? LS_END - 2: LS_END); bool update_in_use = IsSavegameVersionBefore(SLV_GROUP_LIVERIES); - if (c != NULL) { + if (c != nullptr) { for (i = 0; i < num_liveries; i++) { SlObject(&c->livery[i], _company_livery_desc); if (update_in_use && i != LS_DEFAULT) { @@ -507,7 +510,7 @@ static void Check_PLYR() int index; while ((index = SlIterateArray()) != -1) { CompanyProperties *cprops = new CompanyProperties(); - SaveLoad_PLYR_common(NULL, cprops); + SaveLoad_PLYR_common(nullptr, cprops); /* We do not load old custom names */ if (IsSavegameVersionBefore(SLV_84)) { @@ -520,7 +523,7 @@ static void Check_PLYR() } } - if (cprops->name == NULL && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) && + if (cprops->name == nullptr && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) && cprops->name_1 != STR_GAME_SAVELOAD_NOT_AVAILABLE && cprops->name_1 != STR_SV_UNNAMED && cprops->name_1 != SPECSTR_ANDCO_NAME && cprops->name_1 != SPECSTR_PRESIDENT_NAME && cprops->name_1 != SPECSTR_SILLY_NAME) { diff --git a/src/saveload/depot_sl.cpp b/src/saveload/depot_sl.cpp index b92417693c..74559f9237 100644 --- a/src/saveload/depot_sl.cpp +++ b/src/saveload/depot_sl.cpp @@ -64,5 +64,5 @@ static void Ptrs_DEPT() } extern const ChunkHandler _depot_chunk_handlers[] = { - { 'DEPT', Save_DEPT, Load_DEPT, Ptrs_DEPT, NULL, CH_ARRAY | CH_LAST}, + { 'DEPT', Save_DEPT, Load_DEPT, Ptrs_DEPT, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/economy_sl.cpp b/src/saveload/economy_sl.cpp index 0ddab13514..754d07ebdc 100644 --- a/src/saveload/economy_sl.cpp +++ b/src/saveload/economy_sl.cpp @@ -22,8 +22,8 @@ static void Load_PRIC() { /* Old games store 49 base prices, very old games store them as int32 */ int vt = IsSavegameVersionBefore(SLV_65) ? SLE_FILE_I32 : SLE_FILE_I64; - SlArray(NULL, 49, vt | SLE_VAR_NULL); - SlArray(NULL, 49, SLE_FILE_U16 | SLE_VAR_NULL); + SlArray(nullptr, 49, vt | SLE_VAR_NULL); + SlArray(nullptr, 49, SLE_FILE_U16 | SLE_VAR_NULL); } /** Cargo payment rates in pre 126 savegames */ @@ -31,8 +31,8 @@ static void Load_CAPR() { uint num_cargo = IsSavegameVersionBefore(SLV_55) ? 12 : IsSavegameVersionBefore(SLV_EXTEND_CARGOTYPES) ? 32 : NUM_CARGO; int vt = IsSavegameVersionBefore(SLV_65) ? SLE_FILE_I32 : SLE_FILE_I64; - SlArray(NULL, num_cargo, vt | SLE_VAR_NULL); - SlArray(NULL, num_cargo, SLE_FILE_U16 | SLE_VAR_NULL); + SlArray(nullptr, num_cargo, vt | SLE_VAR_NULL); + SlArray(nullptr, num_cargo, SLE_FILE_U16 | SLE_VAR_NULL); } static const SaveLoad _economy_desc[] = { @@ -101,8 +101,8 @@ static void Ptrs_CAPY() extern const ChunkHandler _economy_chunk_handlers[] = { - { 'CAPY', Save_CAPY, Load_CAPY, Ptrs_CAPY, NULL, CH_ARRAY}, - { 'PRIC', NULL, Load_PRIC, NULL, NULL, CH_RIFF | CH_AUTO_LENGTH}, - { 'CAPR', NULL, Load_CAPR, NULL, NULL, CH_RIFF | CH_AUTO_LENGTH}, - { 'ECMY', Save_ECMY, Load_ECMY, NULL, NULL, CH_RIFF | CH_LAST}, + { 'CAPY', Save_CAPY, Load_CAPY, Ptrs_CAPY, nullptr, CH_ARRAY}, + { 'PRIC', nullptr, Load_PRIC, nullptr, nullptr, CH_RIFF | CH_AUTO_LENGTH}, + { 'CAPR', nullptr, Load_CAPR, nullptr, nullptr, CH_RIFF | CH_AUTO_LENGTH}, + { 'ECMY', Save_ECMY, Load_ECMY, nullptr, nullptr, CH_RIFF | CH_LAST}, }; diff --git a/src/saveload/engine_sl.cpp b/src/saveload/engine_sl.cpp index 5221d1bbdc..f4c017bb16 100644 --- a/src/saveload/engine_sl.cpp +++ b/src/saveload/engine_sl.cpp @@ -68,7 +68,7 @@ static Engine* CallocEngine() */ static void FreeEngine(Engine *e) { - if (e != NULL) { + if (e != nullptr) { e->~Engine(); free(e); } @@ -141,7 +141,7 @@ void CopyTempEngineData() e->preview_wait = se->preview_wait; e->company_avail = se->company_avail; e->company_hidden = se->company_hidden; - if (se->name != NULL) e->name = stredup(se->name); + if (se->name != nullptr) e->name = stredup(se->name); } /* Get rid of temporary data */ @@ -177,26 +177,27 @@ static const SaveLoad _engine_id_mapping_desc[] = { static void Save_EIDS() { - const EngineIDMapping *end = _engine_mngr.End(); uint index = 0; - for (EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) { + for (EngineIDMapping &eid : _engine_mngr) { SlSetArrayIndex(index); - SlObject(eid, _engine_id_mapping_desc); + SlObject(&eid, _engine_id_mapping_desc); + index++; } } static void Load_EIDS() { - _engine_mngr.Clear(); + _engine_mngr.clear(); while (SlIterateArray() != -1) { - EngineIDMapping *eid = _engine_mngr.Append(); + /*C++17: EngineIDMapping *eid = &*/ _engine_mngr.emplace_back(); + EngineIDMapping *eid = &_engine_mngr.back(); SlObject(eid, _engine_id_mapping_desc); } } extern const ChunkHandler _engine_chunk_handlers[] = { - { 'EIDS', Save_EIDS, Load_EIDS, NULL, NULL, CH_ARRAY }, - { 'ENGN', Save_ENGN, Load_ENGN, NULL, NULL, CH_ARRAY }, - { 'ENGS', NULL, Load_ENGS, NULL, NULL, CH_RIFF | CH_LAST }, + { 'EIDS', Save_EIDS, Load_EIDS, nullptr, nullptr, CH_ARRAY }, + { 'ENGN', Save_ENGN, Load_ENGN, nullptr, nullptr, CH_ARRAY }, + { 'ENGS', nullptr, Load_ENGS, nullptr, nullptr, CH_RIFF | CH_LAST }, }; diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp index 325ae1c9d4..3602f0f29b 100644 --- a/src/saveload/game_sl.cpp +++ b/src/saveload/game_sl.cpp @@ -52,19 +52,19 @@ static void SaveReal_GSDT(int *index_ptr) _game_saveload_settings[0] = '\0'; config->SettingsToString(_game_saveload_settings, lastof(_game_saveload_settings)); - SlObject(NULL, _game_script); + SlObject(nullptr, _game_script); Game::Save(); } static void Load_GSDT() { /* Free all current data */ - GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(NULL); + GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(nullptr); if ((CompanyID)SlIterateArray() == (CompanyID)-1) return; _game_saveload_version = -1; - SlObject(NULL, _game_script); + SlObject(nullptr, _game_script); if (_networking && !_network_server) { GameInstance::LoadEmpty(); @@ -110,7 +110,7 @@ static void Load_GSDT() static void Save_GSDT() { SlSetArrayIndex(0); - SlAutolength((AutolengthProc *)SaveReal_GSDT, NULL); + SlAutolength((AutolengthProc *)SaveReal_GSDT, nullptr); } extern GameStrings *_current_data; @@ -129,15 +129,15 @@ static const SaveLoad _game_language_string[] = { SLE_END() }; -static void SaveReal_GSTR(LanguageStrings *ls) +static void SaveReal_GSTR(const LanguageStrings *ls) { _game_saveload_string = ls->language; - _game_saveload_strings = ls->lines.Length(); + _game_saveload_strings = (uint)ls->lines.size(); - SlObject(NULL, _game_language_header); - for (uint i = 0; i < _game_saveload_strings; i++) { - _game_saveload_string = ls->lines[i]; - SlObject(NULL, _game_language_string); + SlObject(nullptr, _game_language_header); + for (const auto &i : ls->lines) { + _game_saveload_string = i.c_str(); + SlObject(nullptr, _game_language_string); } } @@ -147,22 +147,22 @@ static void Load_GSTR() _current_data = new GameStrings(); while (SlIterateArray() != -1) { - _game_saveload_string = NULL; - SlObject(NULL, _game_language_header); + _game_saveload_string = nullptr; + SlObject(nullptr, _game_language_header); - LanguageStrings *ls = new LanguageStrings(_game_saveload_string != NULL ? _game_saveload_string : ""); + std::unique_ptr ls(new LanguageStrings(_game_saveload_string != nullptr ? _game_saveload_string : "")); for (uint i = 0; i < _game_saveload_strings; i++) { - SlObject(NULL, _game_language_string); - *ls->lines.Append() = stredup(_game_saveload_string != NULL ? _game_saveload_string : ""); + SlObject(nullptr, _game_language_string); + ls->lines.emplace_back(_game_saveload_string != nullptr ? _game_saveload_string : ""); } - *_current_data->raw_strings.Append() = ls; + _current_data->raw_strings.push_back(std::move(ls)); } - /* If there were no strings in the savegame, set GameStrings to NULL */ - if (_current_data->raw_strings.Length() == 0) { + /* If there were no strings in the savegame, set GameStrings to nullptr */ + if (_current_data->raw_strings.size() == 0) { delete _current_data; - _current_data = NULL; + _current_data = nullptr; return; } @@ -172,15 +172,15 @@ static void Load_GSTR() static void Save_GSTR() { - if (_current_data == NULL) return; + if (_current_data == nullptr) return; - for (uint i = 0; i < _current_data->raw_strings.Length(); i++) { + for (uint i = 0; i < _current_data->raw_strings.size(); i++) { SlSetArrayIndex(i); - SlAutolength((AutolengthProc *)SaveReal_GSTR, _current_data->raw_strings[i]); + SlAutolength((AutolengthProc *)SaveReal_GSTR, _current_data->raw_strings[i].get()); } } extern const ChunkHandler _game_chunk_handlers[] = { - { 'GSTR', Save_GSTR, Load_GSTR, NULL, NULL, CH_ARRAY }, - { 'GSDT', Save_GSDT, Load_GSDT, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'GSTR', Save_GSTR, Load_GSTR, nullptr, nullptr, CH_ARRAY }, + { 'GSDT', Save_GSDT, Load_GSDT, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index d1c502d3be..812d716ecf 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -106,7 +106,7 @@ assert_compile(lengthof(_glog_desc) == GLCT_END); static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions) { - assert(gamelog_action == NULL); + assert(gamelog_action == nullptr); assert(gamelog_actions == 0); GamelogActionType at; @@ -117,7 +117,7 @@ static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_action la->at = at; SlObject(la, _glog_action_desc); // has to be saved after 'DATE'! - la->change = NULL; + la->change = nullptr; la->changes = 0; GamelogChangeType ct; @@ -125,7 +125,7 @@ static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_action la->change = ReallocT(la->change, la->changes + 1); LoggedChange *lc = &la->change[la->changes++]; - /* for SLE_STR, pointer has to be valid! so make it NULL */ + /* for SLE_STR, pointer has to be valid! so make it nullptr */ memset(lc, 0, sizeof(*lc)); lc->ct = ct; @@ -179,5 +179,5 @@ static void Check_GLOG() } extern const ChunkHandler _gamelog_chunk_handlers[] = { - { 'GLOG', Save_GLOG, Load_GLOG, NULL, Check_GLOG, CH_RIFF | CH_LAST } + { 'GLOG', Save_GLOG, Load_GLOG, nullptr, Check_GLOG, CH_RIFF | CH_LAST } }; diff --git a/src/saveload/goal_sl.cpp b/src/saveload/goal_sl.cpp index a8cdc2305d..b636dcf6a2 100644 --- a/src/saveload/goal_sl.cpp +++ b/src/saveload/goal_sl.cpp @@ -45,5 +45,5 @@ static void Load_GOAL() } extern const ChunkHandler _goal_chunk_handlers[] = { - { 'GOAL', Save_GOAL, Load_GOAL, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'GOAL', Save_GOAL, Load_GOAL, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/group_sl.cpp b/src/saveload/group_sl.cpp index 025c8ee3a7..e431401328 100644 --- a/src/saveload/group_sl.cpp +++ b/src/saveload/group_sl.cpp @@ -61,5 +61,5 @@ static void Load_GRPS() } extern const ChunkHandler _group_chunk_handlers[] = { - { 'GRPS', Save_GRPS, Load_GRPS, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'GRPS', Save_GRPS, Load_GRPS, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/industry_sl.cpp b/src/saveload/industry_sl.cpp index 9e81861c4e..34fa14542f 100644 --- a/src/saveload/industry_sl.cpp +++ b/src/saveload/industry_sl.cpp @@ -25,6 +25,7 @@ static const SaveLoad _industry_desc[] = { SLE_VAR(Industry, location.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16), SLE_REF(Industry, town, REF_TOWN), + SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION), SLE_CONDNULL( 2, SL_MIN_VERSION, SLV_61), ///< used to be industry's produced_cargo SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS), SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION), @@ -182,9 +183,9 @@ static void Load_ITBL() } extern const ChunkHandler _industry_chunk_handlers[] = { - { 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, NULL, CH_ARRAY}, - { 'IIDS', Save_IIDS, Load_IIDS, NULL, NULL, CH_ARRAY}, - { 'TIDS', Save_TIDS, Load_TIDS, NULL, NULL, CH_ARRAY}, - { 'IBLD', LoadSave_IBLD, LoadSave_IBLD, NULL, NULL, CH_RIFF}, - { 'ITBL', Save_ITBL, Load_ITBL, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, nullptr, CH_ARRAY}, + { 'IIDS', Save_IIDS, Load_IIDS, nullptr, nullptr, CH_ARRAY}, + { 'TIDS', Save_TIDS, Load_TIDS, nullptr, nullptr, CH_ARRAY}, + { 'IBLD', LoadSave_IBLD, LoadSave_IBLD, nullptr, nullptr, CH_RIFF}, + { 'ITBL', Save_ITBL, Load_ITBL, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/labelmaps_sl.cpp b/src/saveload/labelmaps_sl.cpp index 3b898a3b87..6236e190e1 100644 --- a/src/saveload/labelmaps_sl.cpp +++ b/src/saveload/labelmaps_sl.cpp @@ -17,7 +17,7 @@ #include "../safeguards.h" -static SmallVector _railtype_list; +static std::vector _railtype_list; /** * Test if any saved rail type labels are different to the currently loaded @@ -26,7 +26,7 @@ static SmallVector _railtype_list; */ static bool NeedRailTypeConversion() { - for (uint i = 0; i < _railtype_list.Length(); i++) { + for (uint i = 0; i < _railtype_list.size(); i++) { if ((RailType)i < RAILTYPE_END) { const RailtypeInfo *rti = GetRailTypeInfo((RailType)i); if (rti->label != _railtype_list[i]) return true; @@ -42,13 +42,13 @@ static bool NeedRailTypeConversion() void AfterLoadLabelMaps() { if (NeedRailTypeConversion()) { - SmallVector railtype_conversion_map; + std::vector railtype_conversion_map; - for (uint i = 0; i < _railtype_list.Length(); i++) { + for (uint i = 0; i < _railtype_list.size(); i++) { RailType r = GetRailTypeByLabel(_railtype_list[i]); if (r == INVALID_RAILTYPE) r = RAILTYPE_BEGIN; - *railtype_conversion_map.Append() = r; + railtype_conversion_map.push_back(r); } for (TileIndex t = 0; t < MapSize(); t++) { @@ -81,7 +81,7 @@ void AfterLoadLabelMaps() } } - _railtype_list.Clear(); + _railtype_list.clear(); } /** Container for a label for SaveLoad system */ @@ -108,17 +108,17 @@ static void Save_RAIL() static void Load_RAIL() { - _railtype_list.Clear(); + _railtype_list.clear(); LabelObject lo; while (SlIterateArray() != -1) { SlObject(&lo, _label_object_desc); - *_railtype_list.Append() = (RailTypeLabel)lo.label; + _railtype_list.push_back((RailTypeLabel)lo.label); } } extern const ChunkHandler _labelmaps_chunk_handlers[] = { - { 'RAIL', Save_RAIL, Load_RAIL, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'RAIL', Save_RAIL, Load_RAIL, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index 50a0b62e69..0280cb1f69 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -51,11 +51,11 @@ const SaveLoad *GetLinkGraphDesc() */ const SaveLoad *GetLinkGraphJobDesc() { - static SmallVector saveloads; + static std::vector saveloads; static const char *prefix = "linkgraph."; /* Build the SaveLoad array on first call and don't touch it later on */ - if (saveloads.Length() == 0) { + if (saveloads.size() == 0) { size_t offset_gamesettings = cpp_offsetof(GameSettings, linkgraph); size_t offset_component = cpp_offsetof(LinkGraphJob, settings); @@ -64,12 +64,12 @@ const SaveLoad *GetLinkGraphJobDesc() int setting = 0; const SettingDesc *desc = GetSettingDescription(setting); while (desc->save.cmd != SL_END) { - if (desc->desc.name != NULL && strncmp(desc->desc.name, prefix, prefixlen) == 0) { + if (desc->desc.name != nullptr && strncmp(desc->desc.name, prefix, prefixlen) == 0) { SaveLoad sl = desc->save; char *&address = reinterpret_cast(sl.address); address -= offset_gamesettings; address += offset_component; - *(saveloads.Append()) = sl; + saveloads.push_back(sl); } desc = GetSettingDescription(++setting); } @@ -82,8 +82,8 @@ const SaveLoad *GetLinkGraphJobDesc() int i = 0; do { - *(saveloads.Append()) = job_desc[i++]; - } while (saveloads[saveloads.Length() - 1].cmd != SL_END); + saveloads.push_back(job_desc[i++]); + } while (saveloads[saveloads.size() - 1].cmd != SL_END); } return &saveloads[0]; @@ -292,7 +292,7 @@ static void Ptrs_LGRS() } extern const ChunkHandler _linkgraph_chunk_handlers[] = { - { 'LGRP', Save_LGRP, Load_LGRP, NULL, NULL, CH_ARRAY }, - { 'LGRJ', Save_LGRJ, Load_LGRJ, NULL, NULL, CH_ARRAY }, - { 'LGRS', Save_LGRS, Load_LGRS, Ptrs_LGRS, NULL, CH_LAST } + { 'LGRP', Save_LGRP, Load_LGRP, nullptr, nullptr, CH_ARRAY }, + { 'LGRJ', Save_LGRJ, Load_LGRJ, nullptr, nullptr, CH_ARRAY }, + { 'LGRS', Save_LGRS, Load_LGRS, Ptrs_LGRS, nullptr, CH_LAST } }; diff --git a/src/saveload/map_sl.cpp b/src/saveload/map_sl.cpp index 5402ecc0d2..a857d5b15a 100644 --- a/src/saveload/map_sl.cpp +++ b/src/saveload/map_sl.cpp @@ -13,6 +13,7 @@ #include "../map_func.h" #include "../core/bitmath_func.hpp" #include "../fios.h" +#include #include "saveload.h" @@ -51,80 +52,80 @@ static const uint MAP_SL_BUF_SIZE = 4096; static void Load_MAPT() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j]; } } static void Save_MAPT() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAPH() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j]; } } static void Save_MAPH() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].height; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP1() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; } } static void Save_MAP1() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP2() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, + SlArray(buf.data(), MAP_SL_BUF_SIZE, /* In those versions the m2 was 8 bits */ IsSavegameVersionBefore(SLV_5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 ); @@ -134,94 +135,94 @@ static void Load_MAP2() static void Save_MAP2() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size * sizeof(uint16)); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); } } static void Load_MAP3() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; } } static void Save_MAP3() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP4() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; } } static void Save_MAP4() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP5() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; } } static void Save_MAP5() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP6() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); if (IsSavegameVersionBefore(SLV_42)) { for (TileIndex i = 0; i != size;) { /* 1024, otherwise we overflow on 64x64 maps! */ - SlArray(buf, 1024, SLE_UINT8); + SlArray(buf.data(), 1024, SLE_UINT8); for (uint j = 0; j != 1024; j++) { _me[i++].m6 = GB(buf[j], 0, 2); _me[i++].m6 = GB(buf[j], 2, 2); @@ -231,7 +232,7 @@ static void Load_MAP6() } } else { for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j]; } } @@ -239,73 +240,73 @@ static void Load_MAP6() static void Save_MAP6() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m6; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP7() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; } } static void Save_MAP7() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP8() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m8 = buf[j]; } } static void Save_MAP8() { - SmallStackSafeStackAlloc buf; + std::array buf; TileIndex size = MapSize(); SlSetLength(size * sizeof(uint16)); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m8; - SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); + SlArray(buf.data(), MAP_SL_BUF_SIZE, SLE_UINT16); } } extern const ChunkHandler _map_chunk_handlers[] = { - { 'MAPS', Save_MAPS, Load_MAPS, NULL, Check_MAPS, CH_RIFF }, - { 'MAPT', Save_MAPT, Load_MAPT, NULL, NULL, CH_RIFF }, - { 'MAPH', Save_MAPH, Load_MAPH, NULL, NULL, CH_RIFF }, - { 'MAPO', Save_MAP1, Load_MAP1, NULL, NULL, CH_RIFF }, - { 'MAP2', Save_MAP2, Load_MAP2, NULL, NULL, CH_RIFF }, - { 'M3LO', Save_MAP3, Load_MAP3, NULL, NULL, CH_RIFF }, - { 'M3HI', Save_MAP4, Load_MAP4, NULL, NULL, CH_RIFF }, - { 'MAP5', Save_MAP5, Load_MAP5, NULL, NULL, CH_RIFF }, - { 'MAPE', Save_MAP6, Load_MAP6, NULL, NULL, CH_RIFF }, - { 'MAP7', Save_MAP7, Load_MAP7, NULL, NULL, CH_RIFF }, - { 'MAP8', Save_MAP8, Load_MAP8, NULL, NULL, CH_RIFF | CH_LAST }, + { 'MAPS', Save_MAPS, Load_MAPS, nullptr, Check_MAPS, CH_RIFF }, + { 'MAPT', Save_MAPT, Load_MAPT, nullptr, nullptr, CH_RIFF }, + { 'MAPH', Save_MAPH, Load_MAPH, nullptr, nullptr, CH_RIFF }, + { 'MAPO', Save_MAP1, Load_MAP1, nullptr, nullptr, CH_RIFF }, + { 'MAP2', Save_MAP2, Load_MAP2, nullptr, nullptr, CH_RIFF }, + { 'M3LO', Save_MAP3, Load_MAP3, nullptr, nullptr, CH_RIFF }, + { 'M3HI', Save_MAP4, Load_MAP4, nullptr, nullptr, CH_RIFF }, + { 'MAP5', Save_MAP5, Load_MAP5, nullptr, nullptr, CH_RIFF }, + { 'MAPE', Save_MAP6, Load_MAP6, nullptr, nullptr, CH_RIFF }, + { 'MAP7', Save_MAP7, Load_MAP7, nullptr, nullptr, CH_RIFF }, + { 'MAP8', Save_MAP8, Load_MAP8, nullptr, nullptr, CH_RIFF | CH_LAST }, }; diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp index cca3365b57..4a9b05a461 100644 --- a/src/saveload/misc_sl.cpp +++ b/src/saveload/misc_sl.cpp @@ -30,13 +30,13 @@ extern byte _trees_tick_ctr; /* Keep track of current game position */ int _saved_scrollpos_x; int _saved_scrollpos_y; -ZoomLevelByte _saved_scrollpos_zoom; +ZoomLevel _saved_scrollpos_zoom; void SaveViewportBeforeSaveGame() { const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - if (w != NULL) { + if (w != nullptr) { _saved_scrollpos_x = w->viewport->scrollpos_x; _saved_scrollpos_y = w->viewport->scrollpos_y; _saved_scrollpos_zoom = w->viewport->zoom; @@ -151,6 +151,6 @@ static void SaveLoad_VIEW() } extern const ChunkHandler _misc_chunk_handlers[] = { - { 'DATE', SaveLoad_DATE, SaveLoad_DATE, NULL, Check_DATE, CH_RIFF}, - { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, NULL, NULL, CH_RIFF | CH_LAST}, + { 'DATE', SaveLoad_DATE, SaveLoad_DATE, nullptr, Check_DATE, CH_RIFF}, + { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, nullptr, nullptr, CH_RIFF | CH_LAST}, }; diff --git a/src/saveload/newgrf_sl.cpp b/src/saveload/newgrf_sl.cpp index e40b45926c..2f7dfb3568 100644 --- a/src/saveload/newgrf_sl.cpp +++ b/src/saveload/newgrf_sl.cpp @@ -73,7 +73,7 @@ static void Save_NGRF() { int index = 0; - for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { + for (GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { if (HasBit(c->flags, GCF_STATIC)) continue; SlSetArrayIndex(index++); SlObject(c, _grfconfig_desc); @@ -98,7 +98,7 @@ static void Load_NGRF() if (_game_mode == GM_MENU) { /* Intro game must not have NewGRF. */ - if (_grfconfig != NULL) SlErrorCorrupt("The intro game must not use NewGRF"); + if (_grfconfig != nullptr) SlErrorCorrupt("The intro game must not use NewGRF"); /* Activate intro NewGRFs (townnames) */ ResetGRFConfig(false); @@ -114,5 +114,5 @@ static void Check_NGRF() } extern const ChunkHandler _newgrf_chunk_handlers[] = { - { 'NGRF', Save_NGRF, Load_NGRF, NULL, Check_NGRF, CH_ARRAY | CH_LAST } + { 'NGRF', Save_NGRF, Load_NGRF, nullptr, Check_NGRF, CH_ARRAY | CH_LAST } }; diff --git a/src/saveload/object_sl.cpp b/src/saveload/object_sl.cpp index 6b0b99e479..7d7f2fde9e 100644 --- a/src/saveload/object_sl.cpp +++ b/src/saveload/object_sl.cpp @@ -74,6 +74,6 @@ static void Load_OBID() } extern const ChunkHandler _object_chunk_handlers[] = { - { 'OBID', Save_OBID, Load_OBID, NULL, NULL, CH_ARRAY }, - { 'OBJS', Save_OBJS, Load_OBJS, Ptrs_OBJS, NULL, CH_ARRAY | CH_LAST}, + { 'OBID', Save_OBID, Load_OBID, nullptr, nullptr, CH_ARRAY }, + { 'OBJS', Save_OBJS, Load_OBJS, Ptrs_OBJS, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/oldloader.cpp b/src/saveload/oldloader.cpp index e0ad0e732a..11eb058fad 100644 --- a/src/saveload/oldloader.cpp +++ b/src/saveload/oldloader.cpp @@ -154,11 +154,11 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) default: NOT_REACHED(); } - /* When both pointers are NULL, we are just skipping data */ - if (base_ptr == NULL && chunk->ptr == NULL) continue; + /* When both pointers are nullptr, we are just skipping data */ + if (base_ptr == nullptr && chunk->ptr == nullptr) continue; /* Writing to the var: bits 8 to 15 have the VAR type */ - if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset; + if (chunk->ptr == nullptr) ptr = base_ptr + chunk->offset; /* Write the data */ switch (GetOldChunkVarType(chunk->type)) { @@ -174,7 +174,7 @@ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) } /* Increase pointer base for arrays when looping */ - if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type); + if (chunk->amount > 1 && chunk->ptr != nullptr) ptr += CalcOldVarLen(chunk->type); } } } @@ -259,7 +259,7 @@ static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *l } } - if (title != NULL) { + if (title != nullptr) { switch (type) { case SGT_TTO: title = strecpy(title, "(TTO) ", last); break; case SGT_TTD: title = strecpy(title, "(TTD) ", last); break; @@ -284,14 +284,14 @@ bool LoadOldSaveGame(const char *file) /* Open file */ ls.file = FioFOpenFile(file, "rb", NO_DIRECTORY); - if (ls.file == NULL) { + if (ls.file == nullptr) { DEBUG(oldloader, 0, "Cannot open file '%s'", file); return false; } - SavegameType type = DetermineOldSavegameType(ls.file, NULL, NULL); + SavegameType type = DetermineOldSavegameType(ls.file, nullptr, nullptr); - LoadOldMainProc *proc = NULL; + LoadOldMainProc *proc = nullptr; switch (type) { case SGT_TTO: proc = &LoadTTOMain; break; @@ -303,7 +303,7 @@ bool LoadOldSaveGame(const char *file) bool game_loaded; try { - game_loaded = proc != NULL && proc(&ls); + game_loaded = proc != nullptr && proc(&ls); } catch (...) { game_loaded = false; } @@ -314,7 +314,7 @@ bool LoadOldSaveGame(const char *file) return false; } - _pause_mode = 2; + _pause_mode = PM_PAUSED_SAVELOAD; return true; } @@ -323,7 +323,7 @@ void GetOldSaveGameName(const char *file, char *title, const char *last) { FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY); - if (f == NULL) { + if (f == nullptr) { *title = '\0'; return; } diff --git a/src/saveload/oldloader.h b/src/saveload/oldloader.h index 5483440ea6..12d8a348e5 100644 --- a/src/saveload/oldloader.h +++ b/src/saveload/oldloader.h @@ -90,7 +90,7 @@ struct OldChunks { uint32 amount; ///< Amount of fields void *ptr; ///< Pointer where to save the data (may only be set if offset is 0) - uint offset; ///< Offset from basepointer (may only be set if ptr is NULL) + uint offset; ///< Offset from basepointer (may only be set if ptr is nullptr) OldChunkProc *proc; ///< Pointer to function that is called with OC_CHUNK }; @@ -125,12 +125,12 @@ static inline uint32 ReadUint32(LoadgameState *ls) * - OCL_CHUNK: load another proc to load a part of the savegame, 'amount' times * - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;) */ -#define OCL_SVAR(type, base, offset) { type, 1, NULL, (uint)cpp_offsetof(base, offset), NULL } -#define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, NULL } -#define OCL_END() { OC_END, 0, NULL, 0, NULL } -#define OCL_CNULL(type, amount) { OC_NULL | type, amount, NULL, 0, NULL } -#define OCL_CCHUNK(type, amount, proc) { OC_CHUNK | type, amount, NULL, 0, proc } -#define OCL_ASSERT(type, size) { OC_ASSERT | type, 1, NULL, size, NULL } +#define OCL_SVAR(type, base, offset) { type, 1, nullptr, (uint)cpp_offsetof(base, offset), nullptr } +#define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, nullptr } +#define OCL_END() { OC_END, 0, nullptr, 0, nullptr } +#define OCL_CNULL(type, amount) { OC_NULL | type, amount, nullptr, 0, nullptr } +#define OCL_CCHUNK(type, amount, proc) { OC_CHUNK | type, amount, nullptr, 0, proc } +#define OCL_ASSERT(type, size) { OC_ASSERT | type, 1, nullptr, size, nullptr } #define OCL_NULL(amount) OCL_CNULL((OldChunkType)0, amount) #define OCL_CHUNK(amount, proc) OCL_CCHUNK((OldChunkType)0, amount, proc) diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 1974bb31fa..2287d30a19 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -31,6 +31,7 @@ #include "../core/smallvec_type.hpp" #include "saveload_internal.h" #include "oldloader.h" +#include #include "table/strings.h" #include "../table/engines.h" @@ -178,7 +179,7 @@ void FixOldVehicles() FOR_ALL_VEHICLES(v) { if ((size_t)v->next == 0xFFFF) { - v->next = NULL; + v->next = nullptr; } else { v->next = Vehicle::GetIfValid((size_t)v->next); } @@ -452,7 +453,7 @@ static bool FixTTOEngines() e->preview_company = INVALID_COMPANY; e->preview_asked = (CompanyMask)-1; e->preview_wait = 0; - e->name = NULL; + e->name = nullptr; } return true; @@ -491,7 +492,7 @@ static inline uint RemapOrderIndex(uint x) return _savegame_type == SGT_TTO ? (x - 0x1AC4) / 2 : (x - 0x1C18) / 2; } -extern SmallVector _animated_tiles; +extern std::vector _animated_tiles; extern char *_old_name_array; static uint32 _old_town_index; @@ -621,7 +622,7 @@ static const OldChunks order_chunk[] = { static bool LoadOldOrder(LoadgameState *ls, int num) { - if (!LoadChunk(ls, NULL, order_chunk)) return false; + if (!LoadChunk(ls, nullptr, order_chunk)) return false; Order *o = new (num) Order(); o->AssignOrder(UnpackOldOrder(_old_order)); @@ -632,7 +633,7 @@ static bool LoadOldOrder(LoadgameState *ls, int num) /* Relink the orders to each other (in the orders for one vehicle are behind each other, * with an invalid order (OT_NOTHING) as indication that it is the last order */ Order *prev = Order::GetIfValid(num - 1); - if (prev != NULL) prev->next = o; + if (prev != nullptr) prev->next = o; } return true; @@ -646,12 +647,12 @@ static bool LoadOldAnimTileList(LoadgameState *ls, int num) OCL_END () }; - if (!LoadChunk(ls, NULL, anim_chunk)) return false; + if (!LoadChunk(ls, nullptr, anim_chunk)) return false; /* The first zero in the loaded array indicates the end of the list. */ for (int i = 0; i < 256; i++) { if (anim_list[i] == 0) break; - *_animated_tiles.Append() = anim_list[i]; + _animated_tiles.push_back(anim_list[i]); } return true; @@ -671,7 +672,7 @@ static bool LoadOldDepot(LoadgameState *ls, int num) if (d->xy != 0) { /* In some cases, there could be depots referencing invalid town. */ Town *t = Town::GetIfValid(RemapTownIndex(_old_town_index)); - if (t == NULL) t = Town::GetRandom(); + if (t == nullptr) t = Town::GetRandom(); d->town = t; } else { delete d; @@ -724,7 +725,7 @@ static const OldChunks station_chunk[] = { OCL_NULL( 4 ), ///< bus/lorry tile OCL_SVAR( OC_TILE, Station, train_station.tile ), OCL_SVAR( OC_TILE, Station, airport.tile ), - OCL_SVAR( OC_TILE, Station, dock_tile ), + OCL_NULL( 4 ), ///< dock tile OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ), OCL_NULL( 1 ), ///< sort-index, no longer in use @@ -876,7 +877,7 @@ static bool LoadOldCompanyYearly(LoadgameState *ls, int num) if (_savegame_type == SGT_TTO && i == 6) { _old_yearly = 0; // property maintenance } else { - if (!LoadChunk(ls, NULL, _company_yearly_chunk)) return false; + if (!LoadChunk(ls, nullptr, _company_yearly_chunk)) return false; } c->yearly_expenses[num][i] = _old_yearly; @@ -1106,8 +1107,8 @@ static bool LoadOldVehicleUnion(LoadgameState *ls, int num) uint temp = ls->total_read; bool res; - if (v == NULL) { - res = LoadChunk(ls, NULL, vehicle_empty_chunk); + if (v == nullptr) { + res = LoadChunk(ls, nullptr, vehicle_empty_chunk); } else { switch (v->type) { default: SlErrorCorrupt("Invalid vehicle type"); @@ -1240,7 +1241,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) uint type = ReadByte(ls); switch (type) { default: return false; - case 0x00 /* VEH_INVALID */: v = NULL; break; + case 0x00 /* VEH_INVALID */: v = nullptr; break; case 0x25 /* MONORAIL */: case 0x20 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break; case 0x21 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; @@ -1251,7 +1252,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) } if (!LoadChunk(ls, v, vehicle_chunk)) return false; - if (v == NULL) continue; + if (v == nullptr) continue; v->refit_cap = v->cargo_cap; SpriteID sprite = v->sprite_seq.seq[0].sprite; @@ -1276,7 +1277,8 @@ bool LoadOldVehicle(LoadgameState *ls, int num) }; if (v->spritenum / 2 >= lengthof(spriteset_rail)) return false; v->spritenum = spriteset_rail[v->spritenum / 2]; // adjust railway sprite set offset - Train::From(v)->railtype = type == 0x25 ? 1 : 0; // monorail / rail + /* Should be the original values for monorail / rail, can't use RailType constants */ + Train::From(v)->railtype = static_cast(type == 0x25 ? 1 : 0); break; } @@ -1318,7 +1320,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) /* Read the vehicle type and allocate the right vehicle */ switch (ReadByte(ls)) { default: SlErrorCorrupt("Invalid vehicle type"); - case 0x00 /* VEH_INVALID */: v = NULL; break; + case 0x00 /* VEH_INVALID */: v = nullptr; break; case 0x10 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break; case 0x11 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; case 0x12 /* VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break; @@ -1328,7 +1330,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) } if (!LoadChunk(ls, v, vehicle_chunk)) return false; - if (v == NULL) continue; + if (v == nullptr) continue; _old_vehicle_names[_current_vehicle_id] = RemapOldStringID(_old_string_id); @@ -1754,11 +1756,11 @@ bool LoadTTDMain(LoadgameState *ls) _read_ttdpatch_flags = false; /* Load the biggest chunk */ - SmallStackSafeStackAlloc map3; - _old_map3 = map3.data; - _old_vehicle_names = NULL; + std::array map3; + _old_map3 = map3.data(); + _old_vehicle_names = nullptr; try { - if (!LoadChunk(ls, NULL, main_chunk)) { + if (!LoadChunk(ls, nullptr, main_chunk)) { DEBUG(oldloader, 0, "Loading failed"); free(_old_vehicle_names); return false; @@ -1797,13 +1799,13 @@ bool LoadTTOMain(LoadgameState *ls) _read_ttdpatch_flags = false; - SmallStackSafeStackAlloc engines; // we don't want to call Engine constructor here - _old_engines = (Engine *)engines.data; - SmallStackSafeStackAlloc vehnames; - _old_vehicle_names = vehnames.data; + std::array engines; // we don't want to call Engine constructor here + _old_engines = (Engine *)engines.data(); + std::array vehnames; + _old_vehicle_names = vehnames.data(); /* Load the biggest chunk */ - if (!LoadChunk(ls, NULL, main_chunk)) { + if (!LoadChunk(ls, nullptr, main_chunk)) { DEBUG(oldloader, 0, "Loading failed"); return false; } diff --git a/src/saveload/order_sl.cpp b/src/saveload/order_sl.cpp index b89514d479..c21782de51 100644 --- a/src/saveload/order_sl.cpp +++ b/src/saveload/order_sl.cpp @@ -178,7 +178,7 @@ static void Load_ORDR() /* The orders were built like this: * While the order is valid, set the previous will get its next pointer set */ Order *prev = Order::GetIfValid(order_index - 1); - if (prev != NULL) prev->next = o; + if (prev != nullptr) prev->next = o; } } else { int index; @@ -306,7 +306,7 @@ static void Ptrs_BKOR() } extern const ChunkHandler _order_chunk_handlers[] = { - { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, NULL, CH_ARRAY}, - { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, NULL, CH_ARRAY}, - { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, NULL, CH_ARRAY | CH_LAST}, + { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, nullptr, CH_ARRAY}, + { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, nullptr, CH_ARRAY}, + { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index ab4b1e2a1e..aa8acddf17 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -26,7 +26,7 @@ #include "../stdafx.h" #include "../debug.h" #include "../station_base.h" -#include "../thread/thread.h" +#include "../thread.h" #include "../town.h" #include "../network/network.h" #include "../window_func.h" @@ -45,6 +45,7 @@ #include "../string_func.h" #include "../fios.h" #include "../error.h" +#include #include "table/strings.h" @@ -94,7 +95,7 @@ struct ReadBuffer { * Initialise our variables. * @param reader The filter to actually read data. */ - ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0) + ReadBuffer(LoadFilter *reader) : bufp(nullptr), bufe(nullptr), reader(reader), read(0) { } @@ -125,15 +126,22 @@ struct ReadBuffer { /** Container for dumping the savegame (quickly) to memory. */ struct MemoryDumper { - AutoFreeSmallVector blocks; ///< Buffer with blocks of allocated memory. - byte *buf; ///< Buffer we're going to write to. - byte *bufe; ///< End of the buffer we write to. + std::vector blocks; ///< Buffer with blocks of allocated memory. + byte *buf; ///< Buffer we're going to write to. + byte *bufe; ///< End of the buffer we write to. /** Initialise our variables. */ - MemoryDumper() : buf(NULL), bufe(NULL) + MemoryDumper() : buf(nullptr), bufe(nullptr) { } + ~MemoryDumper() + { + for (auto p : this->blocks) { + free(p); + } + } + /** * Write a single byte into the dumper. * @param b The byte to write. @@ -143,7 +151,7 @@ struct MemoryDumper { /* Are we at the end of this chunk? */ if (this->buf == this->bufe) { this->buf = CallocT(MEMORY_CHUNK_SIZE); - *this->blocks.Append() = this->buf; + this->blocks.push_back(this->buf); this->bufe = this->buf + MEMORY_CHUNK_SIZE; } @@ -175,7 +183,7 @@ struct MemoryDumper { */ size_t GetSize() const { - return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf); + return this->blocks.size() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf); } }; @@ -239,7 +247,7 @@ extern const ChunkHandler _airport_chunk_handlers[]; extern const ChunkHandler _object_chunk_handlers[]; extern const ChunkHandler _persistent_storage_chunk_handlers[]; -/** Array of all chunks in a savegame, \c NULL terminated. */ +/** Array of all chunks in a savegame, \c nullptr terminated. */ static const ChunkHandler * const _chunk_handlers[] = { _gamelog_chunk_handlers, _map_chunk_handlers, @@ -274,7 +282,7 @@ static const ChunkHandler * const _chunk_handlers[] = { _airport_chunk_handlers, _object_chunk_handlers, _persistent_storage_chunk_handlers, - NULL, + nullptr, }; /** @@ -282,10 +290,10 @@ static const ChunkHandler * const _chunk_handlers[] = { * @param ch the chunk handler iterator */ #define FOR_ALL_CHUNK_HANDLERS(ch) \ - for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \ - for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1) + for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != nullptr; chsc++) \ + for (const ChunkHandler *ch = *chsc; ch != nullptr; ch = (ch->flags & CH_LAST) ? nullptr : ch + 1) -/** Null all pointers (convert index -> NULL) */ +/** Null all pointers (convert index -> nullptr) */ static void SlNullPointers() { _sl.action = SLA_NULL; @@ -298,7 +306,7 @@ static void SlNullPointers() DEBUG(sl, 1, "Nulling pointers"); FOR_ALL_CHUNK_HANDLERS(ch) { - if (ch->ptrs_proc != NULL) { + if (ch->ptrs_proc != nullptr) { DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); ch->ptrs_proc(); } @@ -323,14 +331,14 @@ void NORETURN SlError(StringID string, const char *extra_msg) if (_sl.action == SLA_LOAD_CHECK) { _load_check_data.error = string; free(_load_check_data.error_data); - _load_check_data.error_data = (extra_msg == NULL) ? NULL : stredup(extra_msg); + _load_check_data.error_data = (extra_msg == nullptr) ? nullptr : stredup(extra_msg); } else { _sl.error_str = string; free(_sl.extra_msg); - _sl.extra_msg = (extra_msg == NULL) ? NULL : stredup(extra_msg); + _sl.extra_msg = (extra_msg == nullptr) ? nullptr : stredup(extra_msg); } - /* We have to NULL all pointers here; we might be in a state where + /* We have to nullptr all pointers here; we might be in a state where * the pointers are actually filled with indices, which means that * when we access them during cleaning the pool dereferences of * those indices will be made with segmentation faults as result. */ @@ -370,9 +378,9 @@ void NORETURN SlErrorCorruptFmt(const char *format, ...) } -typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished. -static AsyncSaveFinishProc _async_save_finish = NULL; ///< Callback to call when the savegame loading is finished. -static ThreadObject *_save_thread; ///< The thread we're using to compress and write a savegame +typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished. +static std::atomic _async_save_finish; ///< Callback to call when the savegame loading is finished. +static std::thread _save_thread; ///< The thread we're using to compress and write a savegame /** * Called by save thread to tell we finished saving. @@ -381,9 +389,9 @@ static ThreadObject *_save_thread; ///< The thread we're usin static void SetAsyncSaveFinish(AsyncSaveFinishProc proc) { if (_exit_game) return; - while (_async_save_finish != NULL) CSleep(10); + while (_async_save_finish.load(std::memory_order_acquire) != nullptr) CSleep(10); - _async_save_finish = proc; + _async_save_finish.store(proc, std::memory_order_release); } /** @@ -391,16 +399,13 @@ static void SetAsyncSaveFinish(AsyncSaveFinishProc proc) */ void ProcessAsyncSaveFinish() { - if (_async_save_finish == NULL) return; + AsyncSaveFinishProc proc = _async_save_finish.exchange(nullptr, std::memory_order_acq_rel); + if (proc == nullptr) return; - _async_save_finish(); + proc(); - _async_save_finish = NULL; - - if (_save_thread != NULL) { - _save_thread->Join(); - delete _save_thread; - _save_thread = NULL; + if (_save_thread.joinable()) { + _save_thread.join(); } } @@ -858,7 +863,7 @@ static void SlSaveLoadConv(void *ptr, VarType conv) */ static inline size_t SlCalcNetStringLen(const char *ptr, size_t length) { - if (ptr == NULL) return 0; + if (ptr == nullptr) return 0; return min(strlen(ptr), length - 1); } @@ -943,7 +948,7 @@ static void SlString(void *ptr, size_t length, VarType conv) case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate free(*(char **)ptr); if (len == 0) { - *(char **)ptr = NULL; + *(char **)ptr = nullptr; return; } else { *(char **)ptr = MallocT(len + 1); // terminating '\0' @@ -1038,7 +1043,7 @@ void SlArray(void *array, size_t length, VarType conv) * Pointers cannot be saved to a savegame, so this functions gets * the index of the item, and if not available, it hussles with * pointers (looks really bad :() - * Remember that a NULL item has value 0, and all + * Remember that a nullptr item has value 0, and all * indices have +1, so vehicle 0 is saved as index 1. * @param obj The object that we want to get the index of * @param rt SLRefType type of the object the index is being sought of @@ -1048,7 +1053,7 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt) { assert(_sl.action == SLA_SAVE); - if (obj == NULL) return 0; + if (obj == nullptr) return 0; switch (rt) { case REF_VEHICLE_OLD: // Old vehicles we save as new ones @@ -1071,7 +1076,7 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt) * Pointers cannot be loaded from a savegame, so this function * gets the index from the savegame and returns the appropriate * pointer from the already loaded base. - * Remember that an index of 0 is a NULL pointer so all indices + * Remember that an index of 0 is a nullptr pointer so all indices * are +1 so vehicle 0 is saved as 1. * @param index The index that is being converted to a pointer * @param rt SLRefType type of the object the pointer is sought of @@ -1089,8 +1094,8 @@ static void *IntToReference(size_t index, SLRefType rt) rt = REF_VEHICLE; } - /* No need to look up NULL pointers, just return immediately */ - if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL; + /* No need to look up nullptr pointers, just return immediately */ + if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return nullptr; /* Correct index. Old vehicles were saved differently: * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */ @@ -1104,7 +1109,7 @@ static void *IntToReference(size_t index, SLRefType rt) case REF_ORDER: if (Order::IsValidID(index)) return Order::Get(index); /* in old versions, invalid order was used to mark end of order list */ - if (IsSavegameVersionBefore(SLV_5, 2)) return NULL; + if (IsSavegameVersionBefore(SLV_5, 2)) return nullptr; SlErrorCorrupt("Referencing invalid Order"); case REF_VEHICLE_OLD: @@ -1494,7 +1499,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv); break; case SLA_NULL: - *(void **)ptr = NULL; + *(void **)ptr = nullptr; break; default: NOT_REACHED(); } @@ -1508,7 +1513,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) break; /* SL_WRITEBYTE writes a value to the savegame to identify the type of an object. - * When loading, the value is read explictly with SlReadByte() to determine which + * When loading, the value is read explicitly with SlReadByte() to determine which * object description to use. */ case SL_WRITEBYTE: switch (_sl.action) { @@ -1560,7 +1565,7 @@ void SlObject(void *object, const SaveLoad *sld) */ void SlGlobList(const SaveLoadGlobVarList *sldg) { - SlObject(NULL, (const SaveLoad*)sldg); + SlObject(nullptr, (const SaveLoad*)sldg); } /** @@ -1632,7 +1637,7 @@ static void SlLoadChunk(const ChunkHandler *ch) /** * Load a chunk of data for checking savegames. - * If the chunkhandler is NULL, the chunk is skipped. + * If the chunkhandler is nullptr, the chunk is skipped. * @param ch The chunkhandler that will be used for the operation */ static void SlLoadCheckChunk(const ChunkHandler *ch) @@ -1703,7 +1708,7 @@ static inline void SlStubSaveProc2(void *arg) */ static void SlStubSaveProc() { - SlAutolength(SlStubSaveProc2, NULL); + SlAutolength(SlStubSaveProc2, nullptr); } /** @@ -1716,7 +1721,7 @@ static void SlSaveChunk(const ChunkHandler *ch) ChunkSaveLoadProc *proc = ch->save_proc; /* Don't save any chunk information if there is no save handler. */ - if (proc == NULL) return; + if (proc == nullptr) return; SlWriteUint32(ch->id); DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); @@ -1768,7 +1773,7 @@ static void SlSaveChunks() static const ChunkHandler *SlFindChunkHandler(uint32 id) { FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch; - return NULL; + return nullptr; } /** Load all chunks */ @@ -1781,7 +1786,7 @@ static void SlLoadChunks() DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); ch = SlFindChunkHandler(id); - if (ch == NULL) SlErrorCorrupt("Unknown chunk type"); + if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); SlLoadChunk(ch); } } @@ -1796,7 +1801,7 @@ static void SlLoadCheckChunks() DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); ch = SlFindChunkHandler(id); - if (ch == NULL) SlErrorCorrupt("Unknown chunk type"); + if (ch == nullptr) SlErrorCorrupt("Unknown chunk type"); SlLoadCheckChunk(ch); } } @@ -1809,7 +1814,7 @@ static void SlFixPointers() DEBUG(sl, 1, "Fixing pointers"); FOR_ALL_CHUNK_HANDLERS(ch) { - if (ch->ptrs_proc != NULL) { + if (ch->ptrs_proc != nullptr) { DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); ch->ptrs_proc(); } @@ -1830,29 +1835,29 @@ struct FileReader : LoadFilter { * Create the file reader, so it reads from a specific file. * @param file The file to read from. */ - FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file)) + FileReader(FILE *file) : LoadFilter(nullptr), file(file), begin(ftell(file)) { } /** Make sure everything is cleaned up. */ ~FileReader() { - if (this->file != NULL) fclose(this->file); - this->file = NULL; + if (this->file != nullptr) fclose(this->file); + this->file = nullptr; /* Make sure we don't double free. */ - _sl.sf = NULL; + _sl.sf = nullptr; } - /* virtual */ size_t Read(byte *buf, size_t size) + size_t Read(byte *buf, size_t size) override { /* We're in the process of shutting down, i.e. in "failure" mode. */ - if (this->file == NULL) return 0; + if (this->file == nullptr) return 0; return fread(buf, 1, size, this->file); } - /* virtual */ void Reset() + void Reset() override { clearerr(this->file); if (fseek(this->file, this->begin, SEEK_SET)) { @@ -1869,7 +1874,7 @@ struct FileWriter : SaveFilter { * Create the file writer, so it writes to a specific file. * @param file The file to write to. */ - FileWriter(FILE *file) : SaveFilter(NULL), file(file) + FileWriter(FILE *file) : SaveFilter(nullptr), file(file) { } @@ -1879,21 +1884,21 @@ struct FileWriter : SaveFilter { this->Finish(); /* Make sure we don't double free. */ - _sl.sf = NULL; + _sl.sf = nullptr; } - /* virtual */ void Write(byte *buf, size_t size) + void Write(byte *buf, size_t size) override { /* We're in the process of shutting down, i.e. in "failure" mode. */ - if (this->file == NULL) return; + if (this->file == nullptr) return; if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE); } - /* virtual */ void Finish() + void Finish() override { - if (this->file != NULL) fclose(this->file); - this->file = NULL; + if (this->file != nullptr) fclose(this->file); + this->file = nullptr; } }; @@ -1918,7 +1923,7 @@ struct LZOLoadFilter : LoadFilter { if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor"); } - /* virtual */ size_t Read(byte *buf, size_t ssize) + size_t Read(byte *buf, size_t ssize) override { assert(ssize >= LZO_BUFFER_SIZE); @@ -1948,7 +1953,7 @@ struct LZOLoadFilter : LoadFilter { if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum"); /* Decompress */ - int ret = lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL); + int ret = lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, nullptr); if (ret != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); return len; } @@ -1966,7 +1971,7 @@ struct LZOSaveFilter : SaveFilter { if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor"); } - /* virtual */ void Write(byte *buf, size_t size) + void Write(byte *buf, size_t size) override { const lzo_bytep in = buf; /* Buffer size is from the LZO docs plus the chunk header size. */ @@ -2005,7 +2010,7 @@ struct NoCompLoadFilter : LoadFilter { { } - /* virtual */ size_t Read(byte *buf, size_t size) + size_t Read(byte *buf, size_t size) override { return this->chain->Read(buf, size); } @@ -2022,7 +2027,7 @@ struct NoCompSaveFilter : SaveFilter { { } - /* virtual */ void Write(byte *buf, size_t size) + void Write(byte *buf, size_t size) override { this->chain->Write(buf, size); } @@ -2056,7 +2061,7 @@ struct ZlibLoadFilter : LoadFilter { inflateEnd(&this->z); } - /* virtual */ size_t Read(byte *buf, size_t size) + size_t Read(byte *buf, size_t size) override { this->z.next_out = buf; this->z.avail_out = (uint)size; @@ -2135,14 +2140,14 @@ struct ZlibSaveFilter : SaveFilter { } while (this->z.avail_in || !this->z.avail_out); } - /* virtual */ void Write(byte *buf, size_t size) + void Write(byte *buf, size_t size) override { this->WriteLoop(buf, size, 0); } - /* virtual */ void Finish() + void Finish() override { - this->WriteLoop(NULL, 0, Z_FINISH); + this->WriteLoop(nullptr, 0, Z_FINISH); this->chain->Finish(); } }; @@ -2153,7 +2158,7 @@ struct ZlibSaveFilter : SaveFilter { ********** START OF LZMA CODE ************** ********************************************/ -#if defined(WITH_LZMA) +#if defined(WITH_LIBLZMA) #include /** @@ -2185,7 +2190,7 @@ struct LZMALoadFilter : LoadFilter { lzma_end(&this->lzma); } - /* virtual */ size_t Read(byte *buf, size_t size) + size_t Read(byte *buf, size_t size) override { this->lzma.next_out = buf; this->lzma.avail_out = size; @@ -2254,19 +2259,19 @@ struct LZMASaveFilter : SaveFilter { } while (this->lzma.avail_in || !this->lzma.avail_out); } - /* virtual */ void Write(byte *buf, size_t size) + void Write(byte *buf, size_t size) override { this->WriteLoop(buf, size, LZMA_RUN); } - /* virtual */ void Finish() + void Finish() override { - this->WriteLoop(NULL, 0, LZMA_FINISH); + this->WriteLoop(nullptr, 0, LZMA_FINISH); this->chain->Finish(); } }; -#endif /* WITH_LZMA */ +#endif /* WITH_LIBLZMA */ /******************************************* ************* END OF CODE ***************** @@ -2291,7 +2296,7 @@ static const SaveLoadFormat _saveload_formats[] = { /* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */ {"lzo", TO_BE32X('OTTD'), CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, #else - {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0}, + {"lzo", TO_BE32X('OTTD'), nullptr, nullptr, 0, 0, 0}, #endif /* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */ {"none", TO_BE32X('OTTN'), CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, @@ -2301,9 +2306,9 @@ static const SaveLoadFormat _saveload_formats[] = { * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */ {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter, CreateSaveFilter, 0, 6, 9}, #else - {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0}, + {"zlib", TO_BE32X('OTTZ'), nullptr, nullptr, 0, 0, 0}, #endif -#if defined(WITH_LZMA) +#if defined(WITH_LIBLZMA) /* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves. * Higher compression levels are possible, and might improve savegame size by up to 25%, but are also up to 10 times slower. * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50% @@ -2311,14 +2316,14 @@ static const SaveLoadFormat _saveload_formats[] = { * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */ {"lzma", TO_BE32X('OTTX'), CreateLoadFilter, CreateSaveFilter, 0, 2, 9}, #else - {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0}, + {"lzma", TO_BE32X('OTTX'), nullptr, nullptr, 0, 0, 0}, #endif }; /** * Return the savegameformat of the game. Whether it was created with ZLIB compression * uncompressed, or another type - * @param s Name of the savegame format. If NULL it picks the first available one + * @param s Name of the savegame format. If nullptr it picks the first available one * @param compression_level Output for telling what compression level we want. * @return Pointer to SaveLoadFormat struct giving all characteristics of this type of savegame */ @@ -2332,12 +2337,12 @@ static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level) if (!StrEmpty(s)) { /* Get the ":..." of the compression level out of the way */ char *complevel = strrchr(s, ':'); - if (complevel != NULL) *complevel = '\0'; + if (complevel != nullptr) *complevel = '\0'; for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) { - if (slf->init_write != NULL && strcmp(s, slf->name) == 0) { + if (slf->init_write != nullptr && strcmp(s, slf->name) == 0) { *compression_level = slf->default_compression; - if (complevel != NULL) { + if (complevel != nullptr) { /* There is a compression level in the string. * First restore the : we removed to do proper name matching, * then move the the begin of the actual version. */ @@ -2363,7 +2368,7 @@ static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level) ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL); /* Restore the string by adding the : back */ - if (complevel != NULL) *complevel = ':'; + if (complevel != nullptr) *complevel = ':'; } *compression_level = def->default_compression; return def; @@ -2380,16 +2385,16 @@ extern bool LoadOldSaveGame(const char *file); static inline void ClearSaveLoadState() { delete _sl.dumper; - _sl.dumper = NULL; + _sl.dumper = nullptr; delete _sl.sf; - _sl.sf = NULL; + _sl.sf = nullptr; delete _sl.reader; - _sl.reader = NULL; + _sl.reader = nullptr; delete _sl.lf; - _sl.lf = NULL; + _sl.lf = nullptr; } /** @@ -2486,19 +2491,11 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded) } } -/** Thread run function for saving the file to disk. */ -static void SaveFileToDiskThread(void *arg) -{ - SaveFileToDisk(true); -} - void WaitTillSaved() { - if (_save_thread == NULL) return; + if (!_save_thread.joinable()) return; - _save_thread->Join(); - delete _save_thread; - _save_thread = NULL; + _save_thread.join(); /* Make sure every other state is handled properly as well. */ ProcessAsyncSaveFinish(); @@ -2525,7 +2522,8 @@ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded) SlSaveChunks(); SaveFileStart(); - if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread, "ottd:savegame")) { + + if (!threaded || !StartNewThread(&_save_thread, "ottd:savegame", &SaveFileToDisk, true)) { if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode..."); SaveOrLoadResult result = SaveFileToDisk(false); @@ -2616,7 +2614,7 @@ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check) } /* loader for this savegame type is not implemented? */ - if (fmt->init_load == NULL) { + if (fmt->init_load == nullptr) { char err_str[64]; seprintf(err_str, lastof(err_str), "Loader for '%s' is not available.", fmt->name); SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str); @@ -2771,11 +2769,11 @@ SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, Detaile FILE *fh = (fop == SLO_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb); /* Make it a little easier to load savegames from the console */ - if (fh == NULL && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR); - if (fh == NULL && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR); - if (fh == NULL && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR); + if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR); + if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR); + if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR); - if (fh == NULL) { + if (fh == nullptr) { SlError(fop == SLO_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); } diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index ad6b76e05e..d80cc3be35 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -266,8 +266,8 @@ enum SaveLoadVersion : uint16 { SLV_185, ///< 185 25620 Storybooks SLV_186, ///< 186 25833 Objects storage SLV_187, ///< 187 25899 Linkgraph - restricted flows - SLV_188, ///< 188 26169 FS#5831 Unify RV travel time - SLV_189, ///< 189 26450 Heirarchical vehicle subgroups + SLV_188, ///< 188 26169 v1.4 FS#5831 Unify RV travel time + SLV_189, ///< 189 26450 Hierarchical vehicle subgroups SLV_190, ///< 190 26547 Separate order travel and wait times SLV_191, ///< 191 26636 FS#6026 Fix disaster vehicle storage (No bump) @@ -283,14 +283,26 @@ enum SaveLoadVersion : uint16 { SLV_EXTEND_CARGOTYPES, ///< 199 PR#6802 Extend cargotypes to 64 SLV_EXTEND_RAILTYPES, ///< 200 PR#6805 Extend railtypes to 64, adding uint16 to map array. - SLV_EXTEND_PERSISTENT_STORAGE, ///< 201 PR#6885 Extend NewGRF persistant storages. + SLV_EXTEND_PERSISTENT_STORAGE, ///< 201 PR#6885 Extend NewGRF persistent storages. SLV_EXTEND_INDUSTRY_CARGO_SLOTS, ///< 202 PR#6867 Increase industry cargo slots to 16 in, 16 out SLV_SHIP_PATH_CACHE, ///< 203 PR#7072 Add path cache for ships SLV_SHIP_ROTATION, ///< 204 PR#7065 Add extra rotation stages for ships. SLV_GROUP_LIVERIES, ///< 205 PR#7108 Livery storage change and group liveries. SLV_SHIPS_STOP_IN_LOCKS, ///< 206 PR#7150 Ship/lock movement changes. - SLV_FIX_CARGO_MONITOR, ///< 207 PR#7175 Cargo monitor data packing fix to support 64 cargotypes. + SLV_FIX_CARGO_MONITOR, ///< 207 PR#7175 v1.9 Cargo monitor data packing fix to support 64 cargotypes. + SLV_TOWN_CARGOGEN, ///< 208 PR#6965 New algorithms for town building cargo generation. + SLV_SHIP_CURVE_PENALTY, ///< 209 PR#7289 Configurable ship curve penalties. + + SLV_SERVE_NEUTRAL_INDUSTRIES, ///< 210 PR#7234 Company stations can serve industries with attached neutral stations. + SLV_ROADVEH_PATH_CACHE, ///< 211 PR#7261 Add path cache for road vehicles. + SLV_REMOVE_OPF, ///< 212 PR#7245 Remove OPF. + SLV_TREES_WATER_CLASS, ///< 213 PR#7405 WaterClass update for tree tiles. + SLV_ROAD_TYPES, ///< 214 PR#6811 NewGRF road types. + + SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption. + SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station. + SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age. SL_MAX_VERSION, ///< Highest possible saveload version }; @@ -634,11 +646,11 @@ typedef SaveLoad SaveLoadGlobVarList; /** Translate values ingame to different values in the savegame and vv. */ #define SLE_WRITEBYTE(base, variable) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION) -#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, NULL, 0} -#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, NULL, 0} +#define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0} +#define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0} /** End marker of a struct/class save or load. */ -#define SLE_END() {false, SL_END, 0, 0, SL_MIN_VERSION, SL_MIN_VERSION, NULL, 0} +#define SLE_END() {false, SL_END, 0, 0, SL_MIN_VERSION, SL_MIN_VERSION, nullptr, 0} /** * Storage of global simple variables, references (pointers), and arrays. @@ -739,10 +751,10 @@ typedef SaveLoad SaveLoadGlobVarList; * @param from First savegame version that has the empty space. * @param to Last savegame version that has the empty space. */ -#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to, (void*)NULL} +#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to, (void*)nullptr} /** End marker of global variables save or load. */ -#define SLEG_END() {true, SL_END, 0, 0, SL_MIN_VERSION, SL_MIN_VERSION, NULL, 0} +#define SLEG_END() {true, SL_END, 0, 0, SL_MIN_VERSION, SL_MIN_VERSION, nullptr, 0} /** * Checks whether the savegame is below \a major.\a minor. @@ -806,13 +818,13 @@ static inline bool IsNumericType(VarType conv) /** * Get the address of the variable. Which one to pick depends on the object - * pointer. If it is NULL we are dealing with global variables so the address + * pointer. If it is nullptr we are dealing with global variables so the address * is taken. If non-null only the offset is stored in the union and we need * to add this to the address of the object */ static inline void *GetVariableAddress(const void *object, const SaveLoad *sld) { - return const_cast((const byte*)(sld->global ? NULL : object) + (ptrdiff_t)sld->address); + return const_cast((const byte*)(sld->global ? nullptr : object) + (ptrdiff_t)sld->address); } int64 ReadValue(const void *ptr, VarType conv); @@ -834,7 +846,7 @@ void SlGlobList(const SaveLoadGlobVarList *sldg); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); -void NORETURN SlError(StringID string, const char *extra_msg = NULL); +void NORETURN SlError(StringID string, const char *extra_msg = nullptr); void NORETURN SlErrorCorrupt(const char *msg); void NORETURN SlErrorCorruptFmt(const char *format, ...); diff --git a/src/saveload/saveload_filter.h b/src/saveload/saveload_filter.h index 0cb5c86955..ace9182d31 100644 --- a/src/saveload/saveload_filter.h +++ b/src/saveload/saveload_filter.h @@ -89,7 +89,7 @@ struct SaveFilter { */ virtual void Finish() { - if (this->chain != NULL) this->chain->Finish(); + if (this->chain != nullptr) this->chain->Finish(); } }; diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index 74e5b9936d..e7a9e7bf5e 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -49,7 +49,7 @@ void CopyTempEngineData(); extern int32 _saved_scrollpos_x; extern int32 _saved_scrollpos_y; -extern ZoomLevelByte _saved_scrollpos_zoom; +extern ZoomLevel _saved_scrollpos_zoom; extern SavegameType _savegame_type; extern uint32 _ttdp_version; diff --git a/src/saveload/signs_sl.cpp b/src/saveload/signs_sl.cpp index 545c628b36..f2ec21d944 100644 --- a/src/saveload/signs_sl.cpp +++ b/src/saveload/signs_sl.cpp @@ -68,5 +68,5 @@ static void Load_SIGN() /** Chunk handlers related to signs. */ extern const ChunkHandler _sign_chunk_handlers[] = { - { 'SIGN', Save_SIGN, Load_SIGN, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'SIGN', Save_SIGN, Load_SIGN, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 995483ee6d..b9dcbd9e8e 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -47,7 +47,7 @@ void MoveBuoysToWaypoints() VehicleType vt = ol->GetFirstSharedVehicle()->type; if (vt != VEH_SHIP && vt != VEH_TRAIN) continue; - for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); + for (Order *o = ol->GetFirstOrder(); o != nullptr; o = o->next) UpdateWaypointOrder(o); } Vehicle *v; @@ -68,7 +68,7 @@ void MoveBuoysToWaypoints() Town *town = st->town; StringID string_id = st->string_id; char *name = st->name; - st->name = NULL; + st->name = nullptr; Date build_date = st->build_date; /* TTDPatch could use "buoys with rail station" for rail waypoints */ bool train = st->train_station.tile != INVALID_TILE; @@ -116,13 +116,13 @@ void AfterLoadStations() for (uint i = 0; i < st->num_specs; i++) { if (st->speclist[i].grfid == 0) continue; - st->speclist[i].spec = StationClass::GetByGrf(st->speclist[i].grfid, st->speclist[i].localidx, NULL); + st->speclist[i].spec = StationClass::GetByGrf(st->speclist[i].grfid, st->speclist[i].localidx, nullptr); } if (Station::IsExpected(st)) { Station *sta = Station::From(st); - for (const RoadStop *rs = sta->bus_stops; rs != NULL; rs = rs->next) sta->bus_station.Add(rs->xy); - for (const RoadStop *rs = sta->truck_stops; rs != NULL; rs = rs->next) sta->truck_station.Add(rs->xy); + for (const RoadStop *rs = sta->bus_stops; rs != nullptr; rs = rs->next) sta->bus_station.Add(rs->xy); + for (const RoadStop *rs = sta->truck_stops; rs != nullptr; rs = rs->next) sta->truck_station.Add(rs->xy); } StationUpdateCachedTriggers(st); @@ -174,8 +174,8 @@ static const SaveLoad _old_station_desc[] = { SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), SLE_CONDVAR(Station, airport.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), - SLE_CONDVAR(Station, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6), - SLE_CONDVAR(Station, dock_tile, SLE_UINT32, SLV_6, SL_MAX_VERSION), + SLE_CONDNULL(2, SL_MIN_VERSION, SLV_6), + SLE_CONDNULL(4, SLV_6, SLV_MULTITILE_DOCKS), SLE_REF(Station, town, REF_TOWN), SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SL_MAX_VERSION), @@ -423,7 +423,13 @@ static const SaveLoad _station_desc[] = { SLE_REF(Station, bus_stops, REF_ROADSTOPS), SLE_REF(Station, truck_stops, REF_ROADSTOPS), - SLE_VAR(Station, dock_tile, SLE_UINT32), + SLE_CONDNULL(4, SL_MIN_VERSION, SLV_MULTITILE_DOCKS), + SLE_CONDVAR(Station, ship_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION), + SLE_CONDVAR(Station, ship_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION), + SLE_CONDVAR(Station, ship_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION), + SLE_CONDVAR(Station, docking_station.tile, SLE_UINT32, SLV_MULTITILE_DOCKS, SL_MAX_VERSION), + SLE_CONDVAR(Station, docking_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION), + SLE_CONDVAR(Station, docking_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_MULTITILE_DOCKS, SL_MAX_VERSION), SLE_VAR(Station, airport.tile, SLE_UINT32), SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_140, SL_MAX_VERSION), @@ -544,11 +550,11 @@ static void Load_STNN() for (CargoID i = 0; i < num_cargo; i++) { SlObject(&st->goods[i], GetGoodsDesc()); FlowSaveLoad flow; - FlowStat *fs = NULL; + FlowStat *fs = nullptr; StationID prev_source = INVALID_STATION; for (uint32 j = 0; j < _num_flows; ++j) { SlObject(&flow, _flow_desc); - if (fs == NULL || prev_source != flow.source) { + if (fs == nullptr || prev_source != flow.source) { fs = &(st->goods[i].flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second); } else { fs->AppendShare(flow.via, flow.share, flow.restricted); @@ -638,7 +644,7 @@ static void Ptrs_ROADSTOP() } extern const ChunkHandler _station_chunk_handlers[] = { - { 'STNS', NULL, Load_STNS, Ptrs_STNS, NULL, CH_ARRAY }, - { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, NULL, CH_ARRAY }, - { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, NULL, CH_ARRAY | CH_LAST}, + { 'STNS', nullptr, Load_STNS, Ptrs_STNS, nullptr, CH_ARRAY }, + { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, nullptr, CH_ARRAY }, + { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/storage_sl.cpp b/src/saveload/storage_sl.cpp index 9ac77a9c39..b6401a9a58 100644 --- a/src/saveload/storage_sl.cpp +++ b/src/saveload/storage_sl.cpp @@ -114,5 +114,5 @@ static void Save_PSAC() /** Chunk handler for persistent storages. */ extern const ChunkHandler _persistent_storage_chunk_handlers[] = { - { 'PSAC', Save_PSAC, Load_PSAC, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'PSAC', Save_PSAC, Load_PSAC, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/story_sl.cpp b/src/saveload/story_sl.cpp index f9bbf34b9b..11aba1347a 100644 --- a/src/saveload/story_sl.cpp +++ b/src/saveload/story_sl.cpp @@ -102,6 +102,6 @@ static void Load_STORY_PAGE() } extern const ChunkHandler _story_page_chunk_handlers[] = { - { 'STPE', Save_STORY_PAGE_ELEMENT, Load_STORY_PAGE_ELEMENT, NULL, NULL, CH_ARRAY}, - { 'STPA', Save_STORY_PAGE, Load_STORY_PAGE, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'STPE', Save_STORY_PAGE_ELEMENT, Load_STORY_PAGE_ELEMENT, nullptr, nullptr, CH_ARRAY}, + { 'STPA', Save_STORY_PAGE, Load_STORY_PAGE, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/strings_sl.cpp b/src/saveload/strings_sl.cpp index d8fe81d113..9c3f838a80 100644 --- a/src/saveload/strings_sl.cpp +++ b/src/saveload/strings_sl.cpp @@ -49,7 +49,7 @@ StringID RemapOldStringID(StringID s) } /** Location to load the old names to. */ -char *_old_name_array = NULL; +char *_old_name_array = nullptr; /** * Copy and convert old custom names to UTF-8. @@ -61,7 +61,7 @@ char *_old_name_array = NULL; char *CopyFromOldName(StringID id) { /* Is this name an (old) custom name? */ - if (GetStringTab(id) != TEXT_TAB_OLD_CUSTOM) return NULL; + if (GetStringTab(id) != TEXT_TAB_OLD_CUSTOM) return nullptr; if (IsSavegameVersionBefore(SLV_37)) { /* Allow for expansion when converted to UTF-8. */ @@ -82,7 +82,7 @@ char *CopyFromOldName(StringID id) case 0xB8: c = 0x017E; break; // z with caron case 0xBC: c = 0x0152; break; // OE ligature case 0xBD: c = 0x0153; break; // oe ligature - case 0xBE: c = 0x0178; break; // Y with diaresis + case 0xBE: c = 0x0178; break; // Y with diaeresis default: break; } @@ -109,7 +109,7 @@ char *CopyFromOldName(StringID id) void ResetOldNames() { free(_old_name_array); - _old_name_array = NULL; + _old_name_array = nullptr; } /** @@ -140,5 +140,5 @@ static void Load_NAME() /** Chunk handlers related to strings. */ extern const ChunkHandler _name_chunk_handlers[] = { - { 'NAME', NULL, Load_NAME, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'NAME', nullptr, Load_NAME, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/subsidy_sl.cpp b/src/saveload/subsidy_sl.cpp index 6f10ec8d09..536ec2145f 100644 --- a/src/saveload/subsidy_sl.cpp +++ b/src/saveload/subsidy_sl.cpp @@ -48,5 +48,5 @@ static void Load_SUBS() } extern const ChunkHandler _subsidy_chunk_handlers[] = { - { 'SUBS', Save_SUBS, Load_SUBS, NULL, NULL, CH_ARRAY | CH_LAST}, + { 'SUBS', Save_SUBS, Load_SUBS, nullptr, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 6c13be336b..5c06d49912 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -28,6 +28,7 @@ void RebuildTownCaches() { Town *town; InitializeBuildingCounts(); + RebuildTownKdtree(); /* Reset town population and num_houses */ FOR_ALL_TOWNS(town) { @@ -323,6 +324,6 @@ static void Ptrs_TOWN() /** Chunk handler for towns. */ extern const ChunkHandler _town_chunk_handlers[] = { - { 'HIDS', Save_HIDS, Load_HIDS, NULL, NULL, CH_ARRAY }, - { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, NULL, CH_ARRAY | CH_LAST}, + { 'HIDS', Save_HIDS, Load_HIDS, nullptr, nullptr, CH_ARRAY }, + { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 540416586c..b08c1cb5ef 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -36,7 +36,7 @@ void ConnectMultiheadedTrains() Train *v; FOR_ALL_TRAINS(v) { - v->other_multiheaded_part = NULL; + v->other_multiheaded_part = nullptr; } FOR_ALL_TRAINS(v) { @@ -56,8 +56,8 @@ void ConnectMultiheadedTrains() bool sequential_matching = v->IsFrontEngine(); - for (Train *u = v; u != NULL; u = u->GetNextVehicle()) { - if (u->other_multiheaded_part != NULL) continue; // we already linked this one + for (Train *u = v; u != nullptr; u = u->GetNextVehicle()) { + if (u->other_multiheaded_part != nullptr) continue; // we already linked this one if (u->IsMultiheaded()) { if (!u->IsEngine()) { @@ -70,8 +70,8 @@ void ConnectMultiheadedTrains() EngineID eid = u->engine_type; Train *w; if (sequential_matching) { - for (w = u->GetNextVehicle(); w != NULL; w = w->GetNextVehicle()) { - if (w->engine_type != eid || w->other_multiheaded_part != NULL || !w->IsMultiheaded()) continue; + for (w = u->GetNextVehicle(); w != nullptr; w = w->GetNextVehicle()) { + if (w->engine_type != eid || w->other_multiheaded_part != nullptr || !w->IsMultiheaded()) continue; /* we found a car to partner with this engine. Now we will make sure it face the right way */ if (w->IsEngine()) { @@ -82,8 +82,8 @@ void ConnectMultiheadedTrains() } } else { uint stack_pos = 0; - for (w = u->GetNextVehicle(); w != NULL; w = w->GetNextVehicle()) { - if (w->engine_type != eid || w->other_multiheaded_part != NULL || !w->IsMultiheaded()) continue; + for (w = u->GetNextVehicle(); w != nullptr; w = w->GetNextVehicle()) { + if (w->engine_type != eid || w->other_multiheaded_part != nullptr || !w->IsMultiheaded()) continue; if (w->IsEngine()) { stack_pos++; @@ -94,7 +94,7 @@ void ConnectMultiheadedTrains() } } - if (w != NULL) { + if (w != nullptr) { w->other_multiheaded_part = u; u->other_multiheaded_part = w; } else { @@ -118,7 +118,7 @@ void ConvertOldMultiheadToNew() FOR_ALL_TRAINS(t) { if (HasBit(t->subtype, 7) && ((t->subtype & ~0x80) == 0 || (t->subtype & ~0x80) == 4)) { - for (Train *u = t; u != NULL; u = u->Next()) { + for (Train *u = t; u != nullptr; u = u->Next()) { const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); ClrBit(u->subtype, 7); @@ -200,7 +200,7 @@ void UpdateOldAircraft() if (a->subtype == AIR_HELICOPTER) a->Next()->Next()->cur_speed = 32; /* set new position x,y,z */ - GetAircraftFlightLevelBounds(a, &a->z_pos, NULL); + GetAircraftFlightLevelBounds(a, &a->z_pos, nullptr); SetAircraftPosition(a, gp.x, gp.y, GetAircraftFlightLevel(a)); } } @@ -252,11 +252,11 @@ void AfterLoadVehicles(bool part_of_load) FOR_ALL_VEHICLES(v) { /* Reinstate the previous pointer */ - if (v->Next() != NULL) v->Next()->previous = v; - if (v->NextShared() != NULL) v->NextShared()->previous_shared = v; + if (v->Next() != nullptr) v->Next()->previous = v; + if (v->NextShared() != nullptr) v->NextShared()->previous_shared = v; if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID; - v->first = NULL; + v->first = nullptr; if (v->IsGroundVehicle()) v->GetGroundVehicleCache()->first_engine = INVALID_ENGINE; } @@ -272,9 +272,9 @@ void AfterLoadVehicles(bool part_of_load) std::map mapping; FOR_ALL_VEHICLES(v) { - if (v->orders.old != NULL) { + if (v->orders.old != nullptr) { if (IsSavegameVersionBefore(SLV_105)) { // Pre-105 didn't save an OrderList - if (mapping[v->orders.old] == NULL) { + if (mapping[v->orders.old] == nullptr) { /* This adds the whole shared vehicle chain for case b */ /* Creating an OrderList here is safe because the number of vehicles @@ -290,7 +290,7 @@ void AfterLoadVehicles(bool part_of_load) } } } else { // OrderList was saved as such, only recalculate not saved values - if (v->PreviousShared() == NULL) { + if (v->PreviousShared() == nullptr) { v->orders.list->Initialize(v->orders.list->first, v); } } @@ -300,8 +300,8 @@ void AfterLoadVehicles(bool part_of_load) FOR_ALL_VEHICLES(v) { /* Fill the first pointers */ - if (v->Previous() == NULL) { - for (Vehicle *u = v; u != NULL; u = u->Next()) { + if (v->Previous() == nullptr) { + for (Vehicle *u = v; u != nullptr; u = u->Next()) { u->first = v; } } @@ -311,12 +311,12 @@ void AfterLoadVehicles(bool part_of_load) if (IsSavegameVersionBefore(SLV_105)) { /* Before 105 there was no order for shared orders, thus it messed up horribly */ FOR_ALL_VEHICLES(v) { - if (v->First() != v || v->orders.list != NULL || v->previous_shared != NULL || v->next_shared == NULL) continue; + if (v->First() != v || v->orders.list != nullptr || v->previous_shared != nullptr || v->next_shared == nullptr) continue; /* As above, allocating OrderList here is safe. */ assert(OrderList::CanAllocateItem()); - v->orders.list = new OrderList(NULL, v); - for (Vehicle *u = v; u != NULL; u = u->next_shared) { + v->orders.list = new OrderList(nullptr, v); + for (Vehicle *u = v; u != nullptr; u = u->next_shared) { u->orders.list = v->orders.list; } } @@ -392,9 +392,9 @@ void AfterLoadVehicles(bool part_of_load) CheckValidVehicles(); FOR_ALL_VEHICLES(v) { - assert(v->first != NULL); + assert(v->first != nullptr); - v->trip_occupancy = CalcPercentVehicleFilled(v, NULL); + v->trip_occupancy = CalcPercentVehicleFilled(v, nullptr); switch (v->type) { case VEH_TRAIN: { @@ -410,6 +410,14 @@ void AfterLoadVehicles(bool part_of_load) RoadVehicle *rv = RoadVehicle::From(v); if (rv->IsFrontEngine()) { rv->gcache.last_speed = rv->cur_speed; // update displayed road vehicle speed + + rv->roadtype = Engine::Get(rv->engine_type)->u.road.roadtype; + rv->compatible_roadtypes = GetRoadTypeInfo(rv->roadtype)->powered_roadtypes; + for (RoadVehicle *u = rv; u != nullptr; u = u->Next()) { + u->roadtype = rv->roadtype; + u->compatible_roadtypes = rv->compatible_roadtypes; + } + RoadVehUpdateCache(rv); if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { rv->CargoChanged(); @@ -448,13 +456,7 @@ void AfterLoadVehicles(bool part_of_load) FOR_ALL_VEHICLES(v) { switch (v->type) { - case VEH_ROAD: { - RoadVehicle *rv = RoadVehicle::From(v); - rv->roadtype = HasBit(EngInfo(v->First()->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; - rv->compatible_roadtypes = RoadTypeToRoadTypes(rv->roadtype); - FALLTHROUGH; - } - + case VEH_ROAD: case VEH_TRAIN: case VEH_SHIP: v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq); @@ -502,7 +504,7 @@ void FixupTrainLengths() /* The vehicle center is now more to the front depending on vehicle length, * so we need to move all vehicles forward to cover the difference to the * old center, otherwise wagon spacing in trains would be broken upon load. */ - for (Train *u = Train::From(v); u != NULL; u = u->Next()) { + for (Train *u = Train::From(v); u != nullptr; u = u->Next()) { if (u->track == TRACK_BIT_DEPOT || (u->vehstatus & VS_CRASHED)) continue; Train *next = u->Next(); @@ -514,7 +516,7 @@ void FixupTrainLengths() if (!TrainController(u, next, false)) break; } - if (next != NULL && done < diff && u->IsFrontEngine()) { + if (next != nullptr && done < diff && u->IsFrontEngine()) { /* Pulling the front vehicle forwards failed, we either encountered a dead-end * or a red signal. To fix this, we try to move the whole train the required * space backwards and re-do the fix up of the front vehicle. */ @@ -530,14 +532,14 @@ void FixupTrainLengths() /* We moved the first vehicle which is now the last. Move it back to the * original position as we will fix up the last vehicle later in the loop. */ - for (int i = 0; i < done; i++) TrainController(u->Last(), NULL); + for (int i = 0; i < done; i++) TrainController(u->Last(), nullptr); /* Move the train backwards to get space for the first vehicle. As the stopping * distance from a line end is rounded up, move the train one unit more to cater * for front vehicles with odd lengths. */ int moved; for (moved = 0; moved < diff + 1; moved++) { - if (!TrainController(u, NULL, false)) break; + if (!TrainController(u, nullptr, false)) break; } /* Swap start<>end, start+1<>end-1, ... again. */ @@ -556,17 +558,17 @@ void FixupTrainLengths() /* We moved one unit more backwards than needed for even-length front vehicles, * try to move that unit forward again. We don't care if this step fails. */ - TrainController(u, NULL, false); + TrainController(u, nullptr, false); } /* If the next wagon is still in a depot, check if it shouldn't be outside already. */ - if (next != NULL && next->track == TRACK_BIT_DEPOT) { + if (next != nullptr && next->track == TRACK_BIT_DEPOT) { int d = TicksToLeaveDepot(u); if (d <= 0) { /* Next vehicle should have left the depot already, show it and pull forward. */ next->vehstatus &= ~VS_HIDDEN; next->track = TrackToTrackBits(GetRailDepotTrack(next->tile)); - for (int i = 0; i >= d; i--) TrainController(next, NULL); + for (int i = 0; i >= d; i--) TrainController(next, nullptr); } } } @@ -752,21 +754,23 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) static const SaveLoad _roadveh_desc[] = { SLE_WRITEBYTE(Vehicle, type), SLE_VEH_INCLUDE(), - SLE_VAR(RoadVehicle, state, SLE_UINT8), - SLE_VAR(RoadVehicle, frame, SLE_UINT8), - SLE_VAR(RoadVehicle, blocked_ctr, SLE_UINT16), - SLE_VAR(RoadVehicle, overtaking, SLE_UINT8), - SLE_VAR(RoadVehicle, overtaking_ctr, SLE_UINT8), - SLE_VAR(RoadVehicle, crashed_ctr, SLE_UINT16), - SLE_VAR(RoadVehicle, reverse_ctr, SLE_UINT8), + SLE_VAR(RoadVehicle, state, SLE_UINT8), + SLE_VAR(RoadVehicle, frame, SLE_UINT8), + SLE_VAR(RoadVehicle, blocked_ctr, SLE_UINT16), + SLE_VAR(RoadVehicle, overtaking, SLE_UINT8), + SLE_VAR(RoadVehicle, overtaking_ctr, SLE_UINT8), + SLE_VAR(RoadVehicle, crashed_ctr, SLE_UINT16), + SLE_VAR(RoadVehicle, reverse_ctr, SLE_UINT8), + SLE_CONDDEQUE(RoadVehicle, path.td, SLE_UINT8, SLV_ROADVEH_PATH_CACHE, SL_MAX_VERSION), + SLE_CONDDEQUE(RoadVehicle, path.tile, SLE_UINT32, SLV_ROADVEH_PATH_CACHE, SL_MAX_VERSION), - SLE_CONDNULL(2, SLV_6, SLV_69), - SLE_CONDVAR(RoadVehicle, gv_flags, SLE_UINT16, SLV_139, SL_MAX_VERSION), - SLE_CONDNULL(4, SLV_69, SLV_131), - SLE_CONDNULL(2, SLV_6, SLV_131), - SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space + SLE_CONDNULL(2, SLV_6, SLV_69), + SLE_CONDVAR(RoadVehicle, gv_flags, SLE_UINT16, SLV_139, SL_MAX_VERSION), + SLE_CONDNULL(4, SLV_69, SLV_131), + SLE_CONDNULL(2, SLV_6, SLV_131), + SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space - SLE_END() + SLE_END() }; static const SaveLoad _ship_desc[] = { @@ -958,5 +962,5 @@ static void Ptrs_VEHS() } extern const ChunkHandler _veh_chunk_handlers[] = { - { 'VEHS', Save_VEHS, Load_VEHS, Ptrs_VEHS, NULL, CH_SPARSE_ARRAY | CH_LAST}, + { 'VEHS', Save_VEHS, Load_VEHS, Ptrs_VEHS, nullptr, CH_SPARSE_ARRAY | CH_LAST}, }; diff --git a/src/saveload/waypoint_sl.cpp b/src/saveload/waypoint_sl.cpp index ae74d812b1..70a1a27394 100644 --- a/src/saveload/waypoint_sl.cpp +++ b/src/saveload/waypoint_sl.cpp @@ -36,13 +36,13 @@ struct OldWaypoint { uint8 localidx; uint32 grfid; const StationSpec *spec; - OwnerByte owner; + Owner owner; size_t new_index; }; /** Temporary array with old waypoints. */ -static SmallVector _old_waypoints; +static std::vector _old_waypoints; /** * Update the waypoint orders to get the new waypoint ID. @@ -52,10 +52,10 @@ static void UpdateWaypointOrder(Order *o) { if (!o->IsType(OT_GOTO_WAYPOINT)) return; - for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { - if (wp->index != o->GetDestination()) continue; + for (OldWaypoint &wp : _old_waypoints) { + if (wp.index != o->GetDestination()) continue; - o->SetDestination((DestinationID)wp->new_index); + o->SetDestination((DestinationID)wp.new_index); return; } } @@ -71,47 +71,47 @@ void MoveWaypointsToBaseStations() * id which was stored in m4 is now saved as a grf/id reference in the * waypoint struct. */ if (IsSavegameVersionBefore(SLV_17)) { - for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { - if (wp->delete_ctr != 0) continue; // The waypoint was deleted + for (OldWaypoint &wp : _old_waypoints) { + if (wp.delete_ctr != 0) continue; // The waypoint was deleted /* Waypoint indices were not added to the map prior to this. */ - _m[wp->xy].m2 = (StationID)wp->index; + _m[wp.xy].m2 = (StationID)wp.index; - if (HasBit(_m[wp->xy].m3, 4)) { - wp->spec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(_m[wp->xy].m4 + 1); + if (HasBit(_m[wp.xy].m3, 4)) { + wp.spec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(_m[wp.xy].m4 + 1); } } } else { /* As of version 17, we recalculate the custom graphic ID of waypoints * from the GRF ID / station index. */ - for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { + for (OldWaypoint &wp : _old_waypoints) { StationClass* stclass = StationClass::Get(STAT_CLASS_WAYP); for (uint i = 0; i < stclass->GetSpecCount(); i++) { const StationSpec *statspec = stclass->GetSpec(i); - if (statspec != NULL && statspec->grf_prop.grffile->grfid == wp->grfid && statspec->grf_prop.local_id == wp->localidx) { - wp->spec = statspec; + if (statspec != nullptr && statspec->grf_prop.grffile->grfid == wp.grfid && statspec->grf_prop.local_id == wp.localidx) { + wp.spec = statspec; break; } } } } - if (!Waypoint::CanAllocateItem(_old_waypoints.Length())) SlError(STR_ERROR_TOO_MANY_STATIONS_LOADING); + if (!Waypoint::CanAllocateItem(_old_waypoints.size())) SlError(STR_ERROR_TOO_MANY_STATIONS_LOADING); /* All saveload conversions have been done. Create the new waypoints! */ - for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { - Waypoint *new_wp = new Waypoint(wp->xy); - new_wp->town = wp->town; - new_wp->town_cn = wp->town_cn; - new_wp->name = wp->name; + for (OldWaypoint &wp : _old_waypoints) { + Waypoint *new_wp = new Waypoint(wp.xy); + new_wp->town = wp.town; + new_wp->town_cn = wp.town_cn; + new_wp->name = wp.name; new_wp->delete_ctr = 0; // Just reset delete counter for once. - new_wp->build_date = wp->build_date; - new_wp->owner = wp->owner; + new_wp->build_date = wp.build_date; + new_wp->owner = wp.owner; new_wp->string_id = STR_SV_STNAME_WAYPOINT; - TileIndex t = wp->xy; - if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp->index) { + TileIndex t = wp.xy; + if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp.index) { /* The tile might've been reserved! */ bool reserved = !IsSavegameVersionBefore(SLV_100) && HasBit(_m[t].m5, 4); @@ -122,13 +122,13 @@ void MoveWaypointsToBaseStations() SetRailStationReservation(t, reserved); - if (wp->spec != NULL) { - SetCustomStationSpecIndex(t, AllocateSpecToStation(wp->spec, new_wp, true)); + if (wp.spec != nullptr) { + SetCustomStationSpecIndex(t, AllocateSpecToStation(wp.spec, new_wp, true)); } new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); } - wp->new_index = new_wp->index; + wp.new_index = new_wp->index; } /* Update the orders of vehicles */ @@ -136,7 +136,7 @@ void MoveWaypointsToBaseStations() FOR_ALL_ORDER_LISTS(ol) { if (ol->GetFirstSharedVehicle()->type != VEH_TRAIN) continue; - for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); + for (Order *o = ol->GetFirstOrder(); o != nullptr; o = o->next) UpdateWaypointOrder(o); } Vehicle *v; @@ -146,7 +146,8 @@ void MoveWaypointsToBaseStations() UpdateWaypointOrder(&v->current_order); } - _old_waypoints.Reset(); + _old_waypoints.clear(); + _old_waypoints.shrink_to_fit(); } static const SaveLoad _old_waypoint_desc[] = { @@ -172,12 +173,13 @@ static const SaveLoad _old_waypoint_desc[] = { static void Load_WAYP() { /* Precaution for when loading failed and it didn't get cleared */ - _old_waypoints.Clear(); + _old_waypoints.clear(); int index; while ((index = SlIterateArray()) != -1) { - OldWaypoint *wp = _old_waypoints.Append(); + /*C++17: OldWaypoint *wp = &*/ _old_waypoints.emplace_back(); + OldWaypoint *wp = &_old_waypoints.back(); memset(wp, 0, sizeof(*wp)); wp->index = index; @@ -187,31 +189,31 @@ static void Load_WAYP() static void Ptrs_WAYP() { - for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { - SlObject(wp, _old_waypoint_desc); + for (OldWaypoint &wp : _old_waypoints) { + SlObject(&wp, _old_waypoint_desc); if (IsSavegameVersionBefore(SLV_12)) { - wp->town_cn = (wp->string_id & 0xC000) == 0xC000 ? (wp->string_id >> 8) & 0x3F : 0; - wp->town = ClosestTownFromTile(wp->xy, UINT_MAX); + wp.town_cn = (wp.string_id & 0xC000) == 0xC000 ? (wp.string_id >> 8) & 0x3F : 0; + wp.town = ClosestTownFromTile(wp.xy, UINT_MAX); } else if (IsSavegameVersionBefore(SLV_122)) { /* Only for versions 12 .. 122 */ - if (!Town::IsValidID(wp->town_index)) { + if (!Town::IsValidID(wp.town_index)) { /* Upon a corrupted waypoint we'll likely get here. The next step will be to - * loop over all Ptrs procs to NULL the pointers. However, we don't know - * whether we're in the NULL or "normal" Ptrs proc. So just clear the list + * loop over all Ptrs procs to nullptr the pointers. However, we don't know + * whether we're in the nullptr or "normal" Ptrs proc. So just clear the list * of old waypoints we constructed and then this waypoint (and the other - * possibly corrupt ones) will not be queried in the NULL Ptrs proc run. */ - _old_waypoints.Clear(); + * possibly corrupt ones) will not be queried in the nullptr Ptrs proc run. */ + _old_waypoints.clear(); SlErrorCorrupt("Referencing invalid Town"); } - wp->town = Town::Get(wp->town_index); + wp.town = Town::Get(wp.town_index); } if (IsSavegameVersionBefore(SLV_84)) { - wp->name = CopyFromOldName(wp->string_id); + wp.name = CopyFromOldName(wp.string_id); } } } extern const ChunkHandler _waypoint_chunk_handlers[] = { - { 'CHKP', NULL, Load_WAYP, Ptrs_WAYP, NULL, CH_ARRAY | CH_LAST}, + { 'CHKP', nullptr, Load_WAYP, Ptrs_WAYP, nullptr, CH_ARRAY | CH_LAST}, }; diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 700a065669..b2d7d21bd8 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -120,7 +120,7 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user } FILE *f = fopen(name, "wb"); - if (f == NULL) return false; + if (f == nullptr) return false; /* Each scanline must be aligned on a 32bit boundary */ uint bytewidth = Align(w * bpp, 4); // bytes per line in file @@ -268,18 +268,18 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); - if (f == NULL) return false; + if (f == nullptr) return false; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast(name), png_my_error, png_my_warning); - if (png_ptr == NULL) { + if (png_ptr == nullptr) { fclose(f); return false; } info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - png_destroy_write_struct(&png_ptr, (png_infopp)NULL); + if (info_ptr == nullptr) { + png_destroy_write_struct(&png_ptr, (png_infopp)nullptr); fclose(f); return false; } @@ -311,7 +311,7 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user char *p = buf; p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); p = strecpy(p, "NewGRFs:\n", lastof(buf)); - for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) { + for (const GRFConfig *c = _game_mode == GM_MENU ? nullptr : _grfconfig; c != nullptr; c = c->next) { p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid)); p = md5sumToString(p, lastof(buf), c->ident.md5sum); p += seprintf(p, lastof(buf), " %s\n", c->filename); @@ -319,7 +319,7 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user p = strecpy(p, "\nCompanies:\n", lastof(buf)); const Company *c; FOR_ALL_COMPANIES(c) { - if (c->ai_info == NULL) { + if (c->ai_info == nullptr) { p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index); } else { p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); @@ -447,7 +447,7 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user if (pixelformat != 8 || w == 0) return false; f = fopen(name, "wb"); - if (f == NULL) return false; + if (f == nullptr) return false; memset(&pcx, 0, sizeof(pcx)); @@ -701,7 +701,7 @@ static const char *MakeScreenshotName(const char *default_fn, const char *ext, b static bool MakeSmallScreenshot(bool crashlog) { const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; - return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension, crashlog), CurrentScreenCallback, NULL, _screen.width, _screen.height, + return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension, crashlog), CurrentScreenCallback, nullptr, _screen.width, _screen.height, BlitterFactory::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette); } @@ -743,7 +743,7 @@ void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp) vp->top = 0; vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom); vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom); - vp->overlay = NULL; + vp->overlay = nullptr; } /** @@ -800,7 +800,7 @@ bool MakeHeightmapScreenshot(const char *filename) palette[i].b = i; } const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; - return sf->proc(filename, HeightmapCallback, NULL, MapSizeX(), MapSizeY(), 8, palette); + return sf->proc(filename, HeightmapCallback, nullptr, MapSizeX(), MapSizeY(), 8, palette); } /** @@ -821,7 +821,7 @@ bool MakeScreenshot(ScreenshotType t, const char *name) } _screenshot_name[0] = '\0'; - if (name != NULL) strecpy(_screenshot_name, name, lastof(_screenshot_name)); + if (name != nullptr) strecpy(_screenshot_name, name, lastof(_screenshot_name)); bool ret; switch (t) { diff --git a/src/script/api/ai/ai_engine.hpp.sq b/src/script/api/ai/ai_engine.hpp.sq index 6dbde29099..b10e7e34f7 100644 --- a/src/script/api/ai/ai_engine.hpp.sq +++ b/src/script/api/ai/ai_engine.hpp.sq @@ -41,6 +41,8 @@ void SQAIEngine_Register(Squirrel *engine) SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsWagon, "IsWagon", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRail, "CanRunOnRail", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRail, "HasPowerOnRail", 3, ".ii"); + SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRoad, "CanRunOnRoad", 3, ".ii"); + SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRoad, "HasPowerOnRoad", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRoadType, "GetRoadType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRailType, "GetRailType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsArticulated, "IsArticulated", 2, ".i"); diff --git a/src/script/api/ai/ai_event.hpp.sq b/src/script/api/ai/ai_event.hpp.sq index 75098625a3..11fd181434 100644 --- a/src/script/api/ai/ai_event.hpp.sq +++ b/src/script/api/ai/ai_event.hpp.sq @@ -50,6 +50,7 @@ void SQAIEvent_Register(Squirrel *engine) SQAIEvent.DefSQConst(engine, ScriptEvent::ET_GOAL_QUESTION_ANSWER, "ET_GOAL_QUESTION_ANSWER"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_EXCLUSIVE_TRANSPORT_RIGHTS, "ET_EXCLUSIVE_TRANSPORT_RIGHTS"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_ROAD_RECONSTRUCTION, "ET_ROAD_RECONSTRUCTION"); + SQAIEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_AUTOREPLACED, "ET_VEHICLE_AUTOREPLACED"); SQAIEvent.DefSQMethod(engine, &ScriptEvent::GetEventType, "GetEventType", 1, "x"); diff --git a/src/script/api/ai/ai_event_types.hpp.sq b/src/script/api/ai/ai_event_types.hpp.sq index f3468d14ba..69cdba2dc9 100644 --- a/src/script/api/ai/ai_event_types.hpp.sq +++ b/src/script/api/ai/ai_event_types.hpp.sq @@ -405,3 +405,19 @@ void SQAIEventRoadReconstruction_Register(Squirrel *engine) SQAIEventRoadReconstruction.PostRegister(engine); } + + +template <> const char *GetClassName() { return "AIEventVehicleAutoReplaced"; } + +void SQAIEventVehicleAutoReplaced_Register(Squirrel *engine) +{ + DefSQClass SQAIEventVehicleAutoReplaced("AIEventVehicleAutoReplaced"); + SQAIEventVehicleAutoReplaced.PreRegister(engine, "AIEvent"); + + SQAIEventVehicleAutoReplaced.DefSQStaticMethod(engine, &ScriptEventVehicleAutoReplaced::Convert, "Convert", 2, ".x"); + + SQAIEventVehicleAutoReplaced.DefSQMethod(engine, &ScriptEventVehicleAutoReplaced::GetOldVehicleID, "GetOldVehicleID", 1, "x"); + SQAIEventVehicleAutoReplaced.DefSQMethod(engine, &ScriptEventVehicleAutoReplaced::GetNewVehicleID, "GetNewVehicleID", 1, "x"); + + SQAIEventVehicleAutoReplaced.PostRegister(engine); +} diff --git a/src/script/api/ai/ai_group.hpp.sq b/src/script/api/ai/ai_group.hpp.sq index 5fa50ae1be..29d86754d0 100644 --- a/src/script/api/ai/ai_group.hpp.sq +++ b/src/script/api/ai/ai_group.hpp.sq @@ -45,6 +45,10 @@ void SQAIGroup_Register(Squirrel *engine) SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetProfitThisYear, "GetProfitThisYear", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetProfitLastYear, "GetProfitLastYear", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetCurrentUsage, "GetCurrentUsage", 2, ".i"); + SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::SetPrimaryColour, "SetPrimaryColour", 3, ".ii"); + SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::SetSecondaryColour, "SetSecondaryColour", 3, ".ii"); + SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetPrimaryColour, "GetPrimaryColour", 2, ".i"); + SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetSecondaryColour, "GetSecondaryColour", 2, ".i"); SQAIGroup.PostRegister(engine); } diff --git a/src/script/api/ai/ai_rail.hpp.sq b/src/script/api/ai/ai_rail.hpp.sq index ba9d7e6564..d7e421669f 100644 --- a/src/script/api/ai/ai_rail.hpp.sq +++ b/src/script/api/ai/ai_rail.hpp.sq @@ -56,7 +56,7 @@ void SQAIRail_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_ARE_NO_SIGNALS, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_STATION, ScriptRail::ERR_UNSUITABLE_TRACK); - ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_RAIL, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); ScriptError::RegisterErrorMapString(ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); diff --git a/src/script/api/ai/ai_road.hpp.sq b/src/script/api/ai/ai_road.hpp.sq index 3da4607c90..7e91fb2682 100644 --- a/src/script/api/ai/ai_road.hpp.sq +++ b/src/script/api/ai/ai_road.hpp.sq @@ -26,9 +26,13 @@ void SQAIRoad_Register(Squirrel *engine) SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_ROAD, "ROADTYPE_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_TRAM, "ROADTYPE_TRAM"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_INVALID, "ROADTYPE_INVALID"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_ROAD, "ROADTRAMTYPES_ROAD"); + SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_TRAM, "ROADTRAMTYPES_TRAM"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_BUS, "ROADVEHTYPE_BUS"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_TRUCK, "ROADVEHTYPE_TRUCK"); SQAIRoad.DefSQConst(engine, ScriptRoad::BT_ROAD, "BT_ROAD"); @@ -40,12 +44,19 @@ void SQAIRoad_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_DIRECTION, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_ROAD, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_TRAMWAY, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_INCOMPATIBLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetName, "GetName", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); @@ -54,6 +65,9 @@ void SQAIRoad_Register(Squirrel *engine) SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTypeAvailable, "IsRoadTypeAvailable", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetCurrentRoadType, "GetCurrentRoadType", 1, "."); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::SetCurrentRoadType, "SetCurrentRoadType", 2, ".i"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehCanRunOnRoad, "RoadVehCanRunOnRoad", 3, ".ii"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehHasPowerOnRoad, "RoadVehHasPowerOnRoad", 3, ".ii"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::ConvertRoadType, "ConvertRoadType", 4, ".iii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::HasRoadType, "HasRoadType", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::AreRoadTilesConnected, "AreRoadTilesConnected", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadParts, "CanBuildConnectedRoadParts", 5, ".iaii"); @@ -74,6 +88,8 @@ void SQAIRoad_Register(Squirrel *engine) SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadDepot, "RemoveRoadDepot", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadStation, "RemoveRoadStation", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetBuildCost, "GetBuildCost", 3, ".ii"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadTramType, "GetRoadTramType", 2, ".i"); + SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQAIRoad.PostRegister(engine); diff --git a/src/script/api/ai/ai_roadtypelist.hpp.sq b/src/script/api/ai/ai_roadtypelist.hpp.sq new file mode 100644 index 0000000000..cbe316f8d2 --- /dev/null +++ b/src/script/api/ai/ai_roadtypelist.hpp.sq @@ -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 . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_roadtypelist.hpp" +#include "../template/template_roadtypelist.hpp.sq" + + +template <> const char *GetClassName() { return "AIRoadTypeList"; } + +void SQAIRoadTypeList_Register(Squirrel *engine) +{ + DefSQClass SQAIRoadTypeList("AIRoadTypeList"); + SQAIRoadTypeList.PreRegister(engine, "AIList"); + SQAIRoadTypeList.AddConstructor(engine, "xi"); + + SQAIRoadTypeList.PostRegister(engine); +} diff --git a/src/script/api/ai/ai_vehicle.hpp.sq b/src/script/api/ai/ai_vehicle.hpp.sq index 0eb21ed672..dbd0096ada 100644 --- a/src/script/api/ai/ai_vehicle.hpp.sq +++ b/src/script/api/ai/ai_vehicle.hpp.sq @@ -122,6 +122,8 @@ void SQAIVehicle_Register(Squirrel *engine) SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsInDepot, "IsInDepot", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsStoppedInDepot, "IsStoppedInDepot", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::BuildVehicle, "BuildVehicle", 3, ".ii"); + SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::BuildVehicleWithRefit, "BuildVehicleWithRefit", 4, ".iii"); + SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetBuildWithRefitCapacity, "GetBuildWithRefitCapacity", 4, ".iii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::CloneVehicle, "CloneVehicle", 4, ".iib"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagon, "MoveWagon", 5, ".iiii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagonChain, "MoveWagonChain", 5, ".iiii"); diff --git a/src/script/api/ai_changelog.hpp b/src/script/api/ai_changelog.hpp index f9db78c280..2a2918fe2b 100644 --- a/src/script/api/ai_changelog.hpp +++ b/src/script/api/ai_changelog.hpp @@ -15,6 +15,30 @@ * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * + * \b 1.10.0 + * + * This version is not yet released. The following changes are not set in stone yet. + * + * API additions: + * \li AIGroup::SetPrimaryColour + * \li AIGroup::SetSecondaryColour + * \li AIGroup::GetPrimaryColour + * \li AIGroup::GetSecondaryColour + * \li AIVehicle::BuildVehicleWithRefit + * \li AIVehicle::GetBuildWithRefitCapacity + * \li AIRoad::GetName + * \li AIRoad::RoadVehCanRunOnRoad + * \li AIRoad::RoadVehHasPowerOnRoad + * \li AIRoad::ConvertRoadType + * \li AIRoad::GetMaxSpeed + * \li AIEngine::CanRunOnRoad + * \li AIEngine::HasPowerOnRoad + * \li AIRoadTypeList::RoadTypeList + * \li AIEventVehicleAutoReplaced + * + * Other changes: + * \li AITile::DemolishTile works without a selected company + * * \b 1.9.0 * * API additions: @@ -34,6 +58,9 @@ * * No changes * + * API additions: + * \li AIRoad::ERR_ROADTYPE_DISALLOWS_CROSSING + * * \b 1.7.0 - 1.7.2 * * No changes @@ -287,7 +314,7 @@ * destination it its catchment area. One industry tile or one town house * is enough as long as station accepts the cargo. Awarded subsidies are no * longer bound to stations used for first delivery, any station can be - * used for loading and unloading as long as cargo is transfered from + * used for loading and unloading as long as cargo is transferred from * source to destination. * \li Make AIEngine:CanRefitCargo() not report refittability to mail by * default for aircraft. It is not necessarily true. This means that even diff --git a/src/script/api/game/game_engine.hpp.sq b/src/script/api/game/game_engine.hpp.sq index 4881755473..67153b1d9e 100644 --- a/src/script/api/game/game_engine.hpp.sq +++ b/src/script/api/game/game_engine.hpp.sq @@ -41,6 +41,8 @@ void SQGSEngine_Register(Squirrel *engine) SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsWagon, "IsWagon", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRail, "CanRunOnRail", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRail, "HasPowerOnRail", 3, ".ii"); + SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRoad, "CanRunOnRoad", 3, ".ii"); + SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRoad, "HasPowerOnRoad", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRoadType, "GetRoadType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRailType, "GetRailType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsArticulated, "IsArticulated", 2, ".i"); diff --git a/src/script/api/game/game_event.hpp.sq b/src/script/api/game/game_event.hpp.sq index 53b9b2ce9e..1febdb2be9 100644 --- a/src/script/api/game/game_event.hpp.sq +++ b/src/script/api/game/game_event.hpp.sq @@ -50,6 +50,7 @@ void SQGSEvent_Register(Squirrel *engine) SQGSEvent.DefSQConst(engine, ScriptEvent::ET_GOAL_QUESTION_ANSWER, "ET_GOAL_QUESTION_ANSWER"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_EXCLUSIVE_TRANSPORT_RIGHTS, "ET_EXCLUSIVE_TRANSPORT_RIGHTS"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_ROAD_RECONSTRUCTION, "ET_ROAD_RECONSTRUCTION"); + SQGSEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_AUTOREPLACED, "ET_VEHICLE_AUTOREPLACED"); SQGSEvent.DefSQMethod(engine, &ScriptEvent::GetEventType, "GetEventType", 1, "x"); diff --git a/src/script/api/game/game_rail.hpp.sq b/src/script/api/game/game_rail.hpp.sq index c057360300..f145e84818 100644 --- a/src/script/api/game/game_rail.hpp.sq +++ b/src/script/api/game/game_rail.hpp.sq @@ -56,7 +56,7 @@ void SQGSRail_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_ARE_NO_SIGNALS, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_STATION, ScriptRail::ERR_UNSUITABLE_TRACK); - ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_RAIL, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); ScriptError::RegisterErrorMapString(ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); diff --git a/src/script/api/game/game_road.hpp.sq b/src/script/api/game/game_road.hpp.sq index 51da4144eb..725e24bf12 100644 --- a/src/script/api/game/game_road.hpp.sq +++ b/src/script/api/game/game_road.hpp.sq @@ -26,9 +26,13 @@ void SQGSRoad_Register(Squirrel *engine) SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_ROAD, "ROADTYPE_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_TRAM, "ROADTYPE_TRAM"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_INVALID, "ROADTYPE_INVALID"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_ROAD, "ROADTRAMTYPES_ROAD"); + SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTRAMTYPES_TRAM, "ROADTRAMTYPES_TRAM"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_BUS, "ROADVEHTYPE_BUS"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_TRUCK, "ROADVEHTYPE_TRUCK"); SQGSRoad.DefSQConst(engine, ScriptRoad::BT_ROAD, "BT_ROAD"); @@ -40,12 +44,19 @@ void SQGSRoad_Register(Squirrel *engine) ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_DIRECTION, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS); + ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED_ROAD, ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_TRAMWAY, ScriptRoad::ERR_UNSUITABLE_ROAD); + ScriptError::RegisterErrorMap(STR_ERROR_INCOMPATIBLE_ROAD, ScriptRoad::ERR_UNSUITABLE_ROAD); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROADTYPE_DISALLOWS_CROSSING, "ERR_ROADTYPE_DISALLOWS_CROSSING"); + ScriptError::RegisterErrorMapString(ScriptRoad::ERR_UNSUITABLE_ROAD, "ERR_UNSUITABLE_ROAD"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetName, "GetName", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); @@ -54,6 +65,9 @@ void SQGSRoad_Register(Squirrel *engine) SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTypeAvailable, "IsRoadTypeAvailable", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetCurrentRoadType, "GetCurrentRoadType", 1, "."); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::SetCurrentRoadType, "SetCurrentRoadType", 2, ".i"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehCanRunOnRoad, "RoadVehCanRunOnRoad", 3, ".ii"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RoadVehHasPowerOnRoad, "RoadVehHasPowerOnRoad", 3, ".ii"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::ConvertRoadType, "ConvertRoadType", 4, ".iii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::HasRoadType, "HasRoadType", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::AreRoadTilesConnected, "AreRoadTilesConnected", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadParts, "CanBuildConnectedRoadParts", 5, ".iaii"); @@ -74,6 +88,8 @@ void SQGSRoad_Register(Squirrel *engine) SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadDepot, "RemoveRoadDepot", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadStation, "RemoveRoadStation", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetBuildCost, "GetBuildCost", 3, ".ii"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadTramType, "GetRoadTramType", 2, ".i"); + SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQGSRoad.PostRegister(engine); diff --git a/src/script/api/game/game_roadtypelist.hpp.sq b/src/script/api/game/game_roadtypelist.hpp.sq new file mode 100644 index 0000000000..f61adaa8fa --- /dev/null +++ b/src/script/api/game/game_roadtypelist.hpp.sq @@ -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 . + */ + +/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_roadtypelist.hpp" +#include "../template/template_roadtypelist.hpp.sq" + + +template <> const char *GetClassName() { return "GSRoadTypeList"; } + +void SQGSRoadTypeList_Register(Squirrel *engine) +{ + DefSQClass SQGSRoadTypeList("GSRoadTypeList"); + SQGSRoadTypeList.PreRegister(engine, "GSList"); + SQGSRoadTypeList.AddConstructor(engine, "xi"); + + SQGSRoadTypeList.PostRegister(engine); +} diff --git a/src/script/api/game/game_vehicle.hpp.sq b/src/script/api/game/game_vehicle.hpp.sq index 3dc9fe67ad..15a007046e 100644 --- a/src/script/api/game/game_vehicle.hpp.sq +++ b/src/script/api/game/game_vehicle.hpp.sq @@ -123,6 +123,8 @@ void SQGSVehicle_Register(Squirrel *engine) SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsInDepot, "IsInDepot", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsStoppedInDepot, "IsStoppedInDepot", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::BuildVehicle, "BuildVehicle", 3, ".ii"); + SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::BuildVehicleWithRefit, "BuildVehicleWithRefit", 4, ".iii"); + SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetBuildWithRefitCapacity, "GetBuildWithRefitCapacity", 4, ".iii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::CloneVehicle, "CloneVehicle", 4, ".iib"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagon, "MoveWagon", 5, ".iiii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagonChain, "MoveWagonChain", 5, ".iiii"); diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 7735b9e1f3..218c96cd42 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -227,8 +227,8 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RAIL_ROAD_TYPE_DROPDOWN, "WID_RV_RAIL_ROAD_TYPE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_DROPDOWN, "WID_RV_TRAIN_ENGINEWAGON_DROPDOWN"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); @@ -385,6 +385,8 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TRAM_DESC, "WID_CI_TRAM_DESC"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TRAM_COUNT, "WID_CI_TRAM_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); @@ -466,6 +468,8 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FRW_TIMES_NAMES, "WID_FRW_TIMES_NAMES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FRW_TIMES_CURRENT, "WID_FRW_TIMES_CURRENT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FRW_TIMES_AVERAGE, "WID_FRW_TIMES_AVERAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FRW_ALLOCSIZE, "WID_FRW_ALLOCSIZE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FRW_SEL_MEMORY, "WID_FRW_SEL_MEMORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FRW_SCROLLBAR, "WID_FRW_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FGW_CAPTION, "WID_FGW_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_FGW_GRAPH, "WID_FGW_GRAPH"); @@ -636,6 +640,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_WEBSITE, "WID_A_WEBSITE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CAPTION, "WID_QS_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_TEXT, "WID_QS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_WARNING, "WID_QS_WARNING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_DEFAULT, "WID_QS_DEFAULT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CANCEL, "WID_QS_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_OK, "WID_QS_OK"); @@ -780,6 +785,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_LABEL, "WID_NCP_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_PASSWORD, "WID_NCP_PASSWORD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, "WID_NCP_SAVE_AS_DEFAULT_PASSWORD"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_WARNING, "WID_NCP_WARNING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_CANCEL, "WID_NCP_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_OK, "WID_NCP_OK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_CAPTION, "WID_NGRFI_CAPTION"); @@ -995,6 +1001,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_CAPTION, "WID_ROT_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); @@ -1006,6 +1013,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_CONVERT_ROAD, "WID_ROT_CONVERT_ROAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); @@ -1116,6 +1124,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ROADVEHS, "WID_SV_ROADVEHS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SHIPS, "WID_SV_SHIPS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_PLANES, "WID_SV_PLANES"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CATCHMENT, "WID_SV_CATCHMENT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CAPTION, "WID_STL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_LIST, "WID_STL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SCROLLBAR, "WID_STL_SCROLLBAR"); @@ -1212,6 +1221,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_BUILDING_TOOLS_START, "WID_TN_BUILDING_TOOLS_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAMS, "WID_TN_TRAMS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); @@ -1235,6 +1245,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TRAMS, "WID_TE_TRAMS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); @@ -1244,10 +1255,12 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_FILTER, "WID_TD_FILTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SCROLLBAR, "WID_TD_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_WORLD_POPULATION, "WID_TD_WORLD_POPULATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_CAPTION, "WID_TA_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_ZONE_BUTTON, "WID_TA_ZONE_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_RATING_INFO, "WID_TA_RATING_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_COMMAND_LIST, "WID_TA_COMMAND_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_SCROLLBAR, "WID_TA_SCROLLBAR"); @@ -1259,6 +1272,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CENTER_VIEW, "WID_TV_CENTER_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_SHOW_AUTHORITY, "WID_TV_SHOW_AUTHORITY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CHANGE_NAME, "WID_TV_CHANGE_NAME"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CATCHMENT, "WID_TV_CATCHMENT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_EXPAND, "WID_TV_EXPAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_DELETE, "WID_TV_DELETE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_NEW_TOWN, "WID_TF_NEW_TOWN"); diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index b74f65deb5..3befcaf97a 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -15,6 +15,19 @@ * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * + * \b 1.10.0 + * + * This version is not yet released. The following changes are not set in stone yet. + * + * API additions: + * \li GSVehicle::BuildVehicleWithRefit + * \li GSVehicle::GetBuildWithRefitCapacity + * \li GSRoad::GetName + * \li GSRoad::RoadVehCanRunOnRoad + * \li GSRoad::RoadVehHasPowerOnRoad + * \li GSRoad::ConvertRoadType + * \li GSRoad::GetMaxSpeed + * * \b 1.9.0 * * API additions: @@ -34,6 +47,9 @@ * * No changes * + * API additions: + * \li GSRoad::ERR_ROADTYPE_DISALLOWS_CROSSING + * * \b 1.7.0 - 1.7.2 * * No changes diff --git a/src/script/api/script_admin.cpp b/src/script/api/script_admin.cpp index f66d9fc8a8..7a0fe627a3 100644 --- a/src/script/api/script_admin.cpp +++ b/src/script/api/script_admin.cpp @@ -135,7 +135,6 @@ std::string json; ScriptAdmin::MakeJSON(vm, -1, SQUIRREL_MAX_DEPTH, json); -#ifdef ENABLE_NETWORK if (json.length() > NETWORK_GAMESCRIPT_JSON_LENGTH) { ScriptLog::Error("You are trying to send a table that is too large to the AdminPort. No data sent."); sq_pushinteger(vm, 0); @@ -143,7 +142,6 @@ } NetworkAdminGameScript(json.c_str()); -#endif /* ENABLE_NETWORK */ sq_pushinteger(vm, 1); return 1; diff --git a/src/script/api/script_airport.cpp b/src/script/api/script_airport.cpp index 8e19d257df..7d80f97afa 100644 --- a/src/script/api/script_airport.cpp +++ b/src/script/api/script_airport.cpp @@ -130,17 +130,20 @@ /* static */ int ScriptAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type) { - extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it); - extern uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile); + extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist); + extern uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance); if (!::IsValidTile(tile)) return -1; if (!IsAirportInformationAvailable(type)) return -1; + const AirportSpec *as = ::AirportSpec::Get(type); + if (!as->IsWithinMapBounds(0, tile)) return -1; + if (_settings_game.economy.station_noise_level) { - const AirportSpec *as = ::AirportSpec::Get(type); AirportTileTableIterator it(as->table[0], tile); - const Town *t = AirportGetNearestTown(as, it); - return GetAirportNoiseLevelForTown(as, it, t->xy); + uint dist; + AirportGetNearestTown(as, it, dist); + return GetAirportNoiseLevelForDistance(as, dist); } return 1; @@ -148,13 +151,16 @@ /* static */ TownID ScriptAirport::GetNearestTown(TileIndex tile, AirportType type) { - extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it); + extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist); if (!::IsValidTile(tile)) return INVALID_TOWN; if (!IsAirportInformationAvailable(type)) return INVALID_TOWN; const AirportSpec *as = AirportSpec::Get(type); - return AirportGetNearestTown(as, AirportTileTableIterator(as->table[0], tile))->index; + if (!as->IsWithinMapBounds(0, tile)) return INVALID_TOWN; + + uint dist; + return AirportGetNearestTown(as, AirportTileTableIterator(as->table[0], tile), dist)->index; } /* static */ uint16 ScriptAirport::GetMaintenanceCostFactor(AirportType type) diff --git a/src/script/api/script_basestation.cpp b/src/script/api/script_basestation.cpp index 229abf8657..c51fa867a5 100644 --- a/src/script/api/script_basestation.cpp +++ b/src/script/api/script_basestation.cpp @@ -22,12 +22,12 @@ /* static */ bool ScriptBaseStation::IsValidBaseStation(StationID station_id) { const BaseStation *st = ::BaseStation::GetIfValid(station_id); - return st != NULL && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE); + return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE); } /* static */ char *ScriptBaseStation::GetName(StationID station_id) { - if (!IsValidBaseStation(station_id)) return NULL; + if (!IsValidBaseStation(station_id)) return nullptr; ::SetDParam(0, station_id); return GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME); @@ -39,7 +39,7 @@ EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidBaseStation(station_id)); - EnforcePrecondition(false, name != NULL); + EnforcePrecondition(false, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_STATION_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); diff --git a/src/script/api/script_basestation.hpp b/src/script/api/script_basestation.hpp index 9676829f67..5bfd9ac84b 100644 --- a/src/script/api/script_basestation.hpp +++ b/src/script/api/script_basestation.hpp @@ -52,7 +52,7 @@ public: * @param station_id The basestation to set the name of. * @param name The new name of the station (can be either a raw string, or a ScriptText object). * @pre IsValidBaseStation(station_id). - * @pre name != NULL && len(name) != 0. + * @pre name != nullptr && len(name) != 0. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if the name was changed. diff --git a/src/script/api/script_bridge.cpp b/src/script/api/script_bridge.cpp index f532f11b73..d2d2a9c2df 100644 --- a/src/script/api/script_bridge.cpp +++ b/src/script/api/script_bridge.cpp @@ -83,7 +83,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) switch (vehicle_type) { case ScriptVehicle::VT_ROAD: type |= (TRANSPORT_ROAD << 15); - type |= (::RoadTypeToRoadTypes((::RoadType)ScriptObject::GetRoadType()) << 8); + type |= (ScriptRoad::GetCurrentRoadType() << 8); break; case ScriptVehicle::VT_RAIL: type |= (TRANSPORT_RAIL << 15); @@ -102,7 +102,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) ScriptObject::SetCallbackVariable(0, start); ScriptObject::SetCallbackVariable(1, end); - return ScriptObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE, NULL, &::_DoCommandReturnBuildBridge1); + return ScriptObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE, nullptr, &::_DoCommandReturnBuildBridge1); } /* static */ bool ScriptBridge::_BuildBridgeRoad1() @@ -114,7 +114,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); - return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &::_DoCommandReturnBuildBridge2); + return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptRoad::GetCurrentRoadType() << 4), 0, CMD_BUILD_ROAD, nullptr, &::_DoCommandReturnBuildBridge2); } /* static */ bool ScriptBridge::_BuildBridgeRoad2() @@ -126,7 +126,7 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); - return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD); + return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptRoad::GetCurrentRoadType() << 4), 0, CMD_BUILD_ROAD); } /* static */ bool ScriptBridge::RemoveBridge(TileIndex tile) @@ -138,8 +138,8 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) /* static */ char *ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type) { - EnforcePrecondition(NULL, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER); - if (!IsValidBridge(bridge_id)) return NULL; + EnforcePrecondition(nullptr, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER); + if (!IsValidBridge(bridge_id)) return nullptr; return GetString(vehicle_type == ScriptVehicle::VT_WATER ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : ::GetBridgeSpec(bridge_id)->transport_name[vehicle_type]); } diff --git a/src/script/api/script_cargo.cpp b/src/script/api/script_cargo.cpp index a2643f897f..9e83daa083 100644 --- a/src/script/api/script_cargo.cpp +++ b/src/script/api/script_cargo.cpp @@ -29,7 +29,7 @@ /* static */ char *ScriptCargo::GetCargoLabel(CargoID cargo_type) { - if (!IsValidCargo(cargo_type)) return NULL; + if (!IsValidCargo(cargo_type)) return nullptr; const CargoSpec *cargo = ::CargoSpec::Get(cargo_type); /* cargo->label is a uint32 packing a 4 character non-terminated string, diff --git a/src/script/api/script_cargo.hpp b/src/script/api/script_cargo.hpp index d1bfdd1fcc..e977031a10 100644 --- a/src/script/api/script_cargo.hpp +++ b/src/script/api/script_cargo.hpp @@ -36,7 +36,7 @@ public: CC_LIQUID = ::CC_LIQUID, ///< Liquids (Oil, Water, Rubber) CC_REFRIGERATED = ::CC_REFRIGERATED, ///< Refrigerated cargo (Food, Fruit) CC_HAZARDOUS = ::CC_HAZARDOUS, ///< Hazardous cargo (Nuclear Fuel, Explosives, etc.) - CC_COVERED = ::CC_COVERED, ///< Covered/Sheltered Freight (Transporation in Box Vans, Silo Wagons, etc.) + CC_COVERED = ::CC_COVERED, ///< Covered/Sheltered Freight (Transportation in Box Vans, Silo Wagons, etc.) }; /** diff --git a/src/script/api/script_cargomonitor.cpp b/src/script/api/script_cargomonitor.cpp index 3cb9b4a8e7..e862fed3e6 100644 --- a/src/script/api/script_cargomonitor.cpp +++ b/src/script/api/script_cargomonitor.cpp @@ -20,7 +20,7 @@ /* static */ int32 ScriptCargoMonitor::GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring) { CompanyID cid = static_cast(company); - if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; + if (cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Town::IsValidID(town_id)) return -1; @@ -31,7 +31,7 @@ /* static */ int32 ScriptCargoMonitor::GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring) { CompanyID cid = static_cast(company); - if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; + if (cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Industry::IsValidID(industry_id)) return -1; @@ -42,7 +42,7 @@ /* static */ int32 ScriptCargoMonitor::GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring) { CompanyID cid = static_cast(company); - if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; + if (cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Town::IsValidID(town_id)) return -1; @@ -53,7 +53,7 @@ /* static */ int32 ScriptCargoMonitor::GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring) { CompanyID cid = static_cast(company); - if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; + if (cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Industry::IsValidID(industry_id)) return -1; diff --git a/src/script/api/script_client.cpp b/src/script/api/script_client.cpp index 771a0ae4ec..247cac98ca 100644 --- a/src/script/api/script_client.cpp +++ b/src/script/api/script_client.cpp @@ -16,59 +16,41 @@ #include "../../safeguards.h" -#ifdef ENABLE_NETWORK /** * Finds NetworkClientInfo given client-identifier, * is used by other methods to resolve client-identifier. * @param client The client to get info structure for - * @return A pointer to corresponding CI struct or NULL when not found. + * @return A pointer to corresponding CI struct or nullptr when not found. */ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client) { - if (client == ScriptClient::CLIENT_INVALID) return NULL; - if (!_networking) return NULL; + if (client == ScriptClient::CLIENT_INVALID) return nullptr; + if (!_networking) return nullptr; return NetworkClientInfo::GetByClientID((::ClientID)client); } -#endif /* static */ ScriptClient::ClientID ScriptClient::ResolveClientID(ScriptClient::ClientID client) { -#ifdef ENABLE_NETWORK - return (FindClientInfo(client) == NULL ? ScriptClient::CLIENT_INVALID : client); -#else - return CLIENT_INVALID; -#endif + return (FindClientInfo(client) == nullptr ? ScriptClient::CLIENT_INVALID : client); } /* static */ char *ScriptClient::GetName(ScriptClient::ClientID client) { -#ifdef ENABLE_NETWORK NetworkClientInfo *ci = FindClientInfo(client); - if (ci == NULL) return NULL; + if (ci == nullptr) return nullptr; return stredup(ci->client_name); -#else - return NULL; -#endif } /* static */ ScriptCompany::CompanyID ScriptClient::GetCompany(ScriptClient::ClientID client) { -#ifdef ENABLE_NETWORK NetworkClientInfo *ci = FindClientInfo(client); - if (ci == NULL) return ScriptCompany::COMPANY_INVALID; + if (ci == nullptr) return ScriptCompany::COMPANY_INVALID; return (ScriptCompany::CompanyID)ci->client_playas; -#else - return ScriptCompany::COMPANY_INVALID; -#endif } /* static */ ScriptDate::Date ScriptClient::GetJoinDate(ScriptClient::ClientID client) { -#ifdef ENABLE_NETWORK NetworkClientInfo *ci = FindClientInfo(client); - if (ci == NULL) return ScriptDate::DATE_INVALID; + if (ci == nullptr) return ScriptDate::DATE_INVALID; return (ScriptDate::Date)ci->join_date; -#else - return ScriptDate::DATE_INVALID; -#endif } diff --git a/src/script/api/script_client.hpp b/src/script/api/script_client.hpp index 423f134c07..20cbdc7fee 100644 --- a/src/script/api/script_client.hpp +++ b/src/script/api/script_client.hpp @@ -26,7 +26,7 @@ class ScriptClient : public ScriptObject { public: /** Different constants related to ClientID. */ - enum ClientID { + enum ClientID : uint32 { CLIENT_INVALID = 0, ///< Client is not part of anything CLIENT_SERVER = 1, ///< Servers always have this ID CLIENT_FIRST = 2, ///< The first client ID diff --git a/src/script/api/script_clientlist.cpp b/src/script/api/script_clientlist.cpp index 2f7a19a9ff..dbbbce0ec4 100644 --- a/src/script/api/script_clientlist.cpp +++ b/src/script/api/script_clientlist.cpp @@ -19,18 +19,15 @@ ScriptClientList::ScriptClientList() { -#ifdef ENABLE_NETWORK if (!_networking) return; NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { this->AddItem(ci->client_id); } -#endif } ScriptClientList_Company::ScriptClientList_Company(ScriptCompany::CompanyID company) { -#ifdef ENABLE_NETWORK if (!_networking) return; CompanyID c; if (company == ScriptCompany::COMPANY_SPECTATOR) { @@ -45,5 +42,4 @@ ScriptClientList_Company::ScriptClientList_Company(ScriptCompany::CompanyID comp FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_playas == c) this->AddItem(ci->client_id); } -#endif } diff --git a/src/script/api/script_company.cpp b/src/script/api/script_company.cpp index 54888c33cb..59f4fa43e3 100644 --- a/src/script/api/script_company.cpp +++ b/src/script/api/script_company.cpp @@ -45,7 +45,7 @@ { CCountedPtr counter(name); - EnforcePrecondition(false, name != NULL); + EnforcePrecondition(false, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_COMPANY_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); @@ -56,7 +56,7 @@ /* static */ char *ScriptCompany::GetName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); - if (company == COMPANY_INVALID) return NULL; + if (company == COMPANY_INVALID) return nullptr; ::SetDParam(0, company); return GetString(STR_COMPANY_NAME); @@ -66,7 +66,7 @@ { CCountedPtr counter(name); - EnforcePrecondition(false, name != NULL); + EnforcePrecondition(false, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_PRESIDENT_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); @@ -312,7 +312,7 @@ if ((::LiveryScheme)scheme < LS_BEGIN || (::LiveryScheme)scheme >= LS_END) return COLOUR_INVALID; const Company *c = ::Company::GetIfValid(_current_company); - if (c == NULL) return COLOUR_INVALID; + if (c == nullptr) return COLOUR_INVALID; return (ScriptCompany::Colours)c->livery[scheme].colour1; } @@ -322,7 +322,7 @@ if ((::LiveryScheme)scheme < LS_BEGIN || (::LiveryScheme)scheme >= LS_END) return COLOUR_INVALID; const Company *c = ::Company::GetIfValid(_current_company); - if (c == NULL) return COLOUR_INVALID; + if (c == nullptr) return COLOUR_INVALID; return (ScriptCompany::Colours)c->livery[scheme].colour2; } diff --git a/src/script/api/script_company.hpp b/src/script/api/script_company.hpp index 55cb7a9300..e3be24e557 100644 --- a/src/script/api/script_company.hpp +++ b/src/script/api/script_company.hpp @@ -139,7 +139,7 @@ public: /** * Set the name of your company. * @param name The new name of the company (can be either a raw string, or a ScriptText object). - * @pre name != NULL && len(name) != 0. + * @pre name != nullptr && len(name) != 0. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if the name was changed. */ @@ -156,7 +156,7 @@ public: /** * Set the name of your president. * @param name The new name of the president (can be either a raw string, or a ScriptText object). - * @pre name != NULL && len(name) != 0. + * @pre name != nullptr && len(name) != 0. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if the name was changed. */ diff --git a/src/script/api/script_controller.cpp b/src/script/api/script_controller.cpp index a42c8ede9b..beb9b155fb 100644 --- a/src/script/api/script_controller.cpp +++ b/src/script/api/script_controller.cpp @@ -43,7 +43,7 @@ ticks = 1; } - throw Script_Suspend(ticks, NULL); + throw Script_Suspend(ticks, nullptr); } /* static */ void ScriptController::Break(const char* message) @@ -119,7 +119,7 @@ ScriptController::~ScriptController() strtolower(library_name); ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version); - if (lib == NULL) { + if (lib == nullptr) { char error[1024]; seprintf(error, lastof(error), "couldn't find library '%s' with version %d", library, version); throw sq_throwerror(vm, error); diff --git a/src/script/api/script_engine.cpp b/src/script/api/script_engine.cpp index 1fe16321b5..88f55226ea 100644 --- a/src/script/api/script_engine.cpp +++ b/src/script/api/script_engine.cpp @@ -15,6 +15,7 @@ #include "../../company_base.h" #include "../../strings_func.h" #include "../../rail.h" +#include "../../road.h" #include "../../engine_base.h" #include "../../engine_func.h" #include "../../articulated_vehicles.h" @@ -25,7 +26,7 @@ /* static */ bool ScriptEngine::IsValidEngine(EngineID engine_id) { const Engine *e = ::Engine::GetIfValid(engine_id); - if (e == NULL || !e->IsEnabled()) return false; + if (e == nullptr || !e->IsEnabled()) return false; /* AIs have only access to engines they can purchase or still have in use. * Deity has access to all engined that will be or were available ever. */ @@ -36,12 +37,12 @@ /* static */ bool ScriptEngine::IsBuildable(EngineID engine_id) { const Engine *e = ::Engine::GetIfValid(engine_id); - return e != NULL && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany()); + return e != nullptr && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany()); } /* static */ char *ScriptEngine::GetName(EngineID engine_id) { - if (!IsValidEngine(engine_id)) return NULL; + if (!IsValidEngine(engine_id)) return nullptr; ::SetDParam(0, engine_id); return GetString(STR_ENGINE_NAME); @@ -219,12 +220,26 @@ return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type); } +/* static */ bool ScriptEngine::CanRunOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type) +{ + return HasPowerOnRoad(engine_id, road_type); +} + +/* static */ bool ScriptEngine::HasPowerOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type) +{ + if (!IsValidEngine(engine_id)) return false; + if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return false; + if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return false; + + return ::HasPowerOnRoad((::RoadType)::RoadVehInfo(engine_id)->roadtype, (::RoadType)road_type); +} + /* static */ ScriptRoad::RoadType ScriptEngine::GetRoadType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptRoad::ROADTYPE_INVALID; if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return ScriptRoad::ROADTYPE_INVALID; - return HasBit(::EngInfo(engine_id)->misc_flags, EF_ROAD_TRAM) ? ScriptRoad::ROADTYPE_TRAM : ScriptRoad::ROADTYPE_ROAD; + return (ScriptRoad::RoadType)(uint)::RoadVehInfo(engine_id)->roadtype; } /* static */ ScriptRail::RailType ScriptEngine::GetRailType(EngineID engine_id) @@ -256,9 +271,6 @@ if (!IsValidEngine(engine_id)) return 0; switch (GetVehicleType(engine_id)) { - case ScriptVehicle::VT_WATER: - return _settings_game.pf.pathfinder_for_ships != VPF_NPF ? 129 : 0; - case ScriptVehicle::VT_AIR: return ::Engine::Get(engine_id)->GetRange() * ::Engine::Get(engine_id)->GetRange(); diff --git a/src/script/api/script_engine.hpp b/src/script/api/script_engine.hpp index 173377742d..b08b6f64b4 100644 --- a/src/script/api/script_engine.hpp +++ b/src/script/api/script_engine.hpp @@ -217,6 +217,28 @@ public: */ static bool HasPowerOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type); + /** + * Check if a road vehicle can run on a RoadType. + * @param engine_id The engine to check. + * @param road_type Another RoadType. + * @pre IsValidEngine(engine_id). + * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD. + * @pre ScriptRoad::IsRoadTypeAvailable(road_type). + * @return Whether an engine of type 'engine_id' can run on 'road_type'. + */ + static bool CanRunOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type); + + /** + * Check if a road vehicle has power on a RoadType. + * @param engine_id The engine to check. + * @param road_type Another RoadType. + * @pre IsValidEngine(engine_id). + * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD. + * @pre ScriptRoad::IsRoadTypeAvailable(road_type). + * @return Whether an engine of type 'engine_id' has power on 'road_type'. + */ + static bool HasPowerOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type); + /** * Get the RoadType of the engine. * @param engine_id The engine to get the RoadType of. diff --git a/src/script/api/script_error.hpp b/src/script/api/script_error.hpp index 1817cdb7d9..346298d2c4 100644 --- a/src/script/api/script_error.hpp +++ b/src/script/api/script_error.hpp @@ -44,7 +44,7 @@ * @param string The string that is checked. */ #define EnforcePreconditionEncodedText(returnval, string) \ - if ((string) == NULL) { \ + if ((string) == nullptr) { \ ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS); \ return returnval; \ } \ diff --git a/src/script/api/script_event.cpp b/src/script/api/script_event.cpp index 0e711ca416..2d364e8d2e 100644 --- a/src/script/api/script_event.cpp +++ b/src/script/api/script_event.cpp @@ -23,7 +23,7 @@ struct ScriptEventData { /* static */ void ScriptEventController::CreateEventPointer() { - assert(ScriptObject::GetEventPointer() == NULL); + assert(ScriptObject::GetEventPointer() == nullptr); ScriptObject::GetEventPointer() = new ScriptEventData(); } @@ -45,7 +45,7 @@ struct ScriptEventData { /* static */ bool ScriptEventController::IsEventWaiting() { - if (ScriptObject::GetEventPointer() == NULL) ScriptEventController::CreateEventPointer(); + if (ScriptObject::GetEventPointer() == nullptr) ScriptEventController::CreateEventPointer(); ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); return !data->stack.empty(); @@ -53,10 +53,10 @@ struct ScriptEventData { /* static */ ScriptEvent *ScriptEventController::GetNextEvent() { - if (ScriptObject::GetEventPointer() == NULL) ScriptEventController::CreateEventPointer(); + if (ScriptObject::GetEventPointer() == nullptr) ScriptEventController::CreateEventPointer(); ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); - if (data->stack.empty()) return NULL; + if (data->stack.empty()) return nullptr; ScriptEvent *e = data->stack.front(); data->stack.pop(); @@ -65,7 +65,7 @@ struct ScriptEventData { /* static */ void ScriptEventController::InsertEvent(ScriptEvent *event) { - if (ScriptObject::GetEventPointer() == NULL) ScriptEventController::CreateEventPointer(); + if (ScriptObject::GetEventPointer() == nullptr) ScriptEventController::CreateEventPointer(); ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); event->AddRef(); diff --git a/src/script/api/script_event.hpp b/src/script/api/script_event.hpp index b2dddebd67..a9e17df7e0 100644 --- a/src/script/api/script_event.hpp +++ b/src/script/api/script_event.hpp @@ -55,6 +55,7 @@ public: ET_GOAL_QUESTION_ANSWER, ET_EXCLUSIVE_TRANSPORT_RIGHTS, ET_ROAD_RECONSTRUCTION, + ET_VEHICLE_AUTOREPLACED, }; /** diff --git a/src/script/api/script_event_types.cpp b/src/script/api/script_event_types.cpp index d424e6feff..e997f23201 100644 --- a/src/script/api/script_event_types.cpp +++ b/src/script/api/script_event_types.cpp @@ -25,12 +25,12 @@ bool ScriptEventEnginePreview::IsEngineValid() const { const Engine *e = ::Engine::GetIfValid(this->engine); - return e != NULL && e->IsEnabled(); + return e != nullptr && e->IsEnabled(); } char *ScriptEventEnginePreview::GetName() { - if (!this->IsEngineValid()) return NULL; + if (!this->IsEngineValid()) return nullptr; ::SetDParam(0, this->engine); return GetString(STR_ENGINE_NAME); @@ -132,13 +132,13 @@ ScriptEventAdminPort::~ScriptEventAdminPort() } #define SKIP_EMPTY(p) while (*(p) == ' ' || *(p) == '\n' || *(p) == '\r') (p)++; -#define RETURN_ERROR(stack) { ScriptLog::Error("Received invalid JSON data from AdminPort."); if (stack != 0) sq_pop(vm, stack); return NULL; } +#define RETURN_ERROR(stack) { ScriptLog::Error("Received invalid JSON data from AdminPort."); if (stack != 0) sq_pop(vm, stack); return nullptr; } SQInteger ScriptEventAdminPort::GetObject(HSQUIRRELVM vm) { char *p = this->json; - if (this->ReadTable(vm, p) == NULL) { + if (this->ReadTable(vm, p) == nullptr) { sq_pushnull(vm); return 1; } @@ -189,18 +189,18 @@ char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, char *p) if (*p++ != '"') RETURN_ERROR(1); p = ReadString(vm, p); - if (p == NULL) { + if (p == nullptr) { sq_pop(vm, 1); - return NULL; + return nullptr; } SKIP_EMPTY(p); if (*p++ != ':') RETURN_ERROR(2); p = this->ReadValue(vm, p); - if (p == NULL) { + if (p == nullptr) { sq_pop(vm, 2); - return NULL; + return nullptr; } sq_rawset(vm, -3); @@ -241,7 +241,7 @@ char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p) case '"': { /* String */ p = ReadString(vm, ++p); - if (p == NULL) return NULL; + if (p == nullptr) return nullptr; break; } @@ -249,7 +249,7 @@ char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p) case '{': { /* Table */ p = this->ReadTable(vm, p); - if (p == NULL) return NULL; + if (p == nullptr) return nullptr; break; } @@ -268,9 +268,9 @@ char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p) while (*p++ != ']') { p = this->ReadValue(vm, p); - if (p == NULL) { + if (p == nullptr) { sq_pop(vm, 1); - return NULL; + return nullptr; } sq_arrayappend(vm, -2); diff --git a/src/script/api/script_event_types.hpp b/src/script/api/script_event_types.hpp index f13e588eed..aeb5ebe2d2 100644 --- a/src/script/api/script_event_types.hpp +++ b/src/script/api/script_event_types.hpp @@ -799,8 +799,8 @@ private: /** * Event AircraftDestTooFar, indicating the next destination of an aircraft is too far away. - * This event can be trigger when the current oder of an aircraft changes, usually either when - * loading is done or when switch manually. + * This event can be triggered when the current order of an aircraft changes, usually either when + * loading is done or when switched manually. * @api ai */ class ScriptEventAircraftDestTooFar : public ScriptEvent { @@ -1060,4 +1060,44 @@ public: static ScriptEventRoadReconstruction *Convert(ScriptEventCompanyTown *instance) { return (ScriptEventRoadReconstruction *)instance; } }; +/** + * Event VehicleAutoReplaced, indicating a vehicle has been auto replaced. + * @api ai + */ +class ScriptEventVehicleAutoReplaced : public ScriptEvent { +public: + /** + * @param old_id The vehicle that has been replaced. + * @param new_id The vehicle that has been created in replacement. + */ + ScriptEventVehicleAutoReplaced(VehicleID old_id, VehicleID new_id) : + ScriptEvent(ET_VEHICLE_AUTOREPLACED), + old_id(old_id), + new_id(new_id) + {} + + /** + * Convert an ScriptEvent to the real instance. + * @param instance The instance to convert. + * @return The converted instance. + */ + static ScriptEventVehicleAutoReplaced *Convert(ScriptEvent *instance) { return (ScriptEventVehicleAutoReplaced *)instance; } + + /** + * Get the VehicleID of the vehicle that has been replaced. + * @return The VehicleID of the vehicle that has been replaced. This ID is no longer valid for referencing the vehicle. + */ + VehicleID GetOldVehicleID() { return this->old_id; } + + /** + * Get the VehicleID of the vehicle that has been created in replacement. + * @return The VehicleID of the vehicle that has been created in replacement. + */ + VehicleID GetNewVehicleID() { return this->new_id; } + +private: + VehicleID old_id; ///< The vehicle that has been replaced. + VehicleID new_id; ///< The vehicle that has been created in replacement. +}; + #endif /* SCRIPT_EVENT_TYPES_HPP */ diff --git a/src/script/api/script_game.cpp b/src/script/api/script_game.cpp index c24757a3cc..3e26174885 100644 --- a/src/script/api/script_game.cpp +++ b/src/script/api/script_game.cpp @@ -39,9 +39,5 @@ /* static */ bool ScriptGame::IsMultiplayer() { -#ifdef ENABLE_NETWORK return _network_server; -#else - return false; -#endif } diff --git a/src/script/api/script_gamesettings.cpp b/src/script/api/script_gamesettings.cpp index 1f8ded877e..490e6eee0c 100644 --- a/src/script/api/script_gamesettings.cpp +++ b/src/script/api/script_gamesettings.cpp @@ -21,7 +21,7 @@ { uint i; const SettingDesc *sd = GetSettingFromName(setting, &i); - return sd != NULL && sd->desc.cmd != SDT_STRING; + return sd != nullptr && sd->desc.cmd != SDT_STRING; } /* static */ int32 ScriptGameSettings::GetValue(const char *setting) diff --git a/src/script/api/script_goal.cpp b/src/script/api/script_goal.cpp index 517bddfd8d..4c0f5eb353 100644 --- a/src/script/api/script_goal.cpp +++ b/src/script/api/script_goal.cpp @@ -34,14 +34,14 @@ CCountedPtr counter(goal); EnforcePrecondition(GOAL_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); - EnforcePrecondition(GOAL_INVALID, goal != NULL); + EnforcePrecondition(GOAL_INVALID, goal != nullptr); const char *text = goal->GetEncodedText(); EnforcePreconditionEncodedText(GOAL_INVALID, text); EnforcePrecondition(GOAL_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; - StoryPage *story_page = NULL; + StoryPage *story_page = nullptr; if (type == GT_STORY_PAGE && ScriptStoryPage::IsValidStoryPage((ScriptStoryPage::StoryPageID)destination)) story_page = ::StoryPage::Get((ScriptStoryPage::StoryPageID)destination); EnforcePrecondition(GOAL_INVALID, (type == GT_NONE && destination == 0) || @@ -49,7 +49,7 @@ (type == GT_INDUSTRY && ScriptIndustry::IsValidIndustry(destination)) || (type == GT_TOWN && ScriptTown::IsValidTown(destination)) || (type == GT_COMPANY && ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID)destination) != ScriptCompany::COMPANY_INVALID) || - (type == GT_STORY_PAGE && story_page != NULL && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c))); + (type == GT_STORY_PAGE && story_page != nullptr && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c))); if (!ScriptObject::DoCommand(0, type | (c << 8), destination, CMD_CREATE_GOAL, text, &ScriptInstance::DoCommandReturnGoalID)) return GOAL_INVALID; @@ -71,7 +71,7 @@ EnforcePrecondition(false, IsValidGoal(goal_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); - EnforcePrecondition(false, goal != NULL); + EnforcePrecondition(false, goal != nullptr); EnforcePrecondition(false, !StrEmpty(goal->GetEncodedText())); return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_TEXT, goal->GetEncodedText()); @@ -84,12 +84,12 @@ EnforcePrecondition(false, IsValidGoal(goal_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); - /* Ensure null as used for emtpy string. */ - if (progress != NULL && StrEmpty(progress->GetEncodedText())) { - progress = NULL; + /* Ensure null as used for empty string. */ + if (progress != nullptr && StrEmpty(progress->GetEncodedText())) { + progress = nullptr; } - return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_PROGRESS, progress != NULL ? progress->GetEncodedText() : NULL); + return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_PROGRESS, progress != nullptr ? progress->GetEncodedText() : nullptr); } /* static */ bool ScriptGoal::SetCompleted(GoalID goal_id, bool completed) @@ -106,7 +106,7 @@ EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); Goal *g = Goal::Get(goal_id); - return g != NULL && g->completed; + return g != nullptr && g->completed; } /* static */ bool ScriptGoal::DoQuestion(uint16 uniqueid, uint32 target, bool is_client, Text *question, QuestionType type, uint32 buttons) @@ -114,7 +114,7 @@ CCountedPtr counter(question); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); - EnforcePrecondition(false, question != NULL); + EnforcePrecondition(false, question != nullptr); const char *text = question->GetEncodedText(); EnforcePreconditionEncodedText(false, text); EnforcePrecondition(false, CountBits(buttons) >= 1 && CountBits(buttons) <= 3); @@ -137,13 +137,9 @@ { EnforcePrecondition(false, ScriptGame::IsMultiplayer()); EnforcePrecondition(false, ScriptClient::ResolveClientID(client) != ScriptClient::CLIENT_INVALID); -#ifdef ENABLE_NETWORK /* Can only send 16 bits of client_id before proper fix is implemented */ EnforcePrecondition(false, client < (1 << 16)); return DoQuestion(uniqueid, client, true, question, type, buttons); -#else - return false; -#endif } /* static */ bool ScriptGoal::CloseQuestion(uint16 uniqueid) diff --git a/src/script/api/script_goal.hpp b/src/script/api/script_goal.hpp index 9ad01c2b52..30f7df1257 100644 --- a/src/script/api/script_goal.hpp +++ b/src/script/api/script_goal.hpp @@ -99,7 +99,7 @@ public: * @param destination The destination of the \a type type. * @return The new GoalID, or GOAL_INVALID if it failed. * @pre No ScriptCompanyMode may be in scope. - * @pre goal != NULL && len(goal) != 0. + * @pre goal != nullptr && len(goal) != 0. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. * @pre if type is GT_STORY_PAGE, the company of the goal and the company of the story page need to match: * \li Global goals can only reference global story pages. @@ -122,7 +122,7 @@ public: * @param goal The new goal text (can be either a raw string, or a ScriptText object). * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. - * @pre goal != NULL && len(goal) != 0. + * @pre goal != nullptr && len(goal) != 0. * @pre IsValidGoal(goal_id). */ static bool SetText(GoalID goal_id, Text *goal); @@ -133,7 +133,7 @@ public: * the progress string short. * @param goal_id The goal to update. * @param progress The new progress text for the goal (can be either a raw string, - * or a ScriptText object). To clear the progress string you can pass NULL or an + * or a ScriptText object). To clear the progress string you can pass nullptr or an * empty string. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. @@ -169,7 +169,7 @@ public: * @param buttons Any combinations (at least 1, up to 3) of buttons defined in QuestionButton. Like BUTTON_YES + BUTTON_NO. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. - * @pre question != NULL && len(question) != 0. + * @pre question != nullptr && len(question) != 0. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. * @pre CountBits(buttons) >= 1 && CountBits(buttons) <= 3. * @note Replies to the question are given by you via the event ScriptEvent_GoalQuestionAnswer. @@ -187,7 +187,7 @@ public: * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre ScriptGame::IsMultiplayer() - * @pre question != NULL && len(question) != 0. + * @pre question != nullptr && len(question) != 0. * @pre ResolveClientID(client) != CLIENT_INVALID. * @pre CountBits(buttons) >= 1 && CountBits(buttons) <= 3. * @note Replies to the question are given by you via the event ScriptEvent_GoalQuestionAnswer. diff --git a/src/script/api/script_group.cpp b/src/script/api/script_group.cpp index 16a50bc17c..55f5ffdebb 100644 --- a/src/script/api/script_group.cpp +++ b/src/script/api/script_group.cpp @@ -25,12 +25,12 @@ /* static */ bool ScriptGroup::IsValidGroup(GroupID group_id) { const Group *g = ::Group::GetIfValid(group_id); - return g != NULL && g->owner == ScriptObject::GetCompany(); + return g != nullptr && g->owner == ScriptObject::GetCompany(); } /* static */ ScriptGroup::GroupID ScriptGroup::CreateGroup(ScriptVehicle::VehicleType vehicle_type, GroupID parent_group_id) { - if (!ScriptObject::DoCommand(0, (::VehicleType)vehicle_type, parent_group_id, CMD_CREATE_GROUP, NULL, &ScriptInstance::DoCommandReturnGroupID)) return GROUP_INVALID; + if (!ScriptObject::DoCommand(0, (::VehicleType)vehicle_type, parent_group_id, CMD_CREATE_GROUP, nullptr, &ScriptInstance::DoCommandReturnGroupID)) return GROUP_INVALID; /* In case of test-mode, we return GroupID 0 */ return (ScriptGroup::GroupID)0; @@ -55,7 +55,7 @@ CCountedPtr counter(name); EnforcePrecondition(false, IsValidGroup(group_id)); - EnforcePrecondition(false, name != NULL); + EnforcePrecondition(false, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_GROUP_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); @@ -65,7 +65,7 @@ /* static */ char *ScriptGroup::GetName(GroupID group_id) { - if (!IsValidGroup(group_id)) return NULL; + if (!IsValidGroup(group_id)) return nullptr; ::SetDParam(0, group_id); return GetString(STR_GROUP_NAME); @@ -194,3 +194,35 @@ return occupancy / vehicle_count; } + +/* static */ bool ScriptGroup::SetPrimaryColour(GroupID group_id, ScriptCompany::Colours colour) +{ + EnforcePrecondition(false, IsValidGroup(group_id)); + + return ScriptObject::DoCommand(0, group_id, colour << 16, CMD_SET_GROUP_LIVERY); +} + +/* static */ bool ScriptGroup::SetSecondaryColour(GroupID group_id, ScriptCompany::Colours colour) +{ + EnforcePrecondition(false, IsValidGroup(group_id)); + + return ScriptObject::DoCommand(0, group_id, (1 << 8) | (colour << 16), CMD_SET_GROUP_LIVERY); +} + +/* static */ ScriptCompany::Colours ScriptGroup::GetPrimaryColour(GroupID group_id) +{ + EnforcePrecondition(ScriptCompany::Colours::COLOUR_INVALID, IsValidGroup(group_id)); + + const Group *g = ::Group::GetIfValid(group_id); + if (!HasBit(g->livery.in_use, 0)) return ScriptCompany::Colours::COLOUR_INVALID; + return (ScriptCompany::Colours)g->livery.colour1; +} + +/* static */ ScriptCompany::Colours ScriptGroup::GetSecondaryColour(GroupID group_id) +{ + EnforcePrecondition(ScriptCompany::Colours::COLOUR_INVALID, IsValidGroup(group_id)); + + const Group *g = ::Group::GetIfValid(group_id); + if (!HasBit(g->livery.in_use, 1)) return ScriptCompany::Colours::COLOUR_INVALID; + return (ScriptCompany::Colours)g->livery.colour2; +} diff --git a/src/script/api/script_group.hpp b/src/script/api/script_group.hpp index 9e88eaff1c..f44163bbac 100644 --- a/src/script/api/script_group.hpp +++ b/src/script/api/script_group.hpp @@ -71,7 +71,7 @@ public: * @param group_id The group to set the name for. * @param name The name for the group (can be either a raw string, or a ScriptText object). * @pre IsValidGroup(group_id). - * @pre name != NULL && len(name) != 0 + * @pre name != nullptr && len(name) != 0 * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if and only if the name was changed. */ @@ -214,6 +214,36 @@ public: * @return The current usage of the group. */ static uint32 GetCurrentUsage(GroupID group_id); + + /** + * Set primary colour for a group. + * @param group_id The group id to set the colour of. + * @param colour Colour to set. + * @pre IsValidGroup(group_id). + */ + static bool SetPrimaryColour(GroupID group_id, ScriptCompany::Colours colour); + + /** + * Set secondary colour for a group. + * @param group_id The group id to set the colour of. + * @param colour Colour to set. + * @pre IsValidGroup(group_id). + */ + static bool SetSecondaryColour(GroupID group_id, ScriptCompany::Colours colour); + + /** + * Get primary colour of a group. + * @param group_id The group id to get the colour of. + * @pre IsValidGroup(group_id). + */ + static ScriptCompany::Colours GetPrimaryColour(GroupID group_id); + + /** + * Get secondary colour for a group. + * @param group_id The group id to get the colour of. + * @pre IsValidGroup(group_id). + */ + static ScriptCompany::Colours GetSecondaryColour(GroupID group_id); }; #endif /* SCRIPT_GROUP_HPP */ diff --git a/src/script/api/script_industry.cpp b/src/script/api/script_industry.cpp index c536ec5590..e72f9955b5 100644 --- a/src/script/api/script_industry.cpp +++ b/src/script/api/script_industry.cpp @@ -39,7 +39,7 @@ /* static */ char *ScriptIndustry::GetName(IndustryID industry_id) { - if (!IsValidIndustry(industry_id)) return NULL; + if (!IsValidIndustry(industry_id)) return nullptr; ::SetDParam(0, industry_id); return GetString(STR_INDUSTRY_NAME); @@ -132,9 +132,7 @@ if (!IsValidIndustry(industry_id)) return -1; Industry *ind = ::Industry::Get(industry_id); - StationList stations; - ::FindStationsAroundTiles(ind->location, &stations); - return (int32)stations.Length(); + return (int32)ind->stations_near.size(); } /* static */ int32 ScriptIndustry::GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile) diff --git a/src/script/api/script_industrytype.cpp b/src/script/api/script_industrytype.cpp index 1ac59975dc..76b5cab2aa 100644 --- a/src/script/api/script_industrytype.cpp +++ b/src/script/api/script_industrytype.cpp @@ -59,14 +59,14 @@ /* static */ char *ScriptIndustryType::GetName(IndustryType industry_type) { - if (!IsValidIndustryType(industry_type)) return NULL; + if (!IsValidIndustryType(industry_type)) return nullptr; return GetString(::GetIndustrySpec(industry_type)->name); } /* static */ ScriptList *ScriptIndustryType::GetProducedCargo(IndustryType industry_type) { - if (!IsValidIndustryType(industry_type)) return NULL; + if (!IsValidIndustryType(industry_type)) return nullptr; const IndustrySpec *ins = ::GetIndustrySpec(industry_type); @@ -80,7 +80,7 @@ /* static */ ScriptList *ScriptIndustryType::GetAcceptedCargo(IndustryType industry_type) { - if (!IsValidIndustryType(industry_type)) return NULL; + if (!IsValidIndustryType(industry_type)) return nullptr; const IndustrySpec *ins = ::GetIndustrySpec(industry_type); @@ -123,7 +123,8 @@ EnforcePrecondition(false, ScriptMap::IsValidTile(tile)); uint32 seed = ::InteractiveRandom(); - return ScriptObject::DoCommand(tile, (1 << 16) | (::InteractiveRandomRange(::GetIndustrySpec(industry_type)->num_table) << 8) | industry_type, seed, CMD_BUILD_INDUSTRY); + uint32 layout_index = ::InteractiveRandomRange((uint32)::GetIndustrySpec(industry_type)->layouts.size()); + return ScriptObject::DoCommand(tile, (1 << 16) | (layout_index << 8) | industry_type, seed, CMD_BUILD_INDUSTRY); } /* static */ bool ScriptIndustryType::ProspectIndustry(IndustryType industry_type) diff --git a/src/script/api/script_infrastructure.cpp b/src/script/api/script_infrastructure.cpp index d7da2747e1..35febbd58a 100644 --- a/src/script/api/script_infrastructure.cpp +++ b/src/script/api/script_infrastructure.cpp @@ -90,7 +90,8 @@ company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || (::RoadType)roadtype >= ROADTYPE_END || !_settings_game.economy.infrastructure_maintenance) return 0; - return ::RoadMaintenanceCost((::RoadType)roadtype, ::Company::Get((::CompanyID)company)->infrastructure.road[roadtype]); + const ::Company *c = ::Company::Get((::CompanyID)company); + return ::RoadMaintenanceCost((::RoadType)roadtype, c->infrastructure.road[roadtype], RoadTypeIsRoad((::RoadType)roadtype) ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal()); } /* static */ Money ScriptInfrastructure::GetMonthlyInfrastructureCosts(ScriptCompany::CompanyID company, Infrastructure infra_type) @@ -114,8 +115,9 @@ case INFRASTRUCTURE_ROAD: { Money cost; + uint32 road_total = c->infrastructure.GetRoadTotal(); for (::RoadType rt = ::ROADTYPE_BEGIN; rt != ::ROADTYPE_END; rt++) { - cost += RoadMaintenanceCost(rt, c->infrastructure.road[rt]); + cost += RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total); } return cost; } diff --git a/src/script/api/script_list.cpp b/src/script/api/script_list.cpp index d0c72b5bb1..fe747028f8 100644 --- a/src/script/api/script_list.cpp +++ b/src/script/api/script_list.cpp @@ -109,7 +109,7 @@ public: void End() { - this->bucket_list = NULL; + this->bucket_list = nullptr; this->has_no_more_items = true; this->item_next = 0; } @@ -119,7 +119,7 @@ public: */ void FindNext() { - if (this->bucket_list == NULL) { + if (this->bucket_list == nullptr) { this->has_no_more_items = true; return; } @@ -128,7 +128,7 @@ public: if (this->bucket_list_iter == this->bucket_list->end()) { this->bucket_iter++; if (this->bucket_iter == this->list->buckets.end()) { - this->bucket_list = NULL; + this->bucket_list = nullptr; return; } this->bucket_list = &(*this->bucket_iter).second; @@ -203,7 +203,7 @@ public: void End() { - this->bucket_list = NULL; + this->bucket_list = nullptr; this->has_no_more_items = true; this->item_next = 0; } @@ -213,14 +213,14 @@ public: */ void FindNext() { - if (this->bucket_list == NULL) { + if (this->bucket_list == nullptr) { this->has_no_more_items = true; return; } if (this->bucket_list_iter == this->bucket_list->begin()) { if (this->bucket_iter == this->list->buckets.begin()) { - this->bucket_list = NULL; + this->bucket_list = nullptr; return; } this->bucket_iter--; @@ -845,7 +845,7 @@ SQInteger ScriptList::Valuate(HSQUIRRELVM vm) int nparam = sq_gettop(vm) - 1; if (nparam < 1) { - return sq_throwerror(vm, "You need to give a least a Valuator as parameter to ScriptList::Valuate"); + return sq_throwerror(vm, "You need to give at least a Valuator as parameter to ScriptList::Valuate"); } /* Make sure the valuator function is really a function, and not any diff --git a/src/script/api/script_list.hpp b/src/script/api/script_list.hpp index 1fbafe3d9f..b32ebc463e 100644 --- a/src/script/api/script_list.hpp +++ b/src/script/api/script_list.hpp @@ -198,7 +198,7 @@ public: /** * Remove everything that is in the given list from this list (same item index that is). * @param list the list of items to remove. - * @pre list != NULL + * @pre list != nullptr */ void RemoveList(ScriptList *list); @@ -242,7 +242,7 @@ public: /** * Keeps everything that is in the given list from this list (same item index that is). * @param list the list of items to keep. - * @pre list != NULL + * @pre list != nullptr */ void KeepList(ScriptList *list); diff --git a/src/script/api/script_log.cpp b/src/script/api/script_log.cpp index d9fbbde982..b40ed97aac 100644 --- a/src/script/api/script_log.cpp +++ b/src/script/api/script_log.cpp @@ -35,7 +35,7 @@ /* static */ void ScriptLog::Log(ScriptLog::ScriptLogType level, const char *message) { - if (ScriptObject::GetLogPointer() == NULL) { + if (ScriptObject::GetLogPointer() == nullptr) { ScriptObject::GetLogPointer() = new LogData(); LogData *log = (LogData *)ScriptObject::GetLogPointer(); @@ -59,7 +59,7 @@ /* Cut string after first \n */ char *p; - while ((p = strchr(log->lines[log->pos], '\n')) != NULL) { + while ((p = strchr(log->lines[log->pos], '\n')) != nullptr) { *p = '\0'; break; } diff --git a/src/script/api/script_marine.cpp b/src/script/api/script_marine.cpp index 434ec11acc..bba361cec2 100644 --- a/src/script/api/script_marine.cpp +++ b/src/script/api/script_marine.cpp @@ -166,9 +166,9 @@ /* static */ Money ScriptMarine::GetBuildCost(BuildType build_type) { switch (build_type) { - case BT_DOCK: return ::GetPrice(PR_BUILD_STATION_DOCK, 1, NULL); - case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_SHIP, 1, NULL); - case BT_BUOY: return ::GetPrice(PR_BUILD_WAYPOINT_BUOY, 1, NULL); + case BT_DOCK: return ::GetPrice(PR_BUILD_STATION_DOCK, 1, nullptr); + case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_SHIP, 1, nullptr); + case BT_BUOY: return ::GetPrice(PR_BUILD_WAYPOINT_BUOY, 1, nullptr); default: return -1; } } diff --git a/src/script/api/script_news.cpp b/src/script/api/script_news.cpp index 5f84f96d69..0c2ca3792d 100644 --- a/src/script/api/script_news.cpp +++ b/src/script/api/script_news.cpp @@ -25,7 +25,7 @@ { CCountedPtr counter(text); - EnforcePrecondition(false, text != NULL); + EnforcePrecondition(false, text != nullptr); const char *encoded = text->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded); EnforcePrecondition(false, type == NT_ECONOMY || type == NT_SUBSIDIES || type == NT_GENERAL); diff --git a/src/script/api/script_news.hpp b/src/script/api/script_news.hpp index ca0656608f..4414193385 100644 --- a/src/script/api/script_news.hpp +++ b/src/script/api/script_news.hpp @@ -61,7 +61,7 @@ public: * - For #NR_TOWN this parameter should be a valid townID (ScriptTown::IsValidTown). * @return True if the action succeeded. * @pre type must be #NT_ECONOMY, #NT_SUBSIDIES, or #NT_GENERAL. - * @pre text != NULL. + * @pre text != nullptr. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. * @pre The \a reference condition must be fulfilled. */ diff --git a/src/script/api/script_object.cpp b/src/script/api/script_object.cpp index e3501d5de5..6714782e1a 100644 --- a/src/script/api/script_object.cpp +++ b/src/script/api/script_object.cpp @@ -37,9 +37,9 @@ static ScriptStorage *GetStorage() } -/* static */ ScriptInstance *ScriptObject::ActiveInstance::active = NULL; +/* static */ ScriptInstance *ScriptObject::ActiveInstance::active = nullptr; -ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance *instance) +ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance *instance) : alc_scope(instance->engine) { this->last_active = ScriptObject::ActiveInstance::active; ScriptObject::ActiveInstance::active = instance; @@ -52,7 +52,7 @@ ScriptObject::ActiveInstance::~ActiveInstance() /* static */ ScriptInstance *ScriptObject::GetActiveInstance() { - assert(ScriptObject::ActiveInstance::active != NULL); + assert(ScriptObject::ActiveInstance::active != nullptr); return ScriptObject::ActiveInstance::active; } @@ -318,21 +318,19 @@ ScriptObject::ActiveInstance::~ActiveInstance() } /* Set the default callback to return a true/false result of the DoCommand */ - if (callback == NULL) callback = &ScriptInstance::DoCommandReturn; + if (callback == nullptr) callback = &ScriptInstance::DoCommandReturn; /* Are we only interested in the estimate costs? */ - bool estimate_only = GetDoCommandMode() != NULL && !GetDoCommandMode()(); + bool estimate_only = GetDoCommandMode() != nullptr && !GetDoCommandMode()(); -#ifdef ENABLE_NETWORK /* Only set p2 when the command does not come from the network. */ if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX; -#endif /* Store the command for command callback validation. */ if (!estimate_only && _networking && !_generating_world) SetLastCommand(tile, p1, p2, cmd); /* Try to perform the command. */ - CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : NULL, text, false, estimate_only); + CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : nullptr, text, false, estimate_only); /* We failed; set the error and bail out */ if (res.Failed()) { @@ -355,7 +353,7 @@ ScriptObject::ActiveInstance::~ActiveInstance() if (_generating_world) { IncreaseDoCommandCosts(res.GetCost()); - if (callback != NULL) { + if (callback != nullptr) { /* Insert return value into to stack and throw a control code that * the return value in the stack should be used. */ callback(GetActiveInstance()); diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 289c01c824..fba4b69f22 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -18,6 +18,7 @@ #include "script_types.hpp" #include "../script_suspend.hpp" +#include "../squirrel.hpp" /** * The callback function for Mode-classes. @@ -48,6 +49,7 @@ protected: ~ActiveInstance(); private: ScriptInstance *last_active; ///< The active instance before we go instantiated. + ScriptAllocatorScope alc_scope; ///< Keep the correct allocator for the script instance activated static ScriptInstance *active; ///< The global current active instance. }; @@ -69,7 +71,7 @@ protected: /** * Executes a raw DoCommand for the script. */ - static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text = NULL, Script_SuspendCallbackProc *callback = NULL); + static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text = nullptr, Script_SuspendCallbackProc *callback = nullptr); /** * Store the latest command executed by the script. diff --git a/src/script/api/script_order.cpp b/src/script/api/script_order.cpp index a1390bf8f5..045968874c 100644 --- a/src/script/api/script_order.cpp +++ b/src/script/api/script_order.cpp @@ -66,7 +66,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, ScriptOrder::OrderPositio const Order *order = &v->current_order; if (order->GetType() == OT_GOTO_DEPOT && !(order->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return order; order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); - if (order_position == ScriptOrder::ORDER_INVALID) return NULL; + if (order_position == ScriptOrder::ORDER_INVALID) return nullptr; } const Order *order = v->GetFirstOrder(); while (order->GetType() == OT_IMPLICIT) order = order->next; @@ -108,7 +108,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); - return order != NULL && order->GetType() == OT_GOTO_STATION; + return order != nullptr && order->GetType() == OT_GOTO_STATION; } /* static */ bool ScriptOrder::IsGotoDepotOrder(VehicleID vehicle_id, OrderPosition order_position) @@ -116,7 +116,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); - return order != NULL && order->GetType() == OT_GOTO_DEPOT; + return order != nullptr && order->GetType() == OT_GOTO_DEPOT; } /* static */ bool ScriptOrder::IsGotoWaypointOrder(VehicleID vehicle_id, OrderPosition order_position) @@ -124,7 +124,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); - return order != NULL && order->GetType() == OT_GOTO_WAYPOINT; + return order != nullptr && order->GetType() == OT_GOTO_WAYPOINT; } /* static */ bool ScriptOrder::IsConditionalOrder(VehicleID vehicle_id, OrderPosition order_position) @@ -150,7 +150,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); - return order != NULL && order->IsRefit(); + return order != nullptr && order->IsRefit(); } /* static */ bool ScriptOrder::IsCurrentOrderPartOfOrderList(VehicleID vehicle_id) @@ -240,7 +240,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr if (!IsValidVehicleOrder(vehicle_id, order_position)) return INVALID_TILE; const Order *order = ::ResolveOrder(vehicle_id, order_position); - if (order == NULL || order->GetType() == OT_CONDITIONAL) return INVALID_TILE; + if (order == nullptr || order->GetType() == OT_CONDITIONAL) return INVALID_TILE; const Vehicle *v = ::Vehicle::Get(vehicle_id); switch (order->GetType()) { @@ -261,11 +261,13 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr TILE_AREA_LOOP(t, st->train_station) { if (st->TileBelongsToRailStation(t)) return t; } - } else if (st->dock_tile != INVALID_TILE) { - return st->dock_tile; - } else if (st->bus_stops != NULL) { + } else if (st->ship_station.tile != INVALID_TILE) { + TILE_AREA_LOOP(t, st->ship_station) { + if (IsDockTile(t) && GetStationIndex(t) == st->index) return t; + } + } else if (st->bus_stops != nullptr) { return st->bus_stops->xy; - } else if (st->truck_stops != NULL) { + } else if (st->truck_stops != nullptr) { return st->truck_stops->xy; } else if (st->airport.tile != INVALID_TILE) { TILE_AREA_LOOP(tile, st->airport) { @@ -294,7 +296,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr if (!IsValidVehicleOrder(vehicle_id, order_position)) return OF_INVALID; const Order *order = ::ResolveOrder(vehicle_id, order_position); - if (order == NULL || order->GetType() == OT_CONDITIONAL || order->GetType() == OT_DUMMY) return OF_INVALID; + if (order == nullptr || order->GetType() == OT_CONDITIONAL || order->GetType() == OT_DUMMY) return OF_INVALID; ScriptOrderFlags order_flags = OF_NONE; order_flags |= (ScriptOrderFlags)order->GetNonStopType(); @@ -586,7 +588,7 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance) EnforcePrecondition(false, (order_flags & OF_GOTO_NEAREST_DEPOT) == (current & OF_GOTO_NEAREST_DEPOT)); if ((current & OF_NON_STOP_FLAGS) != (order_flags & OF_NON_STOP_FLAGS)) { - return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); + return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, nullptr, &::_DoCommandReturnSetOrderFlags); } switch (order->GetType()) { @@ -595,16 +597,16 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance) uint data = DA_ALWAYS_GO; if (order_flags & OF_SERVICE_IF_NEEDED) data = DA_SERVICE; if (order_flags & OF_STOP_IN_DEPOT) data = DA_STOP; - return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (data << 4) | MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); + return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (data << 4) | MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, nullptr, &::_DoCommandReturnSetOrderFlags); } break; case OT_GOTO_STATION: if ((current & OF_UNLOAD_FLAGS) != (order_flags & OF_UNLOAD_FLAGS)) { - return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); + return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, nullptr, &::_DoCommandReturnSetOrderFlags); } if ((current & OF_LOAD_FLAGS) != (order_flags & OF_LOAD_FLAGS)) { - return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); + return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, nullptr, &::_DoCommandReturnSetOrderFlags); } break; @@ -667,8 +669,14 @@ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance) /* static */ uint ScriptOrder::GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile) { if (vehicle_type == ScriptVehicle::VT_AIR) { - if (ScriptTile::IsStationTile(origin_tile) && ::Station::GetByTile(origin_tile)->airport.tile != INVALID_TILE) origin_tile = ::Station::GetByTile(origin_tile)->airport.tile; - if (ScriptTile::IsStationTile(dest_tile) && ::Station::GetByTile(dest_tile)->airport.tile != INVALID_TILE) dest_tile = ::Station::GetByTile(dest_tile)->airport.tile; + if (ScriptTile::IsStationTile(origin_tile)) { + Station *orig_station = ::Station::GetByTile(origin_tile); + if (orig_station != nullptr && orig_station->airport.tile != INVALID_TILE) origin_tile = orig_station->airport.tile; + } + if (ScriptTile::IsStationTile(dest_tile)) { + Station *dest_station = ::Station::GetByTile(dest_tile); + if (dest_station != nullptr && dest_station->airport.tile != INVALID_TILE) dest_tile = dest_station->airport.tile; + } return ScriptMap::DistanceSquare(origin_tile, dest_tile); } else { diff --git a/src/script/api/script_rail.cpp b/src/script/api/script_rail.cpp index f7682cfd8f..f9495ac2d1 100644 --- a/src/script/api/script_rail.cpp +++ b/src/script/api/script_rail.cpp @@ -25,7 +25,7 @@ /* static */ char *ScriptRail::GetName(RailType rail_type) { - if (!IsRailTypeAvailable(rail_type)) return NULL; + if (!IsRailTypeAvailable(rail_type)) return nullptr; return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text); } @@ -68,7 +68,7 @@ /* static */ bool ScriptRail::IsRailTypeAvailable(RailType rail_type) { - if ((::RailType)rail_type < RAILTYPE_BEGIN || (::RailType)rail_type >= RAILTYPE_END) return false; + if ((::RailType)rail_type >= RAILTYPE_END) return false; return ScriptObject::GetCompany() == OWNER_DEITY || ::HasRailtypeAvail(ScriptObject::GetCompany(), (::RailType)rail_type); } @@ -185,7 +185,7 @@ if (res != CALLBACK_FAILED) { int index = 0; const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index); - if (spec == NULL) { + if (spec == nullptr) { DEBUG(grf, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename); } else { /* We might have gotten an usable station spec. Try to build it, but if it fails we'll fall back to the original station. */ @@ -487,10 +487,10 @@ static bool IsValidSignalType(int signal_type) switch (build_type) { case BT_TRACK: return ::RailBuildCost((::RailType)railtype); - case BT_SIGNAL: return ::GetPrice(PR_BUILD_SIGNALS, 1, NULL); - case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_TRAIN, 1, NULL); - case BT_STATION: return ::GetPrice(PR_BUILD_STATION_RAIL, 1, NULL) + ::GetPrice(PR_BUILD_STATION_RAIL_LENGTH, 1, NULL); - case BT_WAYPOINT: return ::GetPrice(PR_BUILD_WAYPOINT_RAIL, 1, NULL); + case BT_SIGNAL: return ::GetPrice(PR_BUILD_SIGNALS, 1, nullptr); + case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_TRAIN, 1, nullptr); + case BT_STATION: return ::GetPrice(PR_BUILD_STATION_RAIL, 1, nullptr) + ::GetPrice(PR_BUILD_STATION_RAIL_LENGTH, 1, nullptr); + case BT_WAYPOINT: return ::GetPrice(PR_BUILD_WAYPOINT_RAIL, 1, nullptr); default: return -1; } } diff --git a/src/script/api/script_rail.hpp b/src/script/api/script_rail.hpp index 7e2a59e7f7..d52a7bfc46 100644 --- a/src/script/api/script_rail.hpp +++ b/src/script/api/script_rail.hpp @@ -36,7 +36,7 @@ public: ERR_UNSUITABLE_TRACK, // [STR_ERROR_NO_SUITABLE_RAILROAD_TRACK, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, STR_ERROR_THERE_ARE_NO_SIGNALS, STR_ERROR_THERE_IS_NO_STATION] /** This railtype cannot have crossings */ - ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED] + ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED_RAIL] }; /** diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index 3dd1453b68..afa4b28d37 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -23,6 +23,13 @@ return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK; } +/* static */ char *ScriptRoad::GetName(RoadType road_type) +{ + if (!IsRoadTypeAvailable(road_type)) return nullptr; + + return GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name); +} + /* static */ bool ScriptRoad::IsRoadTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; @@ -37,7 +44,7 @@ if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; return ::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) == ROAD_TILE_DEPOT && - (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; + HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType()); } /* static */ bool ScriptRoad::IsRoadStationTile(TileIndex tile) @@ -45,7 +52,7 @@ if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; - return ::IsRoadStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; + return ::IsRoadStopTile(tile) && HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType()); } /* static */ bool ScriptRoad::IsDriveThroughRoadStationTile(TileIndex tile) @@ -53,12 +60,12 @@ if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; - return ::IsDriveThroughStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; + return ::IsDriveThroughStopTile(tile) && HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType()); } /* static */ bool ScriptRoad::IsRoadTypeAvailable(RoadType road_type) { - return ::IsValidRoadType((::RoadType)road_type) && ::HasRoadTypesAvail(ScriptObject::GetCompany(), ::RoadTypeToRoadTypes((::RoadType)road_type)); + return (::RoadType)road_type < ROADTYPE_END && ::HasRoadTypeAvail(ScriptObject::GetCompany(), (::RoadType)road_type); } /* static */ ScriptRoad::RoadType ScriptRoad::GetCurrentRoadType() @@ -73,11 +80,24 @@ ScriptObject::SetRoadType((::RoadType)road_type); } +/* static */ bool ScriptRoad::RoadVehCanRunOnRoad(RoadType engine_road_type, RoadType road_road_type) +{ + return RoadVehHasPowerOnRoad(engine_road_type, road_road_type); +} + +/* static */ bool ScriptRoad::RoadVehHasPowerOnRoad(RoadType engine_road_type, RoadType road_road_type) +{ + if (!IsRoadTypeAvailable(engine_road_type)) return false; + if (!IsRoadTypeAvailable(road_road_type)) return false; + + return ::HasPowerOnRoad((::RoadType)engine_road_type, (::RoadType)road_road_type); +} + /* static */ bool ScriptRoad::HasRoadType(TileIndex tile, RoadType road_type) { if (!ScriptMap::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(road_type)) return false; - return ::GetAnyRoadBits(tile, (::RoadType)road_type, false) != ROAD_NONE; + return ::GetAnyRoadBits(tile, ::GetRoadTramType((::RoadType)road_type), false) != ROAD_NONE; } /* static */ bool ScriptRoad::AreRoadTilesConnected(TileIndex t1, TileIndex t2) @@ -89,8 +109,9 @@ /* Tiles not neighbouring */ if ((abs((int)::TileX(t1) - (int)::TileX(t2)) + abs((int)::TileY(t1) - (int)::TileY(t2))) != 1) return false; - RoadBits r1 = ::GetAnyRoadBits(t1, ScriptObject::GetRoadType()); - RoadBits r2 = ::GetAnyRoadBits(t2, ScriptObject::GetRoadType()); + RoadTramType rtt = ::GetRoadTramType(ScriptObject::GetRoadType()); + RoadBits r1 = ::GetAnyRoadBits(t1, rtt); // TODO + RoadBits r2 = ::GetAnyRoadBits(t2, rtt); // TODO uint dir_1 = (::TileX(t1) == ::TileX(t2)) ? (::TileY(t1) < ::TileY(t2) ? 2 : 0) : (::TileX(t1) < ::TileX(t2) ? 1 : 3); uint dir_2 = 2 ^ dir_1; @@ -100,6 +121,16 @@ return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND); } +/* static */ bool ScriptRoad::ConvertRoadType(TileIndex start_tile, TileIndex end_tile, RoadType road_type) +{ + EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); + EnforcePrecondition(false, ::IsValidTile(start_tile)); + EnforcePrecondition(false, ::IsValidTile(end_tile)); + EnforcePrecondition(false, IsRoadTypeAvailable(road_type)); + + return ScriptObject::DoCommand(start_tile, end_tile, (::RoadType)road_type, CMD_CONVERT_ROAD); +} + /* Helper functions for ScriptRoad::CanBuildConnectedRoadParts(). */ /** @@ -245,7 +276,7 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start /* Now perform the actual rotation. */ for (int j = 0; j < base_rotate; j++) { - for (int i = 0; i < existing->size; i++) { + for (size_t i = 0; i < existing->size; i++) { existing->array[i] = RotateNeighbour(existing->array[i]); } start = RotateNeighbour(start); @@ -256,7 +287,7 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start RoadBits start_roadbits = NeighbourToRoadBits(start); RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end); RoadBits existing_roadbits = ROAD_NONE; - for (int i = 0; i < existing->size; i++) { + for (size_t i = 0; i < existing->size; i++) { existing_roadbits |= NeighbourToRoadBits(existing->array[i]); } @@ -354,7 +385,7 @@ static bool NormaliseTileOffset(int32 *tile) /* The start tile and end tile cannot be the same tile either. */ if (start == end) return -1; - for (int i = 0; i < existing->size; i++) { + for (size_t i = 0; i < existing->size; i++) { if (!NormaliseTileOffset(&existing->array[i])) return -1; } @@ -380,7 +411,7 @@ static bool NormaliseTileOffset(int32 *tile) if (::IsNormalRoadTile(tile)) { rb = ::GetAllRoadBits(tile); } else { - for (::RoadType rt = ::ROADTYPE_BEGIN; rt < ::ROADTYPE_END; rt++) rb |= ::GetAnyRoadBits(tile, rt); + rb = ::GetAnyRoadBits(tile, RTT_ROAD) | ::GetAnyRoadBits(tile, RTT_TRAM); } for (uint i = 0; i < lengthof(neighbours); i++) { if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i]; @@ -392,15 +423,15 @@ static bool NormaliseTileOffset(int32 *tile) /** * Check whether one can reach (possibly by building) a road piece the center * of the neighbouring tile. This includes roads and (drive through) stations. - * @param rts The road type we want to know reachability for + * @param rt The road type we want to know reachability for * @param start_tile The tile to "enter" the neighbouring tile. * @param neighbour The direction to the neighbouring tile to "enter". * @return true if and only if the tile is reachable. */ -static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, DiagDirection neighbour) +static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagDirection neighbour) { TileIndex neighbour_tile = ::TileAddByDiagDir(start_tile, neighbour); - if ((rts & ::GetRoadTypes(neighbour_tile)) == 0) return false; + if (!HasBit(::GetPresentRoadTypes(neighbour_tile), rt)) return false; switch (::GetTileType(neighbour_tile)) { case MP_ROAD: @@ -422,13 +453,13 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; - ::RoadTypes rts = ::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()); + ::RoadType rt = (::RoadType)GetCurrentRoadType(); int32 neighbour = 0; - if (TileX(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NE)) neighbour++; - if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SE)) neighbour++; - if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SW)) neighbour++; - if (TileY(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NW)) neighbour++; + if (TileX(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NE)) neighbour++; + if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SE)) neighbour++; + if (NeighbourHasReachableRoad(rt, tile, DIAGDIR_SW)) neighbour++; + if (TileY(tile) > 0 && NeighbourHasReachableRoad(rt, tile, DIAGDIR_NW)) neighbour++; return neighbour; } @@ -460,10 +491,10 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia EnforcePrecondition(false, ::IsValidTile(start)); EnforcePrecondition(false, ::IsValidTile(end)); EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); - EnforcePrecondition(false, !one_way || ScriptObject::GetRoadType() == ::ROADTYPE_ROAD); + EnforcePrecondition(false, !one_way || RoadTypeIsRoad(ScriptObject::GetRoadType())); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); - return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (ScriptObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 5) | 1 << 6, CMD_BUILD_LONG_ROAD); + return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (ScriptObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 10) | 1 << 11, CMD_BUILD_LONG_ROAD); } /* static */ bool ScriptRoad::BuildRoad(TileIndex start, TileIndex end) @@ -520,11 +551,11 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); } - uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 32; + uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 4; p2 |= drive_through ? 2 : 0; p2 |= road_veh_type == ROADVEHTYPE_TRUCK ? 1 : 0; - p2 |= ::RoadTypeToRoadTypes(ScriptObject::GetRoadType()) << 2; - p2 |= entrance_dir << 6; + p2 |= ScriptObject::GetRoadType() << 5; + p2 |= entrance_dir << 3; p2 |= (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16; return ScriptObject::DoCommand(tile, 1 | 1 << 8, p2, CMD_BUILD_ROAD_STOP); } @@ -588,17 +619,29 @@ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, Dia if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return -1; switch (build_type) { - case BT_ROAD: return ::GetPrice(PR_BUILD_ROAD, 1, NULL); - case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, NULL); - case BT_BUS_STOP: return ::GetPrice(PR_BUILD_STATION_BUS, 1, NULL); - case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, NULL); + case BT_ROAD: return ::RoadBuildCost((::RoadType)roadtype); + case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, nullptr); + case BT_BUS_STOP: return ::GetPrice(PR_BUILD_STATION_BUS, 1, nullptr); + case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, nullptr); default: return -1; } } +/* static */ ScriptRoad::RoadTramTypes ScriptRoad::GetRoadTramType(RoadType roadtype) +{ + return (RoadTramTypes)(1 << ::GetRoadTramType((::RoadType)roadtype)); +} + +/* static */ int32 ScriptRoad::GetMaxSpeed(RoadType road_type) +{ + if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return 0; + + return GetRoadTypeInfo((::RoadType)road_type)->max_speed; +} + /* static */ uint16 ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype) { if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return 0; - return roadtype == ROADTYPE_TRAM ? 3 : 2; + return GetRoadTypeInfo((::RoadType)roadtype)->maintenance_multiplier; } diff --git a/src/script/api/script_road.hpp b/src/script/api/script_road.hpp index ed4058f973..bc230bda33 100644 --- a/src/script/api/script_road.hpp +++ b/src/script/api/script_road.hpp @@ -13,6 +13,7 @@ #define SCRIPT_ROAD_HPP #include "script_tile.hpp" +#include "../../../road.h" /** * Class that handles all road related functions. @@ -36,16 +37,21 @@ public: /** Drive through roads can't be build on town owned roads */ ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, // [STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD] - /** One way roads can't have junctions */ ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, // [STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION] + + /** This roadtype cannot have crossings */ + ERR_ROADTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED_ROAD] + + /** No suitable road could be found */ + ERR_UNSUITABLE_ROAD, // [STR_ERROR_NO_SUITABLE_ROAD, STR_ERROR_NO_SUITABLE_TRAMWAY, STR_ERROR_INCOMPATIBLE_ROAD] }; /** * Types of road known to the game. */ enum RoadType { - /* Note: these values represent part of the in-game RoadType enum */ + /* Note: these values represent part of the in-game static values */ ROADTYPE_ROAD = ::ROADTYPE_ROAD, ///< Build road objects. ROADTYPE_TRAM = ::ROADTYPE_TRAM, ///< Build tram objects. @@ -53,6 +59,14 @@ public: ROADTYPE_INVALID = -1, ///< Invalid RoadType. }; + /** + * Road/tram types + */ + enum RoadTramTypes { + ROADTRAMTYPES_ROAD = ::RTTB_ROAD, ///< Road road types. + ROADTRAMTYPES_TRAM = ::RTTB_TRAM, ///< Tram road types. + }; + /** * Type of road station. */ @@ -71,6 +85,14 @@ public: BT_TRUCK_STOP, ///< Build a truck stop }; + /** + * Get the name of a road type. + * @param road_type The road type to get the name of. + * @pre IsRoadTypeAvailable(road_type). + * @return The name the road type has. + */ + static char *GetName(RoadType road_type); + /** * Determines whether a busstop or a truckstop is needed to transport a certain cargo. * @param cargo_type The cargo to test. @@ -137,6 +159,41 @@ public: */ static void SetCurrentRoadType(RoadType road_type); + /** + * Check if a road vehicle built for a road type can run on another road type. + * @param engine_road_type The road type the road vehicle is built for. + * @param track_road_type The road type you want to check. + * @pre ScriptRoad::IsRoadTypeAvailable(engine_road_type). + * @pre ScriptRoad::IsRoadTypeAvailable(road_road_type). + * @return Whether a road vehicle built for 'engine_road_type' can run on 'road_road_type'. + */ + static bool RoadVehCanRunOnRoad(ScriptRoad::RoadType engine_road_type, ScriptRoad::RoadType road_road_type); + + /** + * Check if a road vehicle built for a road type has power on another road type. + * @param engine_road_type The road type the road vehicle is built for. + * @param road_road_type The road type you want to check. + * @pre ScriptRoad::IsRoadTypeAvailable(engine_road_type). + * @pre ScriptRoad::IsRoadTypeAvailable(road_road_type). + * @return Whether a road vehicle built for 'engine_road_type' has power on 'road_road_type'. + */ + static bool RoadVehHasPowerOnRoad(ScriptRoad::RoadType engine_road_type, ScriptRoad::RoadType road_road_type); + + + /** + * Convert the road on all tiles within a rectangle to another RoadType. + * @param start_tile One corner of the rectangle. + * @param end_tile The opposite corner of the rectangle. + * @param road_type The RoadType you want to convert. + * @pre ScriptMap::IsValidTile(start_tile). + * @pre ScriptMap::IsValidTile(end_tile). + * @pre IsRoadTypeAvailable(road_type). + * @game @pre Valid ScriptCompanyMode active in scope. + * @exception ScriptRoad::ERR_UNSUITABLE_ROAD + * @return Whether at least some road has been converted successfully. + */ + static bool ConvertRoadType(TileIndex start_tile, TileIndex end_tile, RoadType road_type); + /** * Check if a given tile has RoadType. * @param tile The tile to check. @@ -162,7 +219,7 @@ public: static bool AreRoadTilesConnected(TileIndex tile_from, TileIndex tile_to); /** - * Lookup function for building road parts independend on whether the + * Lookup function for building road parts independent of whether the * "building on slopes" setting is enabled or not. * This implementation can be used for abstract reasoning about a tile as * it needs the slope and existing road parts of the tile as information. @@ -193,10 +250,10 @@ public: static int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, struct Array *existing, TileIndex start, TileIndex end); /** - * Lookup function for building road parts independend on whether the + * Lookup function for building road parts independent of whether the * "building on slopes" setting is enabled or not. * This implementation can be used for reasoning about an existing tile. - * @param tile The the tile to examine. + * @param tile The tile to examine. * @param start The tile from where "tile" will be entered. * @param end The tile from where "tile" will be exited. * @pre start != end. @@ -482,16 +539,35 @@ public: /** * Get the baseprice of building a road-related object. - * @param roadtype the roadtype that is build (on) + * @param roadtype the roadtype of the object to build * @param build_type the type of object to build - * @pre IsRoadTypeAvailable(railtype) + * @pre IsRoadTypeAvailable(roadtype) * @return The baseprice of building the given object. */ static Money GetBuildCost(RoadType roadtype, BuildType build_type); /** - * Get the maintenance cost factor of a roadtype. - * @param roadtype The roadtype to get the maintenance factor of. + * Test if a road type is for road or trams. + * @param roadtype the roadtype to test. + * @return RoadTramTypes of the road types. + */ + static RoadTramTypes GetRoadTramType(RoadType roadtype); + + /** + * Get the maximum speed of road vehicles running on this roadtype. + * @param road_type The roadtype to get the maximum speed of. + * @pre IsRoadTypeAvailable(road_type) + * @return The maximum speed road vehicles can run on this roadtype + * or 0 if there is no limit. + * @note The speed is in OpenTTD's internal speed unit. + * This is mph / 0.8, which is roughly 0.5 km/h. + * To get km/h multiply this number by 2.01168. + */ + static int32 GetMaxSpeed(RoadType road_type); + + /** + * Get the maintenance cost factor of a road type. + * @param roadtype The road type to get the maintenance factor of. * @pre IsRoadTypeAvailable(roadtype) * @return Maintenance cost factor of the roadtype. */ diff --git a/src/script/api/script_roadtypelist.cpp b/src/script/api/script_roadtypelist.cpp new file mode 100644 index 0000000000..a6d6c4ae60 --- /dev/null +++ b/src/script/api/script_roadtypelist.cpp @@ -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 . + */ + +/** @file script_roadtypelist.cpp Implementation of ScriptRoadTypeList and friends. */ + +#include "../../stdafx.h" +#include "script_roadtypelist.hpp" +#include "../../road_func.h" + +#include "../../safeguards.h" + +ScriptRoadTypeList::ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts) +{ + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (!HasBit(rtts, GetRoadTramType(rt))) continue; + if (ScriptObject::GetCompany() == OWNER_DEITY || ::HasRoadTypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt); + } +} diff --git a/src/script/api/script_roadtypelist.hpp b/src/script/api/script_roadtypelist.hpp new file mode 100644 index 0000000000..cbcd7fd469 --- /dev/null +++ b/src/script/api/script_roadtypelist.hpp @@ -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 script_roadtypelist.hpp List all available roadtypes. */ + +#ifndef SCRIPT_ROADTYPELIST_HPP +#define SCRIPT_ROADTYPELIST_HPP + +#include "script_list.hpp" +#include "script_road.hpp" + +/** + * Creates a list of all available roadtypes. + * @api ai game + * @ingroup ScriptList + */ +class ScriptRoadTypeList : public ScriptList { +public: + /** + * @param rtts Bitmask of road/tram types to list. + */ + ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts); +}; + +#endif /* SCRIPT_ROADTYPELIST_HPP */ diff --git a/src/script/api/script_sign.cpp b/src/script/api/script_sign.cpp index 236e1df7ef..33c8e9a28a 100644 --- a/src/script/api/script_sign.cpp +++ b/src/script/api/script_sign.cpp @@ -23,7 +23,7 @@ /* static */ bool ScriptSign::IsValidSign(SignID sign_id) { const Sign *si = ::Sign::GetIfValid(sign_id); - return si != NULL && (si->owner == ScriptObject::GetCompany() || si->owner == OWNER_DEITY); + return si != nullptr && (si->owner == ScriptObject::GetCompany() || si->owner == OWNER_DEITY); } /* static */ ScriptCompany::CompanyID ScriptSign::GetOwner(SignID sign_id) @@ -38,7 +38,7 @@ CCountedPtr counter(name); EnforcePrecondition(false, IsValidSign(sign_id)); - EnforcePrecondition(false, name != NULL); + EnforcePrecondition(false, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_SIGN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); @@ -48,7 +48,7 @@ /* static */ char *ScriptSign::GetName(SignID sign_id) { - if (!IsValidSign(sign_id)) return NULL; + if (!IsValidSign(sign_id)) return nullptr; ::SetDParam(0, sign_id); return GetString(STR_SIGN_NAME); @@ -73,7 +73,7 @@ CCountedPtr counter(name); EnforcePrecondition(INVALID_SIGN, ::IsValidTile(location)); - EnforcePrecondition(INVALID_SIGN, name != NULL); + EnforcePrecondition(INVALID_SIGN, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(INVALID_SIGN, text); EnforcePreconditionCustomError(INVALID_SIGN, ::Utf8StringLength(text) < MAX_LENGTH_SIGN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); diff --git a/src/script/api/script_sign.hpp b/src/script/api/script_sign.hpp index e5c2164da8..4b0483e982 100644 --- a/src/script/api/script_sign.hpp +++ b/src/script/api/script_sign.hpp @@ -45,7 +45,7 @@ public: * @param sign_id The sign to set the name for. * @param name The name for the sign (can be either a raw string, or a ScriptText object). * @pre IsValidSign(sign_id). - * @pre name != NULL && len(name) != 0. + * @pre name != nullptr && len(name) != 0. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if and only if the name was changed. */ @@ -81,7 +81,7 @@ public: * @param location The place to build the sign. * @param name The text to place on the sign (can be either a raw string, or a ScriptText object). * @pre ScriptMap::IsValidTile(location). - * @pre name != NULL && len(name) != 0. + * @pre name != nullptr && len(name) != 0. * @exception ScriptSign::ERR_SIGN_TOO_MANY_SIGNS * @return The SignID of the build sign (use IsValidSign() to check for validity). * In test-mode it returns 0 if successful, or any other value to indicate diff --git a/src/script/api/script_station.cpp b/src/script/api/script_station.cpp index 5ed43e0a67..e5536c6e04 100644 --- a/src/script/api/script_station.cpp +++ b/src/script/api/script_station.cpp @@ -23,7 +23,7 @@ /* static */ bool ScriptStation::IsValidStation(StationID station_id) { const Station *st = ::Station::GetIfValid(station_id); - return st != NULL && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE); + return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE); } /* static */ ScriptCompany::CompanyID ScriptStation::GetOwner(StationID station_id) @@ -211,13 +211,11 @@ template if (!IsValidStation(station_id)) return false; if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return false; - ::RoadTypes r = RoadTypeToRoadTypes((::RoadType)road_type); - - for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_BUS); rs != NULL; rs = rs->next) { - if ((::GetRoadTypes(rs->xy) & r) != 0) return true; + for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_BUS); rs != nullptr; rs = rs->next) { + if (HasBit(::GetPresentRoadTypes(rs->xy), (::RoadType)road_type)) return true; } - for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_TRUCK); rs != NULL; rs = rs->next) { - if ((::GetRoadTypes(rs->xy) & r) != 0) return true; + for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_TRUCK); rs != nullptr; rs = rs->next) { + if (HasBit(::GetPresentRoadTypes(rs->xy), (::RoadType)road_type)) return true; } return false; diff --git a/src/script/api/script_stationlist.cpp b/src/script/api/script_stationlist.cpp index 51a06b5a74..4bbb5fa677 100644 --- a/src/script/api/script_stationlist.cpp +++ b/src/script/api/script_stationlist.cpp @@ -32,7 +32,7 @@ ScriptStationList_Vehicle::ScriptStationList_Vehicle(VehicleID vehicle_id) Vehicle *v = ::Vehicle::Get(vehicle_id); - for (Order *o = v->GetFirstOrder(); o != NULL; o = o->next) { + for (Order *o = v->GetFirstOrder(); o != nullptr; o = o->next) { if (o->IsType(OT_GOTO_STATION)) this->AddItem(o->GetDestination()); } } @@ -120,7 +120,7 @@ private: CargoCollector::CargoCollector(ScriptStationList_Cargo *parent, StationID station_id, CargoID cargo, StationID other) : - list(parent), ge(NULL), other_station(other), last_key(INVALID_STATION), amount(0) + list(parent), ge(nullptr), other_station(other), last_key(INVALID_STATION), amount(0) { if (!ScriptStation::IsValidStation(station_id)) return; if (!ScriptCargo::IsValidCargo(cargo)) return; @@ -176,7 +176,7 @@ template void ScriptStationList_CargoWaiting::Add(StationID station_id, CargoID cargo, StationID other_station) { CargoCollector collector(this, station_id, cargo, other_station); - if (collector.GE() == NULL) return; + if (collector.GE() == nullptr) return; StationCargoList::ConstIterator iter = collector.GE()->cargo.Packets()->begin(); StationCargoList::ConstIterator end = collector.GE()->cargo.Packets()->end(); @@ -190,7 +190,7 @@ template void ScriptStationList_CargoPlanned::Add(StationID station_id, CargoID cargo, StationID other_station) { CargoCollector collector(this, station_id, cargo, other_station); - if (collector.GE() == NULL) return; + if (collector.GE() == nullptr) return; FlowStatMap::const_iterator iter = collector.GE()->flows.begin(); FlowStatMap::const_iterator end = collector.GE()->flows.end(); @@ -215,7 +215,7 @@ ScriptStationList_CargoWaitingViaByFrom::ScriptStationList_CargoWaitingViaByFrom StationID station_id, CargoID cargo, StationID via) { CargoCollector collector(this, station_id, cargo, via); - if (collector.GE() == NULL) return; + if (collector.GE() == nullptr) return; std::pair range = collector.GE()->cargo.Packets()->equal_range(via); @@ -261,7 +261,7 @@ ScriptStationList_CargoPlannedFromByVia::ScriptStationList_CargoPlannedFromByVia StationID station_id, CargoID cargo, StationID from) { CargoCollector collector(this, station_id, cargo, from); - if (collector.GE() == NULL) return; + if (collector.GE() == nullptr) return; FlowStatMap::const_iterator iter = collector.GE()->flows.find(from); if (iter == collector.GE()->flows.end()) return; diff --git a/src/script/api/script_story_page.cpp b/src/script/api/script_story_page.cpp index 11820ec3f6..e31ad71c3f 100644 --- a/src/script/api/script_story_page.cpp +++ b/src/script/api/script_story_page.cpp @@ -48,7 +48,7 @@ c, 0, CMD_CREATE_STORY_PAGE, - title != NULL? title->GetEncodedText() : NULL, + title != nullptr? title->GetEncodedText() : nullptr, &ScriptInstance::DoCommandReturnStoryPageID)) return STORY_PAGE_INVALID; /* In case of test-mode, we return StoryPageID 0 */ @@ -61,7 +61,7 @@ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, IsValidStoryPage(story_page_id)); - EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && !StrEmpty(text->GetEncodedText()))); + EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, (type != SPET_TEXT && type != SPET_LOCATION) || (text != nullptr && !StrEmpty(text->GetEncodedText()))); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_LOCATION || ::IsValidTile(reference)); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_GOAL || ScriptGoal::IsValidGoal((ScriptGoal::GoalID)reference)); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_GOAL || !(StoryPage::Get(story_page_id)->company == INVALID_COMPANY && Goal::Get(reference)->company != INVALID_COMPANY)); @@ -70,7 +70,7 @@ story_page_id + (type << 16), type == SPET_GOAL ? reference : 0, CMD_CREATE_STORY_PAGE_ELEMENT, - type == SPET_TEXT || type == SPET_LOCATION ? text->GetEncodedText() : NULL, + type == SPET_TEXT || type == SPET_LOCATION ? text->GetEncodedText() : nullptr, &ScriptInstance::DoCommandReturnStoryPageElementID)) return STORY_PAGE_ELEMENT_INVALID; /* In case of test-mode, we return StoryPageElementID 0 */ @@ -88,7 +88,7 @@ StoryPage *p = StoryPage::Get(pe->page); ::StoryPageElementType type = pe->type; - EnforcePrecondition(false, (type != ::SPET_TEXT && type != ::SPET_LOCATION) || (text != NULL && !StrEmpty(text->GetEncodedText()))); + EnforcePrecondition(false, (type != ::SPET_TEXT && type != ::SPET_LOCATION) || (text != nullptr && !StrEmpty(text->GetEncodedText()))); EnforcePrecondition(false, type != ::SPET_LOCATION || ::IsValidTile(reference)); EnforcePrecondition(false, type != ::SPET_GOAL || ScriptGoal::IsValidGoal((ScriptGoal::GoalID)reference)); EnforcePrecondition(false, type != ::SPET_GOAL || !(p->company == INVALID_COMPANY && Goal::Get(reference)->company != INVALID_COMPANY)); @@ -97,7 +97,7 @@ story_page_element_id, type == ::SPET_GOAL ? reference : 0, CMD_UPDATE_STORY_PAGE_ELEMENT, - type == ::SPET_TEXT || type == ::SPET_LOCATION ? text->GetEncodedText() : NULL); + type == ::SPET_TEXT || type == ::SPET_LOCATION ? text->GetEncodedText() : nullptr); } /* static */ uint32 ScriptStoryPage::GetPageSortValue(StoryPageID story_page_id) @@ -121,7 +121,7 @@ EnforcePrecondition(false, IsValidStoryPage(story_page_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); - return ScriptObject::DoCommand(0, story_page_id, 0, CMD_SET_STORY_PAGE_TITLE, title != NULL? title->GetEncodedText() : NULL); + return ScriptObject::DoCommand(0, story_page_id, 0, CMD_SET_STORY_PAGE_TITLE, title != nullptr? title->GetEncodedText() : nullptr); } /* static */ ScriptCompany::CompanyID ScriptStoryPage::GetCompany(StoryPageID story_page_id) @@ -147,7 +147,7 @@ EnforcePrecondition(false, IsValidStoryPage(story_page_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); - return ScriptObject::DoCommand(0, story_page_id, date, CMD_SET_STORY_PAGE_DATE, NULL); + return ScriptObject::DoCommand(0, story_page_id, date, CMD_SET_STORY_PAGE_DATE, nullptr); } diff --git a/src/script/api/script_story_page.hpp b/src/script/api/script_story_page.hpp index c22d4c198e..e806bb7664 100644 --- a/src/script/api/script_story_page.hpp +++ b/src/script/api/script_story_page.hpp @@ -92,12 +92,12 @@ public: * Create a new story page element. * @param story_page_id The page id of the story page which the page element should be appended to. * @param type Which page element type to create. - * @param reference A reference value to the object that is refered to by some page element types. When type is SPET_GOAL, this is the goal ID. When type is SPET_LOCATION, this is the TileIndex. + * @param reference A reference value to the object that is referred to by some page element types. When type is SPET_GOAL, this is the goal ID. When type is SPET_LOCATION, this is the TileIndex. * @param text The body text of page elements that allow custom text. (SPET_TEXT and SPET_LOCATION) * @return The new StoryPageElementID, or STORY_PAGE_ELEMENT_INVALID if it failed. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page). - * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && len(text) != 0). + * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != nullptr && len(text) != 0). * @pre type != SPET_LOCATION || ScriptMap::IsValidTile(reference). * @pre type != SPET_GOAL || ScriptGoal::IsValidGoal(reference). * @pre if type is SPET_GOAL and story_page is a global page, then referenced goal must be global. @@ -107,12 +107,12 @@ public: /** * Update the content of a page element * @param story_page_element_id The page id of the story page which the page element should be appended to. - * @param reference A reference value to the object that is refered to by some page element types. See also NewElement. + * @param reference A reference value to the object that is referred to by some page element types. See also NewElement. * @param text The body text of page elements that allow custom text. See also NewElement. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page). - * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && len(text) != 0). + * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != nullptr && len(text) != 0). * @pre type != SPET_LOCATION || ScriptMap::IsValidTile(reference). * @pre type != SPET_GOAL || ScriptGoal::IsValidGoal(reference). * @pre if type is SPET_GOAL and story_page is a global page, then referenced goal must be global. diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index e692be0ae2..bfc866ac42 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -63,7 +63,7 @@ ScriptText::~ScriptText() { for (int i = 0; i < SCRIPT_TEXT_MAX_PARAMETERS; i++) { free(this->params[i]); - if (this->paramt[i] != NULL) this->paramt[i]->Release(); + if (this->paramt[i] != nullptr) this->paramt[i]->Release(); } } @@ -72,11 +72,11 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; free(this->params[parameter]); - if (this->paramt[parameter] != NULL) this->paramt[parameter]->Release(); + if (this->paramt[parameter] != nullptr) this->paramt[parameter]->Release(); this->parami[parameter] = 0; - this->params[parameter] = NULL; - this->paramt[parameter] = NULL; + this->params[parameter] = nullptr; + this->paramt[parameter] = nullptr; switch (sq_gettype(vm, -1)) { case OT_STRING: { @@ -97,7 +97,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) } case OT_INSTANCE: { - SQUserPointer real_instance = NULL; + SQUserPointer real_instance = nullptr; HSQOBJECT instance; sq_getstackobj(vm, -1, &instance); @@ -112,7 +112,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) /* Get the 'real' instance of this class */ sq_getinstanceup(vm, -1, &real_instance, 0); - if (real_instance == NULL) return SQ_ERROR; + if (real_instance == nullptr) return SQ_ERROR; ScriptText *value = static_cast(real_instance); value->AddRef(); @@ -183,7 +183,7 @@ const char *ScriptText::GetEncodedText() static char buf[1024]; int param_count = 0; this->_GetEncodedText(buf, lastof(buf), param_count); - return (param_count > SCRIPT_TEXT_MAX_PARAMETERS) ? NULL : buf; + return (param_count > SCRIPT_TEXT_MAX_PARAMETERS) ? nullptr : buf; } char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count) @@ -191,12 +191,12 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count) p += Utf8Encode(p, SCC_ENCODED); p += seprintf(p, lastofp, "%X", this->string); for (int i = 0; i < this->paramc; i++) { - if (this->params[i] != NULL) { + if (this->params[i] != nullptr) { p += seprintf(p, lastofp, ":\"%s\"", this->params[i]); param_count++; continue; } - if (this->paramt[i] != NULL) { + if (this->paramt[i] != nullptr) { p += seprintf(p, lastofp, ":"); p = this->paramt[i]->_GetEncodedText(p, lastofp, param_count); continue; @@ -211,7 +211,7 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count) const char *Text::GetDecodedText() { const char *encoded_text = this->GetEncodedText(); - if (encoded_text == NULL) return NULL; + if (encoded_text == nullptr) return nullptr; static char buf[1024]; ::SetDParamStr(0, encoded_text); diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index ed14e391d0..12892a7e79 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -23,14 +23,14 @@ class Text : public ScriptObject { public: /** * Convert a ScriptText to a normal string. - * @return A string (in a static buffer), or NULL. + * @return A string (in a static buffer), or nullptr. * @api -all */ virtual const char *GetEncodedText() = 0; /** * Convert a #ScriptText into a decoded normal string. - * @return A string (in a static buffer), or NULL. + * @return A string (in a static buffer), or nullptr. * @api -all */ const char *GetDecodedText(); @@ -45,7 +45,7 @@ public: RawText(const char *text); ~RawText(); - /* virtual */ const char *GetEncodedText() { return this->text; } + const char *GetEncodedText() override { return this->text; } private: const char *text; }; diff --git a/src/script/api/script_tile.cpp b/src/script/api/script_tile.cpp index db9220acd6..0f62406668 100644 --- a/src/script/api/script_tile.cpp +++ b/src/script/api/script_tile.cpp @@ -33,12 +33,12 @@ case MP_WATER: return IsCoast(tile); case MP_ROAD: /* Tram bits aren't considered buildable */ - if (::GetRoadTypes(tile) != ROADTYPES_ROAD) return false; + if (::GetRoadTypeTram(tile) != INVALID_ROADTYPE) return false; /* Depots and crossings aren't considered buildable */ if (::GetRoadTileType(tile) != ROAD_TILE_NORMAL) return false; - if (!HasExactlyOneBit(::GetRoadBits(tile, ROADTYPE_ROAD))) return false; - if (::IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) return true; - if (::IsRoadOwner(tile, ROADTYPE_ROAD, ScriptObject::GetCompany())) return true; + if (!HasExactlyOneBit(::GetRoadBits(tile, RTT_ROAD))) return false; + if (::IsRoadOwner(tile, RTT_ROAD, OWNER_TOWN)) return true; + if (::IsRoadOwner(tile, RTT_ROAD, ScriptObject::GetCompany())) return true; return false; } } @@ -201,7 +201,12 @@ { if (!::IsValidTile(tile)) return false; - return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, UINT32_MAX)) != TRACKDIR_BIT_NONE; + if (transport_type == TRANSPORT_ROAD) { + return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, 0)) != TRACKDIR_BIT_NONE || + ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, 1)) != TRACKDIR_BIT_NONE; + } else { + return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, 0)) != TRACKDIR_BIT_NONE; + } } /* static */ int32 ScriptTile::GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius) @@ -257,7 +262,6 @@ /* static */ bool ScriptTile::DemolishTile(TileIndex tile) { - EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); @@ -292,7 +296,7 @@ if (!::IsValidTile(tile)) return INVALID_TOWN; Town *town = ::ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); - if (town == NULL) return INVALID_TOWN; + if (town == nullptr) return INVALID_TOWN; return town->index; } @@ -302,7 +306,7 @@ if (!::IsValidTile(tile)) return INVALID_TOWN; Town *town = ::ClosestTownFromTile(tile, UINT_MAX); - if (town == NULL) return INVALID_TOWN; + if (town == nullptr) return INVALID_TOWN; return town->index; } @@ -310,14 +314,14 @@ /* static */ Money ScriptTile::GetBuildCost(BuildType build_type) { switch (build_type) { - case BT_FOUNDATION: return ::GetPrice(PR_BUILD_FOUNDATION, 1, NULL); - case BT_TERRAFORM: return ::GetPrice(PR_TERRAFORM, 1, NULL); - case BT_BUILD_TREES: return ::GetPrice(PR_BUILD_TREES, 1, NULL); - case BT_CLEAR_GRASS: return ::GetPrice(PR_CLEAR_GRASS, 1, NULL); - case BT_CLEAR_ROUGH: return ::GetPrice(PR_CLEAR_ROUGH, 1, NULL); - case BT_CLEAR_ROCKY: return ::GetPrice(PR_CLEAR_ROCKS, 1, NULL); - case BT_CLEAR_FIELDS: return ::GetPrice(PR_CLEAR_FIELDS, 1, NULL); - case BT_CLEAR_HOUSE: return ::GetPrice(PR_CLEAR_HOUSE, 1, NULL); + case BT_FOUNDATION: return ::GetPrice(PR_BUILD_FOUNDATION, 1, nullptr); + case BT_TERRAFORM: return ::GetPrice(PR_TERRAFORM, 1, nullptr); + case BT_BUILD_TREES: return ::GetPrice(PR_BUILD_TREES, 1, nullptr); + case BT_CLEAR_GRASS: return ::GetPrice(PR_CLEAR_GRASS, 1, nullptr); + case BT_CLEAR_ROUGH: return ::GetPrice(PR_CLEAR_ROUGH, 1, nullptr); + case BT_CLEAR_ROCKY: return ::GetPrice(PR_CLEAR_ROCKS, 1, nullptr); + case BT_CLEAR_FIELDS: return ::GetPrice(PR_CLEAR_FIELDS, 1, nullptr); + case BT_CLEAR_HOUSE: return ::GetPrice(PR_CLEAR_HOUSE, 1, nullptr); default: return -1; } } diff --git a/src/script/api/script_tile.hpp b/src/script/api/script_tile.hpp index f4a2f0970e..d527e0d7e1 100644 --- a/src/script/api/script_tile.hpp +++ b/src/script/api/script_tile.hpp @@ -40,7 +40,7 @@ public: /** The area was already flat */ ERR_AREA_ALREADY_FLAT, // [STR_ERROR_ALREADY_LEVELLED] - /** There is a tunnel underneed */ + /** There is a tunnel underneath */ ERR_EXCAVATION_WOULD_DAMAGE, // [STR_ERROR_EXCAVATION_WOULD_DAMAGE] }; @@ -351,7 +351,7 @@ public: * @pre width > 0. * @pre height > 0. * @pre radius >= 0. - * @return Value below 8 means no acceptance; the more the better. + * @return Values below 8 mean no acceptance; the more the better. */ static int32 GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius); @@ -445,7 +445,6 @@ public: * Destroy everything on the given tile. * @param tile The tile to demolish. * @pre ScriptMap::IsValidTile(tile). - * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @return True if and only if the tile was demolished. */ diff --git a/src/script/api/script_tilelist.cpp b/src/script/api/script_tilelist.cpp index 933a92c4cb..fcee67d965 100644 --- a/src/script/api/script_tilelist.cpp +++ b/src/script/api/script_tilelist.cpp @@ -49,6 +49,32 @@ void ScriptTileList::RemoveTile(TileIndex tile) this->RemoveItem(tile); } +/** + * Helper to get list of tiles that will cover an industry's production or acceptance. + * @param i Industry in question + * @param radius Catchment radius to test + * @param bta BitmapTileArea to fill + */ +static void FillIndustryCatchment(const Industry *i, int radius, BitmapTileArea &bta) +{ + TILE_AREA_LOOP(cur_tile, i->location) { + if (!::IsTileType(cur_tile, MP_INDUSTRY) || ::GetIndustryIndex(cur_tile) != i->index) continue; + + int tx = TileX(cur_tile); + int ty = TileY(cur_tile); + for (int y = -radius; y <= radius; y++) { + if (ty + y < 0 || ty + y > (int)MapMaxY()) continue; + for (int x = -radius; x <= radius; x++) { + if (tx + x < 0 || tx + x > (int)MapMaxX()) continue; + TileIndex tile = TileXY(tx + x, ty + y); + if (!IsValidTile(tile)) continue; + if (::IsTileType(tile, MP_INDUSTRY) && ::GetIndustryIndex(tile) == i->index) continue; + bta.SetTile(tile); + } + } + } +} + ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID industry_id, int radius) { if (!ScriptIndustry::IsValidIndustry(industry_id) || radius <= 0) return; @@ -66,12 +92,11 @@ ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID in if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED; - TileArea ta(i->location.tile - ::TileDiffXY(radius, radius), i->location.w + radius * 2, i->location.h + radius * 2); - TILE_AREA_LOOP(cur_tile, ta) { - if (!::IsValidTile(cur_tile)) continue; - /* Exclude all tiles that belong to this industry */ - if (::IsTileType(cur_tile, MP_INDUSTRY) && ::GetIndustryIndex(cur_tile) == industry_id) continue; + BitmapTileArea bta(TileArea(i->location).Expand(radius)); + FillIndustryCatchment(i, radius, bta); + BitmapTileIterator it(bta); + for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) { /* Only add the tile if it accepts the cargo (sometimes just 1 tile of an * industry triggers the acceptance). */ CargoArray acceptance = ::GetAcceptanceAroundTiles(cur_tile, 1, 1, radius); @@ -102,12 +127,11 @@ ScriptTileList_IndustryProducing::ScriptTileList_IndustryProducing(IndustryID in if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED; - TileArea ta(i->location.tile - ::TileDiffXY(radius, radius), i->location.w + radius * 2, i->location.h + radius * 2); - TILE_AREA_LOOP(cur_tile, ta) { - if (!::IsValidTile(cur_tile)) continue; - /* Exclude all tiles that belong to this industry */ - if (::IsTileType(cur_tile, MP_INDUSTRY) && ::GetIndustryIndex(cur_tile) == industry_id) continue; + BitmapTileArea bta(TileArea(i->location).Expand(radius)); + FillIndustryCatchment(i, radius, bta); + BitmapTileIterator it(bta); + for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) { this->AddTile(cur_tile); } } diff --git a/src/script/api/script_town.cpp b/src/script/api/script_town.cpp index 64f8e166ea..9adfa50753 100644 --- a/src/script/api/script_town.cpp +++ b/src/script/api/script_town.cpp @@ -35,7 +35,7 @@ /* static */ char *ScriptTown::GetName(TownID town_id) { - if (!IsValidTown(town_id)) return NULL; + if (!IsValidTown(town_id)) return nullptr; ::SetDParam(0, town_id); return GetString(STR_TOWN_NAME); @@ -45,8 +45,8 @@ { CCountedPtr counter(name); - const char *text = NULL; - if (name != NULL) { + const char *text = nullptr; + if (name != nullptr) { text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); @@ -60,7 +60,7 @@ { CCountedPtr counter(text); - EnforcePrecondition(false, text != NULL); + EnforcePrecondition(false, text != nullptr); const char *encoded_text = text->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded_text); EnforcePrecondition(false, IsValidTown(town_id)); @@ -257,7 +257,7 @@ if (ScriptObject::GetCompany() == OWNER_DEITY) return false; if (!IsValidTown(town_id)) return false; - return HasBit(::GetMaskOfTownActions(NULL, ScriptObject::GetCompany(), ::Town::Get(town_id)), town_action); + return HasBit(::GetMaskOfTownActions(nullptr, ScriptObject::GetCompany(), ::Town::Get(town_id)), town_action); } /* static */ bool ScriptTown::PerformTownAction(TownID town_id, TownAction town_action) @@ -293,8 +293,8 @@ layout = (RoadLayout) (byte)_settings_game.economy.town_layout; } - const char *text = NULL; - if (name != NULL) { + const char *text = nullptr; + if (name != nullptr) { text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); diff --git a/src/script/api/script_town.hpp b/src/script/api/script_town.hpp index 7fdf8a6b39..302c676ebf 100644 --- a/src/script/api/script_town.hpp +++ b/src/script/api/script_town.hpp @@ -148,7 +148,7 @@ public: /** * Rename a town. * @param town_id The town to rename - * @param name The new name of the town. If NULL or an empty string is passed, the town name will be reset to the default name. + * @param name The new name of the town. If nullptr or an empty string is passed, the town name will be reset to the default name. * @pre IsValidTown(town_id). * @return True if the action succeeded. * @api -ai @@ -402,7 +402,7 @@ public: * @param size The town size of the new town. * @param city True if the new town should be a city. * @param layout The town layout of the new town. - * @param name The name of the new town. Pass NULL to use a random town name. + * @param name The name of the new town. Pass nullptr to use a random town name. * @game @pre no company mode in scope || ScriptSettings.GetValue("economy.found_town") != 0. * @ai @pre ScriptSettings.GetValue("economy.found_town") != 0. * @game @pre no company mode in scope || size != TOWN_SIZE_LARGE. diff --git a/src/script/api/script_tunnel.cpp b/src/script/api/script_tunnel.cpp index 7b891f28d0..ce94c17ee8 100644 --- a/src/script/api/script_tunnel.cpp +++ b/src/script/api/script_tunnel.cpp @@ -90,7 +90,7 @@ static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance) uint type = 0; if (vehicle_type == ScriptVehicle::VT_ROAD) { type |= (TRANSPORT_ROAD << 8); - type |= ::RoadTypeToRoadTypes((::RoadType)ScriptObject::GetRoadType()); + type |= ScriptRoad::GetCurrentRoadType(); } else { type |= (TRANSPORT_RAIL << 8); type |= ScriptRail::GetCurrentRailType(); @@ -102,7 +102,7 @@ static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance) } ScriptObject::SetCallbackVariable(0, start); - return ScriptObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL, NULL, &::_DoCommandReturnBuildTunnel1); + return ScriptObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL, nullptr, &::_DoCommandReturnBuildTunnel1); } /* static */ bool ScriptTunnel::_BuildTunnelRoad1() @@ -114,7 +114,7 @@ static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance) DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); - return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &::_DoCommandReturnBuildTunnel2); + return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, nullptr, &::_DoCommandReturnBuildTunnel2); } /* static */ bool ScriptTunnel::_BuildTunnelRoad2() diff --git a/src/script/api/script_vehicle.cpp b/src/script/api/script_vehicle.cpp index ca841f7557..e0d129ad87 100644 --- a/src/script/api/script_vehicle.cpp +++ b/src/script/api/script_vehicle.cpp @@ -29,7 +29,7 @@ /* static */ bool ScriptVehicle::IsValidVehicle(VehicleID vehicle_id) { const Vehicle *v = ::Vehicle::GetIfValid(vehicle_id); - return v != NULL && (v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())); + return v != nullptr && (v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())); } /* static */ ScriptCompany::CompanyID ScriptVehicle::GetOwner(VehicleID vehicle_id) @@ -46,8 +46,8 @@ int num = 1; const Train *v = ::Train::GetIfValid(vehicle_id); - if (v != NULL) { - while ((v = v->GetNextUnit()) != NULL) num++; + if (v != nullptr) { + while ((v = v->GetNextUnit()) != nullptr) num++; } return num; @@ -61,27 +61,50 @@ return v->IsGroundVehicle() ? v->GetGroundVehicleCache()->cached_total_length : -1; } -/* static */ VehicleID ScriptVehicle::BuildVehicle(TileIndex depot, EngineID engine_id) +/* static */ VehicleID ScriptVehicle::_BuildVehicleInternal(TileIndex depot, EngineID engine_id, CargoID cargo) { - EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); + EnforcePrecondition(VEHICLE_INVALID, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(VEHICLE_INVALID, ScriptEngine::IsBuildable(engine_id)); + EnforcePrecondition(VEHICLE_INVALID, cargo == CT_INVALID || ScriptCargo::IsValidCargo(cargo)); ::VehicleType type = ::Engine::Get(engine_id)->type; EnforcePreconditionCustomError(VEHICLE_INVALID, !ScriptGameSettings::IsDisabledVehicleType((ScriptVehicle::VehicleType)type), ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); - if (!ScriptObject::DoCommand(depot, engine_id, 0, ::GetCmdBuildVeh(type), NULL, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID; + if (!ScriptObject::DoCommand(depot, engine_id | (cargo << 24), 0, ::GetCmdBuildVeh(type), nullptr, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID; /* In case of test-mode, we return VehicleID 0 */ return 0; } +/* static */ VehicleID ScriptVehicle::BuildVehicle(TileIndex depot, EngineID engine_id) +{ + return _BuildVehicleInternal(depot, engine_id, CT_INVALID); +} + +/* static */ VehicleID ScriptVehicle::BuildVehicleWithRefit(TileIndex depot, EngineID engine_id, CargoID cargo) +{ + EnforcePrecondition(VEHICLE_INVALID, ScriptCargo::IsValidCargo(cargo)); + return _BuildVehicleInternal(depot, engine_id, cargo); +} + +/* static */ int ScriptVehicle::GetBuildWithRefitCapacity(TileIndex depot, EngineID engine_id, CargoID cargo) +{ + if (!ScriptEngine::IsBuildable(engine_id)) return -1; + if (!ScriptCargo::IsValidCargo(cargo)) return -1; + + ::VehicleType type = ::Engine::Get(engine_id)->type; + + CommandCost res = ::DoCommand(depot, engine_id | (cargo << 24), 0, DC_QUERY_COST, ::GetCmdBuildVeh(type)); + return res.Succeeded() ? _returned_refit_capacity : -1; +} + /* static */ VehicleID ScriptVehicle::CloneVehicle(TileIndex depot, VehicleID vehicle_id, bool share_orders) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); - if (!ScriptObject::DoCommand(depot, vehicle_id, share_orders, CMD_CLONE_VEHICLE, NULL, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID; + if (!ScriptObject::DoCommand(depot, vehicle_id, share_orders, CMD_CLONE_VEHICLE, nullptr, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID; /* In case of test-mode, we return VehicleID 0 */ return 0; @@ -97,13 +120,13 @@ const Train *v = ::Train::Get(source_vehicle_id); while (source_wagon-- > 0) v = v->GetNextUnit(); - const Train *w = NULL; + const Train *w = nullptr; if (dest_vehicle_id != -1) { w = ::Train::Get(dest_vehicle_id); while (dest_wagon-- > 0) w = w->GetNextUnit(); } - return ScriptObject::DoCommand(0, v->index | (move_attached_wagons ? 1 : 0) << 20, w == NULL ? ::INVALID_VEHICLE : w->index, CMD_MOVE_RAIL_VEHICLE); + return ScriptObject::DoCommand(0, v->index | (move_attached_wagons ? 1 : 0) << 20, w == nullptr ? ::INVALID_VEHICLE : w->index, CMD_MOVE_RAIL_VEHICLE); } /* static */ bool ScriptVehicle::MoveWagon(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon) @@ -220,7 +243,7 @@ EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); - EnforcePrecondition(false, name != NULL); + EnforcePrecondition(false, name != nullptr); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_VEHICLE_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); @@ -270,7 +293,7 @@ /* static */ char *ScriptVehicle::GetName(VehicleID vehicle_id) { - if (!IsValidVehicle(vehicle_id)) return NULL; + if (!IsValidVehicle(vehicle_id)) return nullptr; ::SetDParam(0, vehicle_id); return GetString(STR_VEHICLE_NAME); @@ -378,7 +401,7 @@ if (!IsValidVehicle(vehicle_id)) return ScriptRoad::ROADTYPE_INVALID; if (GetVehicleType(vehicle_id) != VT_ROAD) return ScriptRoad::ROADTYPE_INVALID; - return (ScriptRoad::RoadType)(::RoadVehicle::Get(vehicle_id))->roadtype; + return (ScriptRoad::RoadType)(int)(::RoadVehicle::Get(vehicle_id))->roadtype; } /* static */ int32 ScriptVehicle::GetCapacity(VehicleID vehicle_id, CargoID cargo) @@ -387,7 +410,7 @@ if (!ScriptCargo::IsValidCargo(cargo)) return -1; uint32 amount = 0; - for (const Vehicle *v = ::Vehicle::Get(vehicle_id); v != NULL; v = v->Next()) { + for (const Vehicle *v = ::Vehicle::Get(vehicle_id); v != nullptr; v = v->Next()) { if (v->cargo_type == cargo) amount += v->cargo_cap; } @@ -400,7 +423,7 @@ if (!ScriptCargo::IsValidCargo(cargo)) return -1; uint32 amount = 0; - for (const Vehicle *v = ::Vehicle::Get(vehicle_id); v != NULL; v = v->Next()) { + for (const Vehicle *v = ::Vehicle::Get(vehicle_id); v != nullptr; v = v->Next()) { if (v->cargo_type == cargo) amount += v->cargo.StoredCount(); } @@ -432,7 +455,7 @@ if (!IsValidVehicle(vehicle_id)) return false; Vehicle *v = ::Vehicle::Get(vehicle_id); - return v->orders.list != NULL && v->orders.list->GetNumVehicles() > 1; + return v->orders.list != nullptr && v->orders.list->GetNumVehicles() > 1; } /* static */ int ScriptVehicle::GetReliability(VehicleID vehicle_id) @@ -449,9 +472,6 @@ const ::Vehicle *v = ::Vehicle::Get(vehicle_id); switch (v->type) { - case VEH_SHIP: - return _settings_game.pf.pathfinder_for_ships != VPF_NPF ? 129 : 0; - case VEH_AIRCRAFT: return ::Aircraft::From(v)->acache.cached_max_range_sqr; diff --git a/src/script/api/script_vehicle.hpp b/src/script/api/script_vehicle.hpp index f6b22c204d..58a0319d0b 100644 --- a/src/script/api/script_vehicle.hpp +++ b/src/script/api/script_vehicle.hpp @@ -115,7 +115,7 @@ public: * @param vehicle_id The vehicle to set the name for. * @param name The name for the vehicle (can be either a raw string, or a ScriptText object). * @pre IsValidVehicle(vehicle_id). - * @pre name != NULL && len(name) != 0. + * @pre name != nullptr && len(name) != 0. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if and only if the name was changed. @@ -320,6 +320,41 @@ public: */ static VehicleID BuildVehicle(TileIndex depot, EngineID engine_id); + /** + * Builds a vehicle with the given engine at the given depot and refits it to the given cargo. + * @param depot The depot where the vehicle will be build. + * @param engine_id The engine to use for this vehicle. + * @param cargo The cargo to refit to. + * @pre The tile at depot has a depot that can build the engine and + * is owned by you. + * @pre ScriptEngine::IsBuildable(engine_id). + * @pre ScriptCargo::IsValidCargo(cargo). + * @game @pre Valid ScriptCompanyMode active in scope. + * @exception ScriptVehicle::ERR_VEHICLE_TOO_MANY + * @exception ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED + * @exception ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT + * @return The VehicleID of the new vehicle, or an invalid VehicleID when + * it failed. Check the return value using IsValidVehicle. In test-mode + * 0 is returned if it was successful; any other value indicates failure. + * @note In Test Mode it means you can't assign orders yet to this vehicle, + * as the vehicle isn't really built yet. Build it for real first before + * assigning orders. + */ + static VehicleID BuildVehicleWithRefit(TileIndex depot, EngineID engine_id, CargoID cargo); + + /** + * Gets the capacity of a vehicle built at the given depot with the given engine and refitted to the given cargo. + * @param depot The depot where the vehicle will be build. + * @param engine_id The engine to use for this vehicle. + * @param cargo The cargo to refit to. + * @pre The tile at depot has a depot that can build the engine and + * is owned by you. + * @pre ScriptEngine::IsBuildable(engine_id). + * @pre ScriptCargo::IsValidCargo(cargo). + * @return The capacity the vehicle will have when refited. + */ + static int GetBuildWithRefitCapacity(TileIndex depot, EngineID engine_id, CargoID cargo); + /** * Clones a vehicle at the given depot, copying or cloning its orders. * @param depot The depot where the vehicle will be build. @@ -563,6 +598,11 @@ public: static uint GetMaximumOrderDistance(VehicleID vehicle_id); private: + /** + * Internal function used by BuildVehicle(WithRefit). + */ + static VehicleID _BuildVehicleInternal(TileIndex depot, EngineID engine_id, CargoID cargo); + /** * Internal function used by SellWagon(Chain). */ diff --git a/src/script/api/script_vehiclelist.cpp b/src/script/api/script_vehiclelist.cpp index c7040041f0..5534f6f8a5 100644 --- a/src/script/api/script_vehiclelist.cpp +++ b/src/script/api/script_vehiclelist.cpp @@ -102,7 +102,7 @@ ScriptVehicleList_SharedOrders::ScriptVehicleList_SharedOrders(VehicleID vehicle { if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return; - for (const Vehicle *v = Vehicle::Get(vehicle_id)->FirstShared(); v != NULL; v = v->NextShared()) { + for (const Vehicle *v = Vehicle::Get(vehicle_id)->FirstShared(); v != nullptr; v = v->NextShared()) { this->AddItem(v->index); } } diff --git a/src/script/api/script_waypoint.cpp b/src/script/api/script_waypoint.cpp index 91733a38e8..3d121a2dcf 100644 --- a/src/script/api/script_waypoint.cpp +++ b/src/script/api/script_waypoint.cpp @@ -20,7 +20,7 @@ /* static */ bool ScriptWaypoint::IsValidWaypoint(StationID waypoint_id) { const Waypoint *wp = ::Waypoint::GetIfValid(waypoint_id); - return wp != NULL && (wp->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || wp->owner == OWNER_NONE); + return wp != nullptr && (wp->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || wp->owner == OWNER_NONE); } /* static */ StationID ScriptWaypoint::GetWaypointID(TileIndex tile) diff --git a/src/script/api/script_waypointlist.cpp b/src/script/api/script_waypointlist.cpp index dd641a6848..7e0b45a5bf 100644 --- a/src/script/api/script_waypointlist.cpp +++ b/src/script/api/script_waypointlist.cpp @@ -32,7 +32,7 @@ ScriptWaypointList_Vehicle::ScriptWaypointList_Vehicle(VehicleID vehicle_id) const Vehicle *v = ::Vehicle::Get(vehicle_id); - for (const Order *o = v->GetFirstOrder(); o != NULL; o = o->next) { + for (const Order *o = v->GetFirstOrder(); o != nullptr; o = o->next) { if (o->IsType(OT_GOTO_WAYPOINT)) this->AddItem(o->GetDestination()); } } diff --git a/src/script/api/script_window.cpp b/src/script/api/script_window.cpp index 1252f0fc7e..2766a0562f 100644 --- a/src/script/api/script_window.cpp +++ b/src/script/api/script_window.cpp @@ -34,10 +34,10 @@ if (ScriptGame::IsMultiplayer()) return false; if (number == NUMBER_ALL) { - return (FindWindowByClass((::WindowClass)window) != NULL); + return (FindWindowByClass((::WindowClass)window) != nullptr); } - return FindWindowById((::WindowClass)window, number) != NULL; + return FindWindowById((::WindowClass)window, number) != nullptr; } /* static */ void ScriptWindow::Highlight(WindowClass window, uint32 number, uint8 widget, TextColour colour) @@ -56,6 +56,6 @@ } const NWidgetBase *wid = w->GetWidget(widget); - if (wid == NULL) return; + if (wid == nullptr) return; w->SetWidgetHighlight(widget, (::TextColour)colour); } diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index 70acaa2798..7b4fc51d5d 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -954,9 +954,11 @@ public: WID_RV_INFO_TAB = ::WID_RV_INFO_TAB, ///< Info tab. WID_RV_STOP_REPLACE = ::WID_RV_STOP_REPLACE, ///< Stop Replacing button. + /* Train/road only widgets */ + WID_RV_RAIL_ROAD_TYPE_DROPDOWN = ::WID_RV_RAIL_ROAD_TYPE_DROPDOWN, ///< Dropdown menu about the rail/roadtype. + /* Train only widgets. */ WID_RV_TRAIN_ENGINEWAGON_DROPDOWN = ::WID_RV_TRAIN_ENGINEWAGON_DROPDOWN, ///< Dropdown to select engines and/or wagons. - WID_RV_TRAIN_RAILTYPE_DROPDOWN = ::WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. WID_RV_TRAIN_WAGONREMOVE_TOGGLE = ::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. }; @@ -1170,6 +1172,8 @@ public: WID_CI_RAIL_COUNT = ::WID_CI_RAIL_COUNT, ///< Count of rail. WID_CI_ROAD_DESC = ::WID_CI_ROAD_DESC, ///< Description of road. WID_CI_ROAD_COUNT = ::WID_CI_ROAD_COUNT, ///< Count of road. + WID_CI_TRAM_DESC = ::WID_CI_TRAM_DESC, ///< Description of tram. + WID_CI_TRAM_COUNT = ::WID_CI_TRAM_COUNT, ///< Count of tram. WID_CI_WATER_DESC = ::WID_CI_WATER_DESC, ///< Description of water. WID_CI_WATER_COUNT = ::WID_CI_WATER_COUNT, ///< Count of water. WID_CI_STATION_DESC = ::WID_CI_STATION_DESC, ///< Description of station. @@ -1305,6 +1309,8 @@ public: WID_FRW_TIMES_NAMES = ::WID_FRW_TIMES_NAMES, WID_FRW_TIMES_CURRENT = ::WID_FRW_TIMES_CURRENT, WID_FRW_TIMES_AVERAGE = ::WID_FRW_TIMES_AVERAGE, + WID_FRW_ALLOCSIZE = ::WID_FRW_ALLOCSIZE, + WID_FRW_SEL_MEMORY = ::WID_FRW_SEL_MEMORY, WID_FRW_SCROLLBAR = ::WID_FRW_SCROLLBAR, }; @@ -1598,6 +1604,7 @@ public: enum QueryStringWidgets { WID_QS_CAPTION = ::WID_QS_CAPTION, ///< Caption of the window. WID_QS_TEXT = ::WID_QS_TEXT, ///< Text of the query. + WID_QS_WARNING = ::WID_QS_WARNING, ///< Warning label about password security WID_QS_DEFAULT = ::WID_QS_DEFAULT, ///< Default button. WID_QS_CANCEL = ::WID_QS_CANCEL, ///< Cancel button. WID_QS_OK = ::WID_QS_OK, ///< OK button. @@ -1817,6 +1824,7 @@ public: WID_NCP_LABEL = ::WID_NCP_LABEL, ///< Label in front of the password field. WID_NCP_PASSWORD = ::WID_NCP_PASSWORD, ///< Input field for the password. WID_NCP_SAVE_AS_DEFAULT_PASSWORD = ::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, ///< Toggle 'button' for saving the current password as default password. + WID_NCP_WARNING = ::WID_NCP_WARNING, ///< Warning text about password security WID_NCP_CANCEL = ::WID_NCP_CANCEL, ///< Close the window without changing anything. WID_NCP_OK = ::WID_NCP_OK, ///< Safe the password etc. }; @@ -2124,6 +2132,7 @@ public: /** Widgets of the #BuildRoadToolbarWindow class. */ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ + WID_ROT_CAPTION = ::WID_ROT_CAPTION, ///< Caption of the window WID_ROT_ROAD_X = ::WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y = ::WID_ROT_ROAD_Y, ///< Build road in y-direction. WID_ROT_AUTOROAD = ::WID_ROT_AUTOROAD, ///< Autorail. @@ -2135,6 +2144,7 @@ public: WID_ROT_BUILD_BRIDGE = ::WID_ROT_BUILD_BRIDGE, ///< Build bridge. WID_ROT_BUILD_TUNNEL = ::WID_ROT_BUILD_TUNNEL, ///< Build tunnel. WID_ROT_REMOVE = ::WID_ROT_REMOVE, ///< Remove road. + WID_ROT_CONVERT_ROAD = ::WID_ROT_CONVERT_ROAD, ///< Convert road. }; /** Widgets of the #BuildRoadDepotWindow class. */ @@ -2288,6 +2298,7 @@ public: WID_SV_ROADVEHS = ::WID_SV_ROADVEHS, ///< List of scheduled road vehs button. WID_SV_SHIPS = ::WID_SV_SHIPS, ///< List of scheduled ships button. WID_SV_PLANES = ::WID_SV_PLANES, ///< List of scheduled planes button. + WID_SV_CATCHMENT = ::WID_SV_CATCHMENT, ///< Toggle catchment area highlight. }; /** Widgets of the #CompanyStationsWindow class. */ @@ -2433,6 +2444,7 @@ public: WID_TN_BUILDING_TOOLS_START = ::WID_TN_BUILDING_TOOLS_START, ///< Helper for the offset of the building tools WID_TN_RAILS = ::WID_TN_RAILS, ///< Rail building menu. WID_TN_ROADS = ::WID_TN_ROADS, ///< Road building menu. + WID_TN_TRAMS = ::WID_TN_TRAMS, ///< Tram building menu. WID_TN_WATER = ::WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR = ::WID_TN_AIR, ///< Airport building toolbar. WID_TN_LANDSCAPE = ::WID_TN_LANDSCAPE, ///< Landscaping toolbar. @@ -2460,11 +2472,11 @@ public: WID_TE_TOWN_GENERATE = ::WID_TE_TOWN_GENERATE, ///< Town building window. WID_TE_INDUSTRY = ::WID_TE_INDUSTRY, ///< Industry building window. WID_TE_ROADS = ::WID_TE_ROADS, ///< Road building menu. + WID_TE_TRAMS = ::WID_TE_TRAMS, ///< Tram building menu. WID_TE_WATER = ::WID_TE_WATER, ///< Water building toolbar. WID_TE_TREES = ::WID_TE_TREES, ///< Tree building toolbar. WID_TE_SIGNS = ::WID_TE_SIGNS, ///< Sign building. WID_TE_DATE_PANEL = ::WID_TE_DATE_PANEL, ///< Container for the date widgets. - /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ WID_TE_MUSIC_SOUND = ::WID_TE_MUSIC_SOUND, ///< Music/sound configuration menu. WID_TE_HELP = ::WID_TE_HELP, ///< Help menu. WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. @@ -2475,6 +2487,7 @@ public: enum TownDirectoryWidgets { WID_TD_SORT_ORDER = ::WID_TD_SORT_ORDER, ///< Direction of sort dropdown. WID_TD_SORT_CRITERIA = ::WID_TD_SORT_CRITERIA, ///< Criteria of sort dropdown. + WID_TD_FILTER = ::WID_TD_FILTER, ///< Filter of name. WID_TD_LIST = ::WID_TD_LIST, ///< List of towns. WID_TD_SCROLLBAR = ::WID_TD_SCROLLBAR, ///< Scrollbar for the town list. WID_TD_WORLD_POPULATION = ::WID_TD_WORLD_POPULATION, ///< The world's population. @@ -2483,6 +2496,7 @@ public: /** Widgets of the #TownAuthorityWindow class. */ enum TownAuthorityWidgets { WID_TA_CAPTION = ::WID_TA_CAPTION, ///< Caption of window. + WID_TA_ZONE_BUTTON = ::WID_TA_ZONE_BUTTON, ///< Turn on/off showing local authority zone. WID_TA_RATING_INFO = ::WID_TA_RATING_INFO, ///< Overview with ratings for each company. WID_TA_COMMAND_LIST = ::WID_TA_COMMAND_LIST, ///< List of commands for the player. WID_TA_SCROLLBAR = ::WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands. @@ -2498,6 +2512,7 @@ public: WID_TV_CENTER_VIEW = ::WID_TV_CENTER_VIEW, ///< Center the main view on this town. WID_TV_SHOW_AUTHORITY = ::WID_TV_SHOW_AUTHORITY, ///< Show the town authority window. WID_TV_CHANGE_NAME = ::WID_TV_CHANGE_NAME, ///< Change the name of this town. + WID_TV_CATCHMENT = ::WID_TV_CATCHMENT, ///< Toggle catchment area highlight. WID_TV_EXPAND = ::WID_TV_EXPAND, ///< Expand this town (scenario editor only). WID_TV_DELETE = ::WID_TV_DELETE, ///< Delete this town (scenario editor only). }; diff --git a/src/script/api/squirrel_export.awk b/src/script/api/squirrel_export.awk index ef0a74c8db..a2782721c7 100644 --- a/src/script/api/squirrel_export.awk +++ b/src/script/api/squirrel_export.awk @@ -34,7 +34,7 @@ function dump_class_templates(name) print " template <> inline const " name " *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" CR print " template <> inline const " name " &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" CR if (name == "ScriptEvent") { - print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" CR + print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, nullptr, DefSQDestructorCallback<" name ">, true); return 1; }" CR } else if (name == "ScriptText") { print "" CR print " template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {" CR @@ -44,10 +44,10 @@ function dump_class_templates(name) print " if (sq_gettype(vm, index) == OT_STRING) {" CR print " return new RawText(GetParam(ForceType(), vm, index, ptr));" CR print " }" CR - print " return NULL;" CR + print " return nullptr;" CR print " }" CR } else { - print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" CR + print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, nullptr, DefSQDestructorCallback<" name ">, true); return 1; }" CR } } diff --git a/src/script/api/squirrel_export.vbs b/src/script/api/squirrel_export.vbs index a13869509a..d9d5d643d0 100644 --- a/src/script/api/squirrel_export.vbs +++ b/src/script/api/squirrel_export.vbs @@ -62,7 +62,7 @@ Function DumpClassTemplates(name, file) file.WriteLine " template <> inline const " & name & " *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" & name & " *)instance; }" file.WriteLine " template <> inline const " & name & " &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" & name & " *)instance; }" If name = "ScriptEvent" Then - file.WriteLine " template <> inline int Return<" & name & " *>(HSQUIRRELVM vm, " & name & " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, " & Chr(34) & realname & Chr(34) & ", res, NULL, DefSQDestructorCallback<" & name & ">, true); return 1; }" + file.WriteLine " template <> inline int Return<" & name & " *>(HSQUIRRELVM vm, " & name & " *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, " & Chr(34) & realname & Chr(34) & ", res, nullptr, DefSQDestructorCallback<" & name & ">, true); return 1; }" ElseIf name = "ScriptText" Then file.WriteLine "" file.WriteLine " template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {" @@ -72,10 +72,10 @@ Function DumpClassTemplates(name, file) file.WriteLine " if (sq_gettype(vm, index) == OT_STRING) {" file.WriteLine " return new RawText(GetParam(ForceType(), vm, index, ptr));" file.WriteLine " }" - file.WriteLine " return NULL;" + file.WriteLine " return nullptr;" file.WriteLine " }" Else - file.WriteLine " template <> inline int Return<" & name & " *>(HSQUIRRELVM vm, " & name & " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, " & Chr(34) & realname & Chr(34) & ", res, NULL, DefSQDestructorCallback<" & name & ">, true); return 1; }" + file.WriteLine " template <> inline int Return<" & name & " *>(HSQUIRRELVM vm, " & name & " *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, " & Chr(34) & realname & Chr(34) & ", res, nullptr, DefSQDestructorCallback<" & name & ">, true); return 1; }" End If End Function diff --git a/src/script/api/template/template_accounting.hpp.sq b/src/script/api/template/template_accounting.hpp.sq index 298217a22f..58f011a4ee 100644 --- a/src/script/api/template/template_accounting.hpp.sq +++ b/src/script/api/template/template_accounting.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptAccounting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAccounting *)instance; } template <> inline const ScriptAccounting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAccounting *)instance; } template <> inline const ScriptAccounting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAccounting *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptAccounting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Accounting", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptAccounting *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Accounting", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_admin.hpp.sq b/src/script/api/template/template_admin.hpp.sq index 2256d674b9..394304be09 100644 --- a/src/script/api/template/template_admin.hpp.sq +++ b/src/script/api/template/template_admin.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptAdmin &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAdmin *)instance; } template <> inline const ScriptAdmin *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAdmin *)instance; } template <> inline const ScriptAdmin &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAdmin *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptAdmin *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Admin", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptAdmin *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Admin", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_airport.hpp.sq b/src/script/api/template/template_airport.hpp.sq index 402eea076d..d091837ce4 100644 --- a/src/script/api/template/template_airport.hpp.sq +++ b/src/script/api/template/template_airport.hpp.sq @@ -23,5 +23,5 @@ namespace SQConvert { template <> inline ScriptAirport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAirport *)instance; } template <> inline const ScriptAirport *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAirport *)instance; } template <> inline const ScriptAirport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAirport *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptAirport *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Airport", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptAirport *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Airport", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_base.hpp.sq b/src/script/api/template/template_base.hpp.sq index 0ff19bcb89..be19e8bad1 100644 --- a/src/script/api/template/template_base.hpp.sq +++ b/src/script/api/template/template_base.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptBase &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBase *)instance; } template <> inline const ScriptBase *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBase *)instance; } template <> inline const ScriptBase &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBase *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptBase *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Base", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptBase *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Base", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_basestation.hpp.sq b/src/script/api/template/template_basestation.hpp.sq index c11a7745e4..272c58e4a3 100644 --- a/src/script/api/template/template_basestation.hpp.sq +++ b/src/script/api/template/template_basestation.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptBaseStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBaseStation *)instance; } template <> inline const ScriptBaseStation *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBaseStation *)instance; } template <> inline const ScriptBaseStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBaseStation *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptBaseStation *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BaseStation", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptBaseStation *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BaseStation", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_bridge.hpp.sq b/src/script/api/template/template_bridge.hpp.sq index f627155119..90a1569de3 100644 --- a/src/script/api/template/template_bridge.hpp.sq +++ b/src/script/api/template/template_bridge.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptBridge &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridge *)instance; } template <> inline const ScriptBridge *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridge *)instance; } template <> inline const ScriptBridge &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridge *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptBridge *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Bridge", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptBridge *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Bridge", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_bridgelist.hpp.sq b/src/script/api/template/template_bridgelist.hpp.sq index 1f78a78742..61c0ccf403 100644 --- a/src/script/api/template/template_bridgelist.hpp.sq +++ b/src/script/api/template/template_bridgelist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptBridgeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList *)instance; } template <> inline const ScriptBridgeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridgeList *)instance; } template <> inline const ScriptBridgeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptBridgeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BridgeList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptBridgeList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BridgeList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,5 +26,5 @@ namespace SQConvert { template <> inline ScriptBridgeList_Length &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList_Length *)instance; } template <> inline const ScriptBridgeList_Length *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridgeList_Length *)instance; } template <> inline const ScriptBridgeList_Length &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList_Length *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptBridgeList_Length *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BridgeList_Length", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptBridgeList_Length *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BridgeList_Length", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_cargo.hpp.sq b/src/script/api/template/template_cargo.hpp.sq index b57e5c05aa..2d85ef8625 100644 --- a/src/script/api/template/template_cargo.hpp.sq +++ b/src/script/api/template/template_cargo.hpp.sq @@ -27,5 +27,5 @@ namespace SQConvert { template <> inline ScriptCargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargo *)instance; } template <> inline const ScriptCargo *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargo *)instance; } template <> inline const ScriptCargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargo *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCargo *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Cargo", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCargo *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Cargo", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_cargolist.hpp.sq b/src/script/api/template/template_cargolist.hpp.sq index 5b39aa66d8..eee5540278 100644 --- a/src/script/api/template/template_cargolist.hpp.sq +++ b/src/script/api/template/template_cargolist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptCargoList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList *)instance; } template <> inline const ScriptCargoList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList *)instance; } template <> inline const ScriptCargoList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,7 +26,7 @@ namespace SQConvert { template <> inline ScriptCargoList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryAccepting *)instance; } template <> inline const ScriptCargoList_IndustryAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_IndustryAccepting *)instance; } template <> inline const ScriptCargoList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryAccepting *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_IndustryAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_IndustryAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_IndustryAccepting *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_IndustryAccepting", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -35,7 +35,7 @@ namespace SQConvert { template <> inline ScriptCargoList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryProducing *)instance; } template <> inline const ScriptCargoList_IndustryProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_IndustryProducing *)instance; } template <> inline const ScriptCargoList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryProducing *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_IndustryProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_IndustryProducing", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_IndustryProducing *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_IndustryProducing", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -44,5 +44,5 @@ namespace SQConvert { template <> inline ScriptCargoList_StationAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_StationAccepting *)instance; } template <> inline const ScriptCargoList_StationAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_StationAccepting *)instance; } template <> inline const ScriptCargoList_StationAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_StationAccepting *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_StationAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_StationAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_StationAccepting *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_StationAccepting", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_cargomonitor.hpp.sq b/src/script/api/template/template_cargomonitor.hpp.sq index ce0a358ace..2010bf6eb5 100644 --- a/src/script/api/template/template_cargomonitor.hpp.sq +++ b/src/script/api/template/template_cargomonitor.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptCargoMonitor &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoMonitor *)instance; } template <> inline const ScriptCargoMonitor *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoMonitor *)instance; } template <> inline const ScriptCargoMonitor &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoMonitor *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCargoMonitor *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoMonitor", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCargoMonitor *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoMonitor", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_client.hpp.sq b/src/script/api/template/template_client.hpp.sq index 13b9d68b6a..7e9314197b 100644 --- a/src/script/api/template/template_client.hpp.sq +++ b/src/script/api/template/template_client.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptClient &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptClient *)instance; } template <> inline const ScriptClient *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptClient *)instance; } template <> inline const ScriptClient &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptClient *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptClient *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Client", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptClient *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Client", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_clientlist.hpp.sq b/src/script/api/template/template_clientlist.hpp.sq index 74c3f4525f..6373994a15 100644 --- a/src/script/api/template/template_clientlist.hpp.sq +++ b/src/script/api/template/template_clientlist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptClientList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptClientList *)instance; } template <> inline const ScriptClientList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptClientList *)instance; } template <> inline const ScriptClientList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptClientList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptClientList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ClientList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptClientList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ClientList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,5 +26,5 @@ namespace SQConvert { template <> inline ScriptClientList_Company &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptClientList_Company *)instance; } template <> inline const ScriptClientList_Company *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptClientList_Company *)instance; } template <> inline const ScriptClientList_Company &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptClientList_Company *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptClientList_Company *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ClientList_Company", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptClientList_Company *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ClientList_Company", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_company.hpp.sq b/src/script/api/template/template_company.hpp.sq index 82c10381ab..77ca0c933c 100644 --- a/src/script/api/template/template_company.hpp.sq +++ b/src/script/api/template/template_company.hpp.sq @@ -31,5 +31,5 @@ namespace SQConvert { template <> inline ScriptCompany &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompany *)instance; } template <> inline const ScriptCompany *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCompany *)instance; } template <> inline const ScriptCompany &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompany *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCompany *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Company", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCompany *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Company", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_companymode.hpp.sq b/src/script/api/template/template_companymode.hpp.sq index f99f1d42d5..c25f047084 100644 --- a/src/script/api/template/template_companymode.hpp.sq +++ b/src/script/api/template/template_companymode.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptCompanyMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompanyMode *)instance; } template <> inline const ScriptCompanyMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCompanyMode *)instance; } template <> inline const ScriptCompanyMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompanyMode *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptCompanyMode *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CompanyMode", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptCompanyMode *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CompanyMode", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_date.hpp.sq b/src/script/api/template/template_date.hpp.sq index cca4a258b1..c6d65a8674 100644 --- a/src/script/api/template/template_date.hpp.sq +++ b/src/script/api/template/template_date.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptDate &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDate *)instance; } template <> inline const ScriptDate *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptDate *)instance; } template <> inline const ScriptDate &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDate *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptDate *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Date", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptDate *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Date", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_depotlist.hpp.sq b/src/script/api/template/template_depotlist.hpp.sq index f5fcbcf544..4305552cfa 100644 --- a/src/script/api/template/template_depotlist.hpp.sq +++ b/src/script/api/template/template_depotlist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptDepotList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDepotList *)instance; } template <> inline const ScriptDepotList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptDepotList *)instance; } template <> inline const ScriptDepotList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDepotList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptDepotList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "DepotList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptDepotList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "DepotList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_engine.hpp.sq b/src/script/api/template/template_engine.hpp.sq index 3d652df9e8..6aa13a94e3 100644 --- a/src/script/api/template/template_engine.hpp.sq +++ b/src/script/api/template/template_engine.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptEngine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngine *)instance; } template <> inline const ScriptEngine *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEngine *)instance; } template <> inline const ScriptEngine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngine *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEngine *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Engine", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEngine *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Engine", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_enginelist.hpp.sq b/src/script/api/template/template_enginelist.hpp.sq index f17c244eb6..3d42f8c53c 100644 --- a/src/script/api/template/template_enginelist.hpp.sq +++ b/src/script/api/template/template_enginelist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptEngineList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngineList *)instance; } template <> inline const ScriptEngineList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEngineList *)instance; } template <> inline const ScriptEngineList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngineList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEngineList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EngineList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEngineList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EngineList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_error.hpp.sq b/src/script/api/template/template_error.hpp.sq index 8e61f08103..817a2226dc 100644 --- a/src/script/api/template/template_error.hpp.sq +++ b/src/script/api/template/template_error.hpp.sq @@ -23,5 +23,5 @@ namespace SQConvert { template <> inline ScriptError &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptError *)instance; } template <> inline const ScriptError *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptError *)instance; } template <> inline const ScriptError &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptError *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptError *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Error", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptError *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Error", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_event.hpp.sq b/src/script/api/template/template_event.hpp.sq index c0a8afdc93..3847a81ca5 100644 --- a/src/script/api/template/template_event.hpp.sq +++ b/src/script/api/template/template_event.hpp.sq @@ -21,7 +21,7 @@ namespace SQConvert { template <> inline ScriptEvent &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEvent *)instance; } template <> inline const ScriptEvent *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEvent *)instance; } template <> inline const ScriptEvent &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEvent *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEvent *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, "Event", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEvent *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, "Event", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -30,5 +30,5 @@ namespace SQConvert { template <> inline ScriptEventController &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventController *)instance; } template <> inline const ScriptEventController *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventController *)instance; } template <> inline const ScriptEventController &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventController *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventController *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventController", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventController *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventController", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_event_types.hpp.sq b/src/script/api/template/template_event_types.hpp.sq index eb6d1f1b42..1351919b11 100644 --- a/src/script/api/template/template_event_types.hpp.sq +++ b/src/script/api/template/template_event_types.hpp.sq @@ -21,7 +21,7 @@ namespace SQConvert { template <> inline ScriptEventVehicleCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleCrashed *)instance; } template <> inline const ScriptEventVehicleCrashed *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleCrashed *)instance; } template <> inline const ScriptEventVehicleCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleCrashed *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleCrashed *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleCrashed", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleCrashed *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleCrashed", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -30,7 +30,7 @@ namespace SQConvert { template <> inline ScriptEventSubsidyOffer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOffer *)instance; } template <> inline const ScriptEventSubsidyOffer *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyOffer *)instance; } template <> inline const ScriptEventSubsidyOffer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOffer *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyOffer *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyOffer", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyOffer *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyOffer", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -39,7 +39,7 @@ namespace SQConvert { template <> inline ScriptEventSubsidyOfferExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOfferExpired *)instance; } template <> inline const ScriptEventSubsidyOfferExpired *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyOfferExpired *)instance; } template <> inline const ScriptEventSubsidyOfferExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOfferExpired *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyOfferExpired *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyOfferExpired", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyOfferExpired *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyOfferExpired", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -48,7 +48,7 @@ namespace SQConvert { template <> inline ScriptEventSubsidyAwarded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyAwarded *)instance; } template <> inline const ScriptEventSubsidyAwarded *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyAwarded *)instance; } template <> inline const ScriptEventSubsidyAwarded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyAwarded *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyAwarded *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyAwarded", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyAwarded *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyAwarded", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -57,7 +57,7 @@ namespace SQConvert { template <> inline ScriptEventSubsidyExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyExpired *)instance; } template <> inline const ScriptEventSubsidyExpired *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyExpired *)instance; } template <> inline const ScriptEventSubsidyExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyExpired *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyExpired *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyExpired", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyExpired *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyExpired", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -66,7 +66,7 @@ namespace SQConvert { template <> inline ScriptEventEnginePreview &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEnginePreview *)instance; } template <> inline const ScriptEventEnginePreview *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventEnginePreview *)instance; } template <> inline const ScriptEventEnginePreview &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEnginePreview *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventEnginePreview *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventEnginePreview", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventEnginePreview *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventEnginePreview", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -75,7 +75,7 @@ namespace SQConvert { template <> inline ScriptEventCompanyNew &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyNew *)instance; } template <> inline const ScriptEventCompanyNew *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyNew *)instance; } template <> inline const ScriptEventCompanyNew &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyNew *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyNew *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyNew", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyNew *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyNew", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -84,7 +84,7 @@ namespace SQConvert { template <> inline ScriptEventCompanyInTrouble &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyInTrouble *)instance; } template <> inline const ScriptEventCompanyInTrouble *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyInTrouble *)instance; } template <> inline const ScriptEventCompanyInTrouble &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyInTrouble *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyInTrouble *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyInTrouble", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyInTrouble *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyInTrouble", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -93,7 +93,7 @@ namespace SQConvert { template <> inline ScriptEventCompanyAskMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyAskMerger *)instance; } template <> inline const ScriptEventCompanyAskMerger *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyAskMerger *)instance; } template <> inline const ScriptEventCompanyAskMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyAskMerger *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyAskMerger *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyAskMerger", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyAskMerger *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyAskMerger", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -102,7 +102,7 @@ namespace SQConvert { template <> inline ScriptEventCompanyMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyMerger *)instance; } template <> inline const ScriptEventCompanyMerger *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyMerger *)instance; } template <> inline const ScriptEventCompanyMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyMerger *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyMerger *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyMerger", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyMerger *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyMerger", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -111,7 +111,7 @@ namespace SQConvert { template <> inline ScriptEventCompanyBankrupt &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyBankrupt *)instance; } template <> inline const ScriptEventCompanyBankrupt *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyBankrupt *)instance; } template <> inline const ScriptEventCompanyBankrupt &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyBankrupt *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyBankrupt *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyBankrupt", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyBankrupt *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyBankrupt", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -120,7 +120,7 @@ namespace SQConvert { template <> inline ScriptEventVehicleLost &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleLost *)instance; } template <> inline const ScriptEventVehicleLost *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleLost *)instance; } template <> inline const ScriptEventVehicleLost &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleLost *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleLost *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleLost", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleLost *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleLost", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -129,7 +129,7 @@ namespace SQConvert { template <> inline ScriptEventVehicleWaitingInDepot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleWaitingInDepot *)instance; } template <> inline const ScriptEventVehicleWaitingInDepot *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleWaitingInDepot *)instance; } template <> inline const ScriptEventVehicleWaitingInDepot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleWaitingInDepot *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleWaitingInDepot *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleWaitingInDepot", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleWaitingInDepot *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleWaitingInDepot", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -138,7 +138,7 @@ namespace SQConvert { template <> inline ScriptEventVehicleUnprofitable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleUnprofitable *)instance; } template <> inline const ScriptEventVehicleUnprofitable *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleUnprofitable *)instance; } template <> inline const ScriptEventVehicleUnprofitable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleUnprofitable *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleUnprofitable *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleUnprofitable", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleUnprofitable *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleUnprofitable", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -147,7 +147,7 @@ namespace SQConvert { template <> inline ScriptEventIndustryOpen &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryOpen *)instance; } template <> inline const ScriptEventIndustryOpen *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventIndustryOpen *)instance; } template <> inline const ScriptEventIndustryOpen &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryOpen *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventIndustryOpen *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventIndustryOpen", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventIndustryOpen *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventIndustryOpen", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -156,7 +156,7 @@ namespace SQConvert { template <> inline ScriptEventIndustryClose &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryClose *)instance; } template <> inline const ScriptEventIndustryClose *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventIndustryClose *)instance; } template <> inline const ScriptEventIndustryClose &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryClose *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventIndustryClose *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventIndustryClose", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventIndustryClose *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventIndustryClose", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -165,7 +165,7 @@ namespace SQConvert { template <> inline ScriptEventEngineAvailable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEngineAvailable *)instance; } template <> inline const ScriptEventEngineAvailable *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventEngineAvailable *)instance; } template <> inline const ScriptEventEngineAvailable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEngineAvailable *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventEngineAvailable *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventEngineAvailable", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventEngineAvailable *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventEngineAvailable", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -174,7 +174,7 @@ namespace SQConvert { template <> inline ScriptEventStationFirstVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventStationFirstVehicle *)instance; } template <> inline const ScriptEventStationFirstVehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventStationFirstVehicle *)instance; } template <> inline const ScriptEventStationFirstVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventStationFirstVehicle *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventStationFirstVehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventStationFirstVehicle", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventStationFirstVehicle *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventStationFirstVehicle", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -183,7 +183,7 @@ namespace SQConvert { template <> inline ScriptEventDisasterZeppelinerCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCrashed *)instance; } template <> inline const ScriptEventDisasterZeppelinerCrashed *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventDisasterZeppelinerCrashed *)instance; } template <> inline const ScriptEventDisasterZeppelinerCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCrashed *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventDisasterZeppelinerCrashed *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventDisasterZeppelinerCrashed", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventDisasterZeppelinerCrashed *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventDisasterZeppelinerCrashed", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -192,7 +192,7 @@ namespace SQConvert { template <> inline ScriptEventDisasterZeppelinerCleared &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCleared *)instance; } template <> inline const ScriptEventDisasterZeppelinerCleared *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventDisasterZeppelinerCleared *)instance; } template <> inline const ScriptEventDisasterZeppelinerCleared &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCleared *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventDisasterZeppelinerCleared *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventDisasterZeppelinerCleared", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventDisasterZeppelinerCleared *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventDisasterZeppelinerCleared", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -201,7 +201,7 @@ namespace SQConvert { template <> inline ScriptEventTownFounded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventTownFounded *)instance; } template <> inline const ScriptEventTownFounded *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventTownFounded *)instance; } template <> inline const ScriptEventTownFounded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventTownFounded *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventTownFounded *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventTownFounded", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventTownFounded *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventTownFounded", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -210,7 +210,7 @@ namespace SQConvert { template <> inline ScriptEventAircraftDestTooFar &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAircraftDestTooFar *)instance; } template <> inline const ScriptEventAircraftDestTooFar *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventAircraftDestTooFar *)instance; } template <> inline const ScriptEventAircraftDestTooFar &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAircraftDestTooFar *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventAircraftDestTooFar *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventAircraftDestTooFar", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventAircraftDestTooFar *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventAircraftDestTooFar", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -219,7 +219,7 @@ namespace SQConvert { template <> inline ScriptEventAdminPort &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAdminPort *)instance; } template <> inline const ScriptEventAdminPort *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventAdminPort *)instance; } template <> inline const ScriptEventAdminPort &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAdminPort *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventAdminPort *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventAdminPort", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventAdminPort *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventAdminPort", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -228,7 +228,7 @@ namespace SQConvert { template <> inline ScriptEventWindowWidgetClick &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventWindowWidgetClick *)instance; } template <> inline const ScriptEventWindowWidgetClick *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventWindowWidgetClick *)instance; } template <> inline const ScriptEventWindowWidgetClick &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventWindowWidgetClick *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventWindowWidgetClick *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventWindowWidgetClick", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventWindowWidgetClick *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventWindowWidgetClick", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -237,7 +237,7 @@ namespace SQConvert { template <> inline ScriptEventGoalQuestionAnswer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventGoalQuestionAnswer *)instance; } template <> inline const ScriptEventGoalQuestionAnswer *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventGoalQuestionAnswer *)instance; } template <> inline const ScriptEventGoalQuestionAnswer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventGoalQuestionAnswer *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventGoalQuestionAnswer *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventGoalQuestionAnswer", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventGoalQuestionAnswer *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventGoalQuestionAnswer", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -246,7 +246,7 @@ namespace SQConvert { template <> inline ScriptEventCompanyTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyTown *)instance; } template <> inline const ScriptEventCompanyTown *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyTown *)instance; } template <> inline const ScriptEventCompanyTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyTown *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyTown *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyTown", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyTown *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyTown", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -255,7 +255,7 @@ namespace SQConvert { template <> inline ScriptEventExclusiveTransportRights &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventExclusiveTransportRights *)instance; } template <> inline const ScriptEventExclusiveTransportRights *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventExclusiveTransportRights *)instance; } template <> inline const ScriptEventExclusiveTransportRights &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventExclusiveTransportRights *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventExclusiveTransportRights *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventExclusiveTransportRights", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventExclusiveTransportRights *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventExclusiveTransportRights", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -264,5 +264,14 @@ namespace SQConvert { template <> inline ScriptEventRoadReconstruction &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventRoadReconstruction *)instance; } template <> inline const ScriptEventRoadReconstruction *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventRoadReconstruction *)instance; } template <> inline const ScriptEventRoadReconstruction &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventRoadReconstruction *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptEventRoadReconstruction *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventRoadReconstruction", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventRoadReconstruction *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventRoadReconstruction", res, nullptr, DefSQDestructorCallback, true); return 1; } +} // namespace SQConvert + +namespace SQConvert { + /* Allow ScriptEventVehicleAutoReplaced to be used as Squirrel parameter */ + template <> inline ScriptEventVehicleAutoReplaced *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleAutoReplaced *)instance; } + template <> inline ScriptEventVehicleAutoReplaced &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleAutoReplaced *)instance; } + template <> inline const ScriptEventVehicleAutoReplaced *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleAutoReplaced *)instance; } + template <> inline const ScriptEventVehicleAutoReplaced &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleAutoReplaced *)instance; } + template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleAutoReplaced *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleAutoReplaced", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_execmode.hpp.sq b/src/script/api/template/template_execmode.hpp.sq index 4c8326bc17..b7030774e0 100644 --- a/src/script/api/template/template_execmode.hpp.sq +++ b/src/script/api/template/template_execmode.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptExecMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptExecMode *)instance; } template <> inline const ScriptExecMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptExecMode *)instance; } template <> inline const ScriptExecMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptExecMode *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptExecMode *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ExecMode", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptExecMode *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ExecMode", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_game.hpp.sq b/src/script/api/template/template_game.hpp.sq index 495aeada41..db30d893e6 100644 --- a/src/script/api/template/template_game.hpp.sq +++ b/src/script/api/template/template_game.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptGame &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGame *)instance; } template <> inline const ScriptGame *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGame *)instance; } template <> inline const ScriptGame &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGame *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptGame *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Game", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptGame *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Game", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_gamesettings.hpp.sq b/src/script/api/template/template_gamesettings.hpp.sq index 9c6e91746c..4882951a14 100644 --- a/src/script/api/template/template_gamesettings.hpp.sq +++ b/src/script/api/template/template_gamesettings.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptGameSettings &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGameSettings *)instance; } template <> inline const ScriptGameSettings *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGameSettings *)instance; } template <> inline const ScriptGameSettings &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGameSettings *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptGameSettings *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "GameSettings", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptGameSettings *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "GameSettings", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_goal.hpp.sq b/src/script/api/template/template_goal.hpp.sq index 6aa3014eea..7b392eca7f 100644 --- a/src/script/api/template/template_goal.hpp.sq +++ b/src/script/api/template/template_goal.hpp.sq @@ -27,5 +27,5 @@ namespace SQConvert { template <> inline ScriptGoal &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGoal *)instance; } template <> inline const ScriptGoal *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGoal *)instance; } template <> inline const ScriptGoal &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGoal *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptGoal *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Goal", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptGoal *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Goal", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_group.hpp.sq b/src/script/api/template/template_group.hpp.sq index ac4abe5a17..0bb83765a3 100644 --- a/src/script/api/template/template_group.hpp.sq +++ b/src/script/api/template/template_group.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroup *)instance; } template <> inline const ScriptGroup *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGroup *)instance; } template <> inline const ScriptGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroup *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptGroup *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Group", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptGroup *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Group", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_grouplist.hpp.sq b/src/script/api/template/template_grouplist.hpp.sq index 858abcf015..8638ef52f5 100644 --- a/src/script/api/template/template_grouplist.hpp.sq +++ b/src/script/api/template/template_grouplist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptGroupList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroupList *)instance; } template <> inline const ScriptGroupList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGroupList *)instance; } template <> inline const ScriptGroupList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroupList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptGroupList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "GroupList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptGroupList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "GroupList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_industry.hpp.sq b/src/script/api/template/template_industry.hpp.sq index e1e02263c6..3b60c0fd3f 100644 --- a/src/script/api/template/template_industry.hpp.sq +++ b/src/script/api/template/template_industry.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptIndustry &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustry *)instance; } template <> inline const ScriptIndustry *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustry *)instance; } template <> inline const ScriptIndustry &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustry *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptIndustry *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Industry", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptIndustry *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Industry", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_industrylist.hpp.sq b/src/script/api/template/template_industrylist.hpp.sq index 0c0316346a..184b42775e 100644 --- a/src/script/api/template/template_industrylist.hpp.sq +++ b/src/script/api/template/template_industrylist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptIndustryList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList *)instance; } template <> inline const ScriptIndustryList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList *)instance; } template <> inline const ScriptIndustryList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,7 +26,7 @@ namespace SQConvert { template <> inline ScriptIndustryList_CargoAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoAccepting *)instance; } template <> inline const ScriptIndustryList_CargoAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList_CargoAccepting *)instance; } template <> inline const ScriptIndustryList_CargoAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoAccepting *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList_CargoAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList_CargoAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList_CargoAccepting *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList_CargoAccepting", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -35,5 +35,5 @@ namespace SQConvert { template <> inline ScriptIndustryList_CargoProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoProducing *)instance; } template <> inline const ScriptIndustryList_CargoProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList_CargoProducing *)instance; } template <> inline const ScriptIndustryList_CargoProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoProducing *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList_CargoProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList_CargoProducing", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList_CargoProducing *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList_CargoProducing", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_industrytype.hpp.sq b/src/script/api/template/template_industrytype.hpp.sq index 79495053ea..dfc735d039 100644 --- a/src/script/api/template/template_industrytype.hpp.sq +++ b/src/script/api/template/template_industrytype.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptIndustryType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryType *)instance; } template <> inline const ScriptIndustryType *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryType *)instance; } template <> inline const ScriptIndustryType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryType *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryType *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryType", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryType *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryType", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_industrytypelist.hpp.sq b/src/script/api/template/template_industrytypelist.hpp.sq index 044f9ccedf..cac1fc0e34 100644 --- a/src/script/api/template/template_industrytypelist.hpp.sq +++ b/src/script/api/template/template_industrytypelist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptIndustryTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryTypeList *)instance; } template <> inline const ScriptIndustryTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryTypeList *)instance; } template <> inline const ScriptIndustryTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryTypeList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryTypeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryTypeList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryTypeList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryTypeList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_infrastructure.hpp.sq b/src/script/api/template/template_infrastructure.hpp.sq index 39460e1406..c2a7b71911 100644 --- a/src/script/api/template/template_infrastructure.hpp.sq +++ b/src/script/api/template/template_infrastructure.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptInfrastructure &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptInfrastructure *)instance; } template <> inline const ScriptInfrastructure *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptInfrastructure *)instance; } template <> inline const ScriptInfrastructure &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptInfrastructure *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptInfrastructure *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Infrastructure", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptInfrastructure *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Infrastructure", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_list.hpp.sq b/src/script/api/template/template_list.hpp.sq index fa8d2b36dc..b16117af34 100644 --- a/src/script/api/template/template_list.hpp.sq +++ b/src/script/api/template/template_list.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptList *)instance; } template <> inline const ScriptList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptList *)instance; } template <> inline const ScriptList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "List", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "List", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_log.hpp.sq b/src/script/api/template/template_log.hpp.sq index 91c0511d0c..fd97373884 100644 --- a/src/script/api/template/template_log.hpp.sq +++ b/src/script/api/template/template_log.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptLog &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptLog *)instance; } template <> inline const ScriptLog *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptLog *)instance; } template <> inline const ScriptLog &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptLog *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptLog *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Log", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptLog *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Log", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_map.hpp.sq b/src/script/api/template/template_map.hpp.sq index 4d34cc734b..980bd7a537 100644 --- a/src/script/api/template/template_map.hpp.sq +++ b/src/script/api/template/template_map.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptMap &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMap *)instance; } template <> inline const ScriptMap *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptMap *)instance; } template <> inline const ScriptMap &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMap *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptMap *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Map", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptMap *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Map", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_marine.hpp.sq b/src/script/api/template/template_marine.hpp.sq index d2415b6994..1dc3eaa33d 100644 --- a/src/script/api/template/template_marine.hpp.sq +++ b/src/script/api/template/template_marine.hpp.sq @@ -23,5 +23,5 @@ namespace SQConvert { template <> inline ScriptMarine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMarine *)instance; } template <> inline const ScriptMarine *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptMarine *)instance; } template <> inline const ScriptMarine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMarine *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptMarine *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Marine", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptMarine *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Marine", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_news.hpp.sq b/src/script/api/template/template_news.hpp.sq index 445a055e10..db65507cca 100644 --- a/src/script/api/template/template_news.hpp.sq +++ b/src/script/api/template/template_news.hpp.sq @@ -23,5 +23,5 @@ namespace SQConvert { template <> inline ScriptNews &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptNews *)instance; } template <> inline const ScriptNews *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptNews *)instance; } template <> inline const ScriptNews &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptNews *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptNews *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "News", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptNews *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "News", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_order.hpp.sq b/src/script/api/template/template_order.hpp.sq index d11fafa14f..39a16e00e9 100644 --- a/src/script/api/template/template_order.hpp.sq +++ b/src/script/api/template/template_order.hpp.sq @@ -31,5 +31,5 @@ namespace SQConvert { template <> inline ScriptOrder &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptOrder *)instance; } template <> inline const ScriptOrder *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptOrder *)instance; } template <> inline const ScriptOrder &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptOrder *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptOrder *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Order", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptOrder *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Order", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_rail.hpp.sq b/src/script/api/template/template_rail.hpp.sq index f92f96d587..3b9c9ce6ae 100644 --- a/src/script/api/template/template_rail.hpp.sq +++ b/src/script/api/template/template_rail.hpp.sq @@ -29,5 +29,5 @@ namespace SQConvert { template <> inline ScriptRail &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRail *)instance; } template <> inline const ScriptRail *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRail *)instance; } template <> inline const ScriptRail &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRail *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptRail *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Rail", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRail *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Rail", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_railtypelist.hpp.sq b/src/script/api/template/template_railtypelist.hpp.sq index 9a768e1d5c..87f9f0e2c9 100644 --- a/src/script/api/template/template_railtypelist.hpp.sq +++ b/src/script/api/template/template_railtypelist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptRailTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRailTypeList *)instance; } template <> inline const ScriptRailTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRailTypeList *)instance; } template <> inline const ScriptRailTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRailTypeList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptRailTypeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "RailTypeList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRailTypeList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "RailTypeList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_road.hpp.sq b/src/script/api/template/template_road.hpp.sq index d50bda573d..26ef7a142e 100644 --- a/src/script/api/template/template_road.hpp.sq +++ b/src/script/api/template/template_road.hpp.sq @@ -17,6 +17,8 @@ namespace SQConvert { template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::RoadType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadType res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptRoad::RoadTramTypes GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadTramTypes)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadTramTypes res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::RoadVehicleType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadVehicleType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadVehicleType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::BuildType)tmp; } @@ -27,5 +29,5 @@ namespace SQConvert { template <> inline ScriptRoad &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoad *)instance; } template <> inline const ScriptRoad *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoad *)instance; } template <> inline const ScriptRoad &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoad *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptRoad *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Road", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRoad *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Road", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_roadtypelist.hpp.sq b/src/script/api/template/template_roadtypelist.hpp.sq new file mode 100644 index 0000000000..5573f8614f --- /dev/null +++ b/src/script/api/template/template_roadtypelist.hpp.sq @@ -0,0 +1,21 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ + +#include "../script_roadtypelist.hpp" + +namespace SQConvert { + /* Allow ScriptRoadTypeList to be used as Squirrel parameter */ + template <> inline ScriptRoadTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoadTypeList *)instance; } + template <> inline ScriptRoadTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoadTypeList *)instance; } + template <> inline const ScriptRoadTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoadTypeList *)instance; } + template <> inline const ScriptRoadTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoadTypeList *)instance; } + template <> inline int Return(HSQUIRRELVM vm, ScriptRoadTypeList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "RoadTypeList", res, nullptr, DefSQDestructorCallback, true); return 1; } +} // namespace SQConvert diff --git a/src/script/api/template/template_sign.hpp.sq b/src/script/api/template/template_sign.hpp.sq index db926fed3f..2441711892 100644 --- a/src/script/api/template/template_sign.hpp.sq +++ b/src/script/api/template/template_sign.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptSign &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSign *)instance; } template <> inline const ScriptSign *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSign *)instance; } template <> inline const ScriptSign &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSign *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptSign *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Sign", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptSign *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Sign", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_signlist.hpp.sq b/src/script/api/template/template_signlist.hpp.sq index e5bd67ae5f..a7c53a6c8d 100644 --- a/src/script/api/template/template_signlist.hpp.sq +++ b/src/script/api/template/template_signlist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptSignList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSignList *)instance; } template <> inline const ScriptSignList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSignList *)instance; } template <> inline const ScriptSignList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSignList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptSignList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "SignList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptSignList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "SignList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_station.hpp.sq b/src/script/api/template/template_station.hpp.sq index 729ae68a6d..3bbd4220e9 100644 --- a/src/script/api/template/template_station.hpp.sq +++ b/src/script/api/template/template_station.hpp.sq @@ -23,5 +23,5 @@ namespace SQConvert { template <> inline ScriptStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStation *)instance; } template <> inline const ScriptStation *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStation *)instance; } template <> inline const ScriptStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStation *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStation *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Station", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStation *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Station", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_stationlist.hpp.sq b/src/script/api/template/template_stationlist.hpp.sq index 5f7bd28129..e13d26b67f 100644 --- a/src/script/api/template/template_stationlist.hpp.sq +++ b/src/script/api/template/template_stationlist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptStationList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList *)instance; } template <> inline const ScriptStationList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList *)instance; } template <> inline const ScriptStationList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -32,7 +32,7 @@ namespace SQConvert { template <> inline ScriptStationList_Cargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Cargo *)instance; } template <> inline const ScriptStationList_Cargo *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_Cargo *)instance; } template <> inline const ScriptStationList_Cargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Cargo *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Cargo *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_Cargo", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Cargo *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_Cargo", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -41,7 +41,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoWaiting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaiting *)instance; } template <> inline const ScriptStationList_CargoWaiting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaiting *)instance; } template <> inline const ScriptStationList_CargoWaiting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaiting *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaiting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaiting", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaiting *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaiting", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -50,7 +50,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoPlanned &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlanned *)instance; } template <> inline const ScriptStationList_CargoPlanned *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlanned *)instance; } template <> inline const ScriptStationList_CargoPlanned &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlanned *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlanned *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlanned", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlanned *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlanned", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -59,7 +59,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoWaitingByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByFrom *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingByFrom *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingByFrom", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -68,7 +68,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoWaitingViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingViaByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingViaByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingViaByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingViaByFrom *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingViaByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingViaByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingViaByFrom *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingViaByFrom", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -77,7 +77,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoWaitingByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByVia *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingByVia", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingByVia *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingByVia", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -86,7 +86,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoWaitingFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingFromByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingFromByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingFromByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingFromByVia *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingFromByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingFromByVia", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingFromByVia *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingFromByVia", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -95,7 +95,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoPlannedByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByFrom *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedByFrom *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedByFrom", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -104,7 +104,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoPlannedViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedViaByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedViaByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedViaByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedViaByFrom *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedViaByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedViaByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedViaByFrom *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedViaByFrom", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -113,7 +113,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoPlannedByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByVia *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedByVia", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedByVia *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedByVia", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -122,7 +122,7 @@ namespace SQConvert { template <> inline ScriptStationList_CargoPlannedFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedFromByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedFromByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedFromByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedFromByVia *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedFromByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedFromByVia", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedFromByVia *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedFromByVia", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -131,5 +131,5 @@ namespace SQConvert { template <> inline ScriptStationList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Vehicle *)instance; } template <> inline const ScriptStationList_Vehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_Vehicle *)instance; } template <> inline const ScriptStationList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Vehicle *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Vehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_Vehicle", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Vehicle *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_Vehicle", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_story_page.hpp.sq b/src/script/api/template/template_story_page.hpp.sq index 4c322a3acf..add3a30e74 100644 --- a/src/script/api/template/template_story_page.hpp.sq +++ b/src/script/api/template/template_story_page.hpp.sq @@ -25,5 +25,5 @@ namespace SQConvert { template <> inline ScriptStoryPage &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPage *)instance; } template <> inline const ScriptStoryPage *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPage *)instance; } template <> inline const ScriptStoryPage &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPage *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPage *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPage", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPage *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPage", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_storypageelementlist.hpp.sq b/src/script/api/template/template_storypageelementlist.hpp.sq index 34d940f928..df7ae6e68e 100644 --- a/src/script/api/template/template_storypageelementlist.hpp.sq +++ b/src/script/api/template/template_storypageelementlist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptStoryPageElementList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageElementList *)instance; } template <> inline const ScriptStoryPageElementList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPageElementList *)instance; } template <> inline const ScriptStoryPageElementList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageElementList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPageElementList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPageElementList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPageElementList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPageElementList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_storypagelist.hpp.sq b/src/script/api/template/template_storypagelist.hpp.sq index 7325969fdc..bb21f83a90 100644 --- a/src/script/api/template/template_storypagelist.hpp.sq +++ b/src/script/api/template/template_storypagelist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptStoryPageList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageList *)instance; } template <> inline const ScriptStoryPageList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPageList *)instance; } template <> inline const ScriptStoryPageList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPageList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPageList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPageList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPageList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_subsidy.hpp.sq b/src/script/api/template/template_subsidy.hpp.sq index 61303a645e..501a2f23ff 100644 --- a/src/script/api/template/template_subsidy.hpp.sq +++ b/src/script/api/template/template_subsidy.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptSubsidy &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidy *)instance; } template <> inline const ScriptSubsidy *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSubsidy *)instance; } template <> inline const ScriptSubsidy &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidy *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidy *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Subsidy", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidy *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Subsidy", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_subsidylist.hpp.sq b/src/script/api/template/template_subsidylist.hpp.sq index 4e6284f4e9..1f3f7b3a12 100644 --- a/src/script/api/template/template_subsidylist.hpp.sq +++ b/src/script/api/template/template_subsidylist.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptSubsidyList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidyList *)instance; } template <> inline const ScriptSubsidyList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSubsidyList *)instance; } template <> inline const ScriptSubsidyList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidyList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidyList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "SubsidyList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidyList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "SubsidyList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_testmode.hpp.sq b/src/script/api/template/template_testmode.hpp.sq index bacafa16e7..5404e80233 100644 --- a/src/script/api/template/template_testmode.hpp.sq +++ b/src/script/api/template/template_testmode.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptTestMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTestMode *)instance; } template <> inline const ScriptTestMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTestMode *)instance; } template <> inline const ScriptTestMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTestMode *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTestMode *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TestMode", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTestMode *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TestMode", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_text.hpp.sq b/src/script/api/template/template_text.hpp.sq index 7a44daf16f..93654c84a3 100644 --- a/src/script/api/template/template_text.hpp.sq +++ b/src/script/api/template/template_text.hpp.sq @@ -25,6 +25,6 @@ namespace SQConvert { if (sq_gettype(vm, index) == OT_STRING) { return new RawText(GetParam(ForceType(), vm, index, ptr)); } - return NULL; + return nullptr; } } // namespace SQConvert diff --git a/src/script/api/template/template_tile.hpp.sq b/src/script/api/template/template_tile.hpp.sq index e78aaa6ace..9271b5ba40 100644 --- a/src/script/api/template/template_tile.hpp.sq +++ b/src/script/api/template/template_tile.hpp.sq @@ -31,5 +31,5 @@ namespace SQConvert { template <> inline ScriptTile &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTile *)instance; } template <> inline const ScriptTile *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTile *)instance; } template <> inline const ScriptTile &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTile *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTile *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Tile", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTile *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Tile", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_tilelist.hpp.sq b/src/script/api/template/template_tilelist.hpp.sq index e3d73a7c85..989e6749e2 100644 --- a/src/script/api/template/template_tilelist.hpp.sq +++ b/src/script/api/template/template_tilelist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptTileList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList *)instance; } template <> inline const ScriptTileList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList *)instance; } template <> inline const ScriptTileList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTileList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTileList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,7 +26,7 @@ namespace SQConvert { template <> inline ScriptTileList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryAccepting *)instance; } template <> inline const ScriptTileList_IndustryAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_IndustryAccepting *)instance; } template <> inline const ScriptTileList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryAccepting *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_IndustryAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_IndustryAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_IndustryAccepting *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_IndustryAccepting", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -35,7 +35,7 @@ namespace SQConvert { template <> inline ScriptTileList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryProducing *)instance; } template <> inline const ScriptTileList_IndustryProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_IndustryProducing *)instance; } template <> inline const ScriptTileList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryProducing *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_IndustryProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_IndustryProducing", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_IndustryProducing *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_IndustryProducing", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -44,5 +44,5 @@ namespace SQConvert { template <> inline ScriptTileList_StationType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_StationType *)instance; } template <> inline const ScriptTileList_StationType *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_StationType *)instance; } template <> inline const ScriptTileList_StationType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_StationType *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_StationType *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_StationType", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_StationType *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_StationType", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_town.hpp.sq b/src/script/api/template/template_town.hpp.sq index 0ec1c285d8..30534fa8a2 100644 --- a/src/script/api/template/template_town.hpp.sq +++ b/src/script/api/template/template_town.hpp.sq @@ -29,5 +29,5 @@ namespace SQConvert { template <> inline ScriptTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTown *)instance; } template <> inline const ScriptTown *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTown *)instance; } template <> inline const ScriptTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTown *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTown *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Town", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTown *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Town", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_townlist.hpp.sq b/src/script/api/template/template_townlist.hpp.sq index 5bbd2e203a..e3709b5b59 100644 --- a/src/script/api/template/template_townlist.hpp.sq +++ b/src/script/api/template/template_townlist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptTownList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownList *)instance; } template <> inline const ScriptTownList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTownList *)instance; } template <> inline const ScriptTownList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTownList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TownList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTownList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TownList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,5 +26,5 @@ namespace SQConvert { template <> inline ScriptTownEffectList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownEffectList *)instance; } template <> inline const ScriptTownEffectList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTownEffectList *)instance; } template <> inline const ScriptTownEffectList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownEffectList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTownEffectList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TownEffectList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTownEffectList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TownEffectList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_tunnel.hpp.sq b/src/script/api/template/template_tunnel.hpp.sq index 2d7eed91e5..b003eae13e 100644 --- a/src/script/api/template/template_tunnel.hpp.sq +++ b/src/script/api/template/template_tunnel.hpp.sq @@ -21,5 +21,5 @@ namespace SQConvert { template <> inline ScriptTunnel &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTunnel *)instance; } template <> inline const ScriptTunnel *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTunnel *)instance; } template <> inline const ScriptTunnel &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTunnel *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptTunnel *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Tunnel", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptTunnel *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Tunnel", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_vehicle.hpp.sq b/src/script/api/template/template_vehicle.hpp.sq index 999a9c5078..d0e2f52b1b 100644 --- a/src/script/api/template/template_vehicle.hpp.sq +++ b/src/script/api/template/template_vehicle.hpp.sq @@ -25,5 +25,5 @@ namespace SQConvert { template <> inline ScriptVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicle *)instance; } template <> inline const ScriptVehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicle *)instance; } template <> inline const ScriptVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicle *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Vehicle", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicle *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Vehicle", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_vehiclelist.hpp.sq b/src/script/api/template/template_vehiclelist.hpp.sq index dd1d17682e..11dac4bc3d 100644 --- a/src/script/api/template/template_vehiclelist.hpp.sq +++ b/src/script/api/template/template_vehiclelist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptVehicleList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList *)instance; } template <> inline const ScriptVehicleList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList *)instance; } template <> inline const ScriptVehicleList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,7 +26,7 @@ namespace SQConvert { template <> inline ScriptVehicleList_Station &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Station *)instance; } template <> inline const ScriptVehicleList_Station *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Station *)instance; } template <> inline const ScriptVehicleList_Station &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Station *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Station *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Station", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Station *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Station", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -35,7 +35,7 @@ namespace SQConvert { template <> inline ScriptVehicleList_Depot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Depot *)instance; } template <> inline const ScriptVehicleList_Depot *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Depot *)instance; } template <> inline const ScriptVehicleList_Depot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Depot *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Depot *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Depot", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Depot *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Depot", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -44,7 +44,7 @@ namespace SQConvert { template <> inline ScriptVehicleList_SharedOrders &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_SharedOrders *)instance; } template <> inline const ScriptVehicleList_SharedOrders *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_SharedOrders *)instance; } template <> inline const ScriptVehicleList_SharedOrders &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_SharedOrders *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_SharedOrders *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_SharedOrders", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_SharedOrders *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_SharedOrders", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -53,7 +53,7 @@ namespace SQConvert { template <> inline ScriptVehicleList_Group &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Group *)instance; } template <> inline const ScriptVehicleList_Group *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Group *)instance; } template <> inline const ScriptVehicleList_Group &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Group *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Group *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Group", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Group *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Group", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -62,5 +62,5 @@ namespace SQConvert { template <> inline ScriptVehicleList_DefaultGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_DefaultGroup *)instance; } template <> inline const ScriptVehicleList_DefaultGroup *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_DefaultGroup *)instance; } template <> inline const ScriptVehicleList_DefaultGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_DefaultGroup *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_DefaultGroup *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_DefaultGroup", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_DefaultGroup *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_DefaultGroup", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_viewport.hpp.sq b/src/script/api/template/template_viewport.hpp.sq index 8a187ae81d..e5b44943bc 100644 --- a/src/script/api/template/template_viewport.hpp.sq +++ b/src/script/api/template/template_viewport.hpp.sq @@ -17,5 +17,5 @@ namespace SQConvert { template <> inline ScriptViewport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptViewport *)instance; } template <> inline const ScriptViewport *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptViewport *)instance; } template <> inline const ScriptViewport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptViewport *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptViewport *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Viewport", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptViewport *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Viewport", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_waypoint.hpp.sq b/src/script/api/template/template_waypoint.hpp.sq index 88cc495c98..613c3cbcc2 100644 --- a/src/script/api/template/template_waypoint.hpp.sq +++ b/src/script/api/template/template_waypoint.hpp.sq @@ -23,5 +23,5 @@ namespace SQConvert { template <> inline ScriptWaypoint &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypoint *)instance; } template <> inline const ScriptWaypoint *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypoint *)instance; } template <> inline const ScriptWaypoint &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypoint *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWaypoint *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Waypoint", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWaypoint *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Waypoint", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_waypointlist.hpp.sq b/src/script/api/template/template_waypointlist.hpp.sq index 2e23bba148..7c2330964d 100644 --- a/src/script/api/template/template_waypointlist.hpp.sq +++ b/src/script/api/template/template_waypointlist.hpp.sq @@ -17,7 +17,7 @@ namespace SQConvert { template <> inline ScriptWaypointList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList *)instance; } template <> inline const ScriptWaypointList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypointList *)instance; } template <> inline const ScriptWaypointList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWaypointList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "WaypointList", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWaypointList *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "WaypointList", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { @@ -26,5 +26,5 @@ namespace SQConvert { template <> inline ScriptWaypointList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList_Vehicle *)instance; } template <> inline const ScriptWaypointList_Vehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypointList_Vehicle *)instance; } template <> inline const ScriptWaypointList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList_Vehicle *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWaypointList_Vehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "WaypointList_Vehicle", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWaypointList_Vehicle *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "WaypointList_Vehicle", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/api/template/template_window.hpp.sq b/src/script/api/template/template_window.hpp.sq index 3077215ec2..c0d3f59deb 100644 --- a/src/script/api/template/template_window.hpp.sq +++ b/src/script/api/template/template_window.hpp.sq @@ -259,5 +259,5 @@ namespace SQConvert { template <> inline ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } template <> inline const ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } template <> inline const ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Window", res, NULL, DefSQDestructorCallback, true); return 1; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Window", res, nullptr, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert diff --git a/src/script/script_config.cpp b/src/script/script_config.cpp index 3171e67d4f..e9b0f69bc6 100644 --- a/src/script/script_config.cpp +++ b/src/script/script_config.cpp @@ -21,17 +21,17 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match, bool is_random) { free(this->name); - this->name = (name == NULL) ? NULL : stredup(name); - this->info = (name == NULL) ? NULL : this->FindInfo(this->name, version, force_exact_match); - this->version = (info == NULL) ? -1 : info->GetVersion(); + this->name = (name == nullptr) ? nullptr : stredup(name); + this->info = (name == nullptr) ? nullptr : this->FindInfo(this->name, version, force_exact_match); + this->version = (info == nullptr) ? -1 : info->GetVersion(); this->is_random = is_random; - if (this->config_list != NULL) delete this->config_list; - this->config_list = (info == NULL) ? NULL : new ScriptConfigItemList(); - if (this->config_list != NULL) this->PushExtraConfigList(); + if (this->config_list != nullptr) delete this->config_list; + this->config_list = (info == nullptr) ? nullptr : new ScriptConfigItemList(); + if (this->config_list != nullptr) this->PushExtraConfigList(); this->ClearConfigList(); - if (_game_mode == GM_NORMAL && this->info != NULL) { + if (_game_mode == GM_NORMAL && this->info != nullptr) { /* If we're in an existing game and the Script is changed, set all settings * for the Script that have the random flag to a random value. */ for (ScriptConfigItemList::const_iterator it = this->info->GetConfigList()->begin(); it != this->info->GetConfigList()->end(); it++) { @@ -45,10 +45,10 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match, ScriptConfig::ScriptConfig(const ScriptConfig *config) { - this->name = (config->name == NULL) ? NULL : stredup(config->name); + this->name = (config->name == nullptr) ? nullptr : stredup(config->name); this->info = config->info; this->version = config->version; - this->config_list = NULL; + this->config_list = nullptr; this->is_random = config->is_random; for (SettingValueList::const_iterator it = config->settings.begin(); it != config->settings.end(); it++) { @@ -61,7 +61,7 @@ ScriptConfig::~ScriptConfig() { free(this->name); this->ResetSettings(); - if (this->config_list != NULL) delete this->config_list; + if (this->config_list != nullptr) delete this->config_list; } ScriptInfo *ScriptConfig::GetInfo() const @@ -71,8 +71,8 @@ ScriptInfo *ScriptConfig::GetInfo() const const ScriptConfigItemList *ScriptConfig::GetConfigList() { - if (this->info != NULL) return this->info->GetConfigList(); - if (this->config_list == NULL) { + if (this->info != nullptr) return this->info->GetConfigList(); + if (this->config_list == nullptr) { this->config_list = new ScriptConfigItemList(); this->PushExtraConfigList(); } @@ -106,10 +106,10 @@ int ScriptConfig::GetSetting(const char *name) const void ScriptConfig::SetSetting(const char *name, int value) { /* You can only set Script specific settings if an Script is selected. */ - if (this->info == NULL) return; + if (this->info == nullptr) return; const ScriptConfigItem *config_item = this->info->GetConfigItem(name); - if (config_item == NULL) return; + if (config_item == nullptr) return; value = Clamp(value, config_item->min_value, config_item->max_value); @@ -140,7 +140,7 @@ void ScriptConfig::AddRandomDeviation() bool ScriptConfig::HasScript() const { - return this->info != NULL; + return this->info != nullptr; } bool ScriptConfig::IsRandom() const @@ -163,18 +163,18 @@ void ScriptConfig::StringToSettings(const char *value) char *value_copy = stredup(value); char *s = value_copy; - while (s != NULL) { + while (s != nullptr) { /* Analyze the string ('name=value,name=value\0') */ char *item_name = s; s = strchr(s, '='); - if (s == NULL) break; + if (s == nullptr) break; if (*s == '\0') break; *s = '\0'; s++; char *item_value = s; s = strchr(s, ','); - if (s != NULL) { + if (s != nullptr) { *s = '\0'; s++; } @@ -209,7 +209,7 @@ void ScriptConfig::SettingsToString(char *string, const char *last) const const char *ScriptConfig::GetTextfile(TextfileType type, CompanyID slot) const { - if (slot == INVALID_COMPANY || this->GetInfo() == NULL) return NULL; + if (slot == INVALID_COMPANY || this->GetInfo() == nullptr) return nullptr; return ::GetTextfile(type, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR, this->GetInfo()->GetMainScript()); } diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index dfc675473c..db04397a75 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -61,10 +61,10 @@ protected: public: ScriptConfig() : - name(NULL), + name(nullptr), version(-1), - info(NULL), - config_list(NULL), + info(nullptr), + config_list(nullptr), is_random(false) {} @@ -139,7 +139,7 @@ public: /** * Randomize all settings the Script requested to be randomized. */ - void AddRandomDeviation(); + virtual void AddRandomDeviation(); /** * Is this config attached to an Script? In other words, is there a Script @@ -178,7 +178,7 @@ public: * Search a textfile file next to this script. * @param type The type of the textfile to search for. * @param slot #CompanyID to check status of. - * @return The filename for the textfile, \c NULL otherwise. + * @return The filename for the textfile, \c nullptr otherwise. */ const char *GetTextfile(TextfileType type, CompanyID slot) const; diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index b95c6e366d..5cab36d0ba 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -25,9 +25,9 @@ ScriptInfo::~ScriptInfo() for (ScriptConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { free((*it).name); free((*it).description); - if (it->labels != NULL) { - for (LabelMapping::iterator it2 = (*it).labels->Begin(); it2 != (*it).labels->End(); it2++) { - free(it2->second); + if (it->labels != nullptr) { + for (auto &lbl_map : *(*it).labels) { + free(lbl_map.second); } delete it->labels; } @@ -85,7 +85,7 @@ bool ScriptInfo::CheckMethod(const char *name) const /* Get location information of the scanner */ info->main_script = stredup(info->scanner->GetMainScript()); const char *tar_name = info->scanner->GetTarFile(); - if (tar_name != NULL) info->tar_file = stredup(tar_name); + if (tar_name != nullptr) info->tar_file = stredup(tar_name); /* Cache the data the info file gives us. */ if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR; @@ -111,7 +111,7 @@ bool ScriptInfo::CheckMethod(const char *name) const bool ScriptInfo::GetSettings() { - return this->engine->CallMethod(*this->SQ_instance, "GetSettings", NULL, MAX_GET_SETTING_OPS); + return this->engine->CallMethod(*this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS); } SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm) @@ -138,8 +138,8 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm) /* Don't allow '=' and ',' in configure setting names, as we need those * 2 chars to nicely store the settings as a string. */ - while ((s = strchr(name, '=')) != NULL) *s = '_'; - while ((s = strchr(name, ',')) != NULL) *s = '_'; + while ((s = strchr(name, '=')) != nullptr) *s = '_'; + while ((s = strchr(name, ',')) != nullptr) *s = '_'; config.name = name; items |= 0x001; } else if (strcmp(key, "description") == 0) { @@ -233,18 +233,18 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm) if (SQ_FAILED(sq_getstring(vm, -2, &setting_name))) return SQ_ERROR; ValidateString(setting_name); - ScriptConfigItem *config = NULL; + ScriptConfigItem *config = nullptr; for (ScriptConfigItemList::iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { if (strcmp((*it).name, setting_name) == 0) config = &(*it); } - if (config == NULL) { + if (config == nullptr) { char error[1024]; seprintf(error, lastof(error), "Trying to add labels for non-defined setting '%s'", setting_name); this->engine->ThrowError(error); return SQ_ERROR; } - if (config->labels != NULL) return SQ_ERROR; + if (config->labels != nullptr) return SQ_ERROR; config->labels = new LabelMapping; @@ -289,7 +289,7 @@ const ScriptConfigItem *ScriptInfo::GetConfigItem(const char *name) const for (ScriptConfigItemList::const_iterator it = this->config_list.begin(); it != this->config_list.end(); it++) { if (strcmp((*it).name, name) == 0) return &(*it); } - return NULL; + return nullptr; } int ScriptInfo::GetSettingDefaultValue(const char *name) const diff --git a/src/script/script_info.hpp b/src/script/script_info.hpp index ae341a7d82..6bcec878ac 100644 --- a/src/script/script_info.hpp +++ b/src/script/script_info.hpp @@ -32,19 +32,19 @@ static const int MAX_GET_SETTING_OPS = 100000; class ScriptInfo : public SimpleCountedObject { public: ScriptInfo() : - engine(NULL), - SQ_instance(NULL), - main_script(NULL), - tar_file(NULL), - author(NULL), - name(NULL), - short_name(NULL), - description(NULL), - date(NULL), - instance_name(NULL), + engine(nullptr), + SQ_instance(nullptr), + main_script(nullptr), + tar_file(nullptr), + author(nullptr), + name(nullptr), + short_name(nullptr), + description(nullptr), + date(nullptr), + instance_name(nullptr), version(0), - url(NULL), - scanner(NULL) + url(nullptr), + scanner(nullptr) {} ~ScriptInfo(); diff --git a/src/script/script_info_dummy.cpp b/src/script/script_info_dummy.cpp index 53860386c1..34e5541e22 100644 --- a/src/script/script_info_dummy.cpp +++ b/src/script/script_info_dummy.cpp @@ -86,11 +86,11 @@ void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type) char *p = safe_error_message; do { newline = strchr(p, '\n'); - if (newline != NULL) *newline = '\0'; + if (newline != nullptr) *newline = '\0'; dp += seprintf(dp, lastof(dummy_script), " %sLog.Error(\"%s\");\n", type, p); p = newline + 1; - } while (newline != NULL); + } while (newline != nullptr); strecpy(dp, " }\n}\n", lastof(dummy_script)); diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index f3830780a4..3468bff446 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -34,8 +34,8 @@ ScriptStorage::~ScriptStorage() { /* Free our pointers */ - if (event_data != NULL) ScriptEventController::FreeEventPointer(); - if (log_data != NULL) ScriptLog::FreeLogPointer(); + if (event_data != nullptr) ScriptEventController::FreeEventPointer(); + if (log_data != nullptr) ScriptLog::FreeLogPointer(); } /** @@ -50,17 +50,17 @@ static void PrintFunc(bool error_msg, const SQChar *message) } ScriptInstance::ScriptInstance(const char *APIName) : - engine(NULL), - versionAPI(NULL), - controller(NULL), - storage(NULL), - instance(NULL), + engine(nullptr), + versionAPI(nullptr), + controller(nullptr), + storage(nullptr), + instance(nullptr), is_started(false), is_dead(false), is_save_data_on_stack(false), suspend(0), is_paused(false), - callback(NULL) + callback(nullptr) { this->storage = new ScriptStorage(); this->engine = new Squirrel(APIName); @@ -95,7 +95,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na return; } ScriptObject::SetAllowDoCommand(true); - } catch (Script_FatalError e) { + } catch (Script_FatalError &e) { this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); @@ -135,8 +135,8 @@ ScriptInstance::~ScriptInstance() { ScriptObject::ActiveInstance active(this); - if (instance != NULL) this->engine->ReleaseObject(this->instance); - if (engine != NULL) delete this->engine; + if (instance != nullptr) this->engine->ReleaseObject(this->instance); + if (engine != nullptr) delete this->engine; delete this->storage; delete this->controller; free(this->instance); @@ -153,10 +153,12 @@ void ScriptInstance::Died() DEBUG(script, 0, "The script died unexpectedly."); this->is_dead = true; - if (this->instance != NULL) this->engine->ReleaseObject(this->instance); + this->last_allocated_memory = this->GetAllocatedMemory(); // Update cache + + if (this->instance != nullptr) this->engine->ReleaseObject(this->instance); delete this->engine; - this->instance = NULL; - this->engine = NULL; + this->instance = nullptr; + this->engine = nullptr; } void ScriptInstance::GameLoop() @@ -179,14 +181,14 @@ void ScriptInstance::GameLoop() _current_company = ScriptObject::GetCompany(); /* If there is a callback to call, call that first */ - if (this->callback != NULL) { + if (this->callback != nullptr) { if (this->is_save_data_on_stack) { sq_poptop(this->engine->GetVM()); this->is_save_data_on_stack = false; } try { this->callback(this); - } catch (Script_Suspend e) { + } catch (Script_Suspend &e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); @@ -195,7 +197,7 @@ void ScriptInstance::GameLoop() } this->suspend = 0; - this->callback = NULL; + this->callback = nullptr; if (!this->is_started) { try { @@ -216,10 +218,10 @@ void ScriptInstance::GameLoop() ScriptObject::SetAllowDoCommand(true); /* Start the script by calling Start() */ if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died(); - } catch (Script_Suspend e) { + } catch (Script_Suspend &e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); - } catch (Script_FatalError e) { + } catch (Script_FatalError &e) { this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); @@ -237,10 +239,10 @@ void ScriptInstance::GameLoop() /* Continue the VM */ try { if (!this->engine->Resume(_settings_game.script.script_max_opcode_till_suspend)) this->Died(); - } catch (Script_Suspend e) { + } catch (Script_Suspend &e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); - } catch (Script_FatalError e) { + } catch (Script_FatalError &e) { this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); @@ -351,7 +353,7 @@ static const SaveLoad _script_byte[] = { case OT_INTEGER: { if (!test) { _script_sl_byte = SQSL_INT; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } SQInteger res; sq_getinteger(vm, index, &res); @@ -365,7 +367,7 @@ static const SaveLoad _script_byte[] = { case OT_STRING: { if (!test) { _script_sl_byte = SQSL_STRING; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } const SQChar *buf; sq_getstring(vm, index, &buf); @@ -376,7 +378,7 @@ static const SaveLoad _script_byte[] = { } if (!test) { _script_sl_byte = (byte)len; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); SlArray(const_cast(buf), len, SLE_CHAR); } return true; @@ -385,7 +387,7 @@ static const SaveLoad _script_byte[] = { case OT_ARRAY: { if (!test) { _script_sl_byte = SQSL_ARRAY; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { @@ -400,7 +402,7 @@ static const SaveLoad _script_byte[] = { sq_pop(vm, 1); if (!test) { _script_sl_byte = SQSL_ARRAY_TABLE_END; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } return true; } @@ -408,7 +410,7 @@ static const SaveLoad _script_byte[] = { case OT_TABLE: { if (!test) { _script_sl_byte = SQSL_TABLE; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { @@ -423,7 +425,7 @@ static const SaveLoad _script_byte[] = { sq_pop(vm, 1); if (!test) { _script_sl_byte = SQSL_ARRAY_TABLE_END; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } return true; } @@ -431,13 +433,13 @@ static const SaveLoad _script_byte[] = { case OT_BOOL: { if (!test) { _script_sl_byte = SQSL_BOOL; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } SQBool res; sq_getbool(vm, index, &res); if (!test) { _script_sl_byte = res ? 1 : 0; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } return true; } @@ -445,7 +447,7 @@ static const SaveLoad _script_byte[] = { case OT_NULL: { if (!test) { _script_sl_byte = SQSL_NULL; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } return true; } @@ -459,7 +461,7 @@ static const SaveLoad _script_byte[] = { /* static */ void ScriptInstance::SaveEmpty() { _script_sl_byte = 0; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } void ScriptInstance::Save() @@ -467,7 +469,7 @@ void ScriptInstance::Save() ScriptObject::ActiveInstance active(this); /* Don't save data if the script didn't start yet or if it crashed. */ - if (this->engine == NULL || this->engine->HasScriptCrashed()) { + if (this->engine == nullptr || this->engine->HasScriptCrashed()) { SaveEmpty(); return; } @@ -475,7 +477,7 @@ void ScriptInstance::Save() HSQUIRRELVM vm = this->engine->GetVM(); if (this->is_save_data_on_stack) { _script_sl_byte = 1; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); /* Save the data that was just loaded. */ SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false); } else if (!this->is_started) { @@ -494,7 +496,7 @@ void ScriptInstance::Save() this->engine->CrashOccurred(); return; } - } catch (Script_FatalError e) { + } catch (Script_FatalError &e) { /* If we don't mark the script as dead here cleaning up the squirrel * stack could throw Script_FatalError again. */ this->is_dead = true; @@ -518,7 +520,7 @@ void ScriptInstance::Save() sq_pushobject(vm, savedata); if (SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, true)) { _script_sl_byte = 1; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false); this->is_save_data_on_stack = true; } else { @@ -528,7 +530,7 @@ void ScriptInstance::Save() } else { ScriptLog::Warning("Save function is not implemented"); _script_sl_byte = 0; - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); } } @@ -553,50 +555,50 @@ bool ScriptInstance::IsPaused() /* static */ bool ScriptInstance::LoadObjects(HSQUIRRELVM vm) { - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); switch (_script_sl_byte) { case SQSL_INT: { int value; SlArray(&value, 1, SLE_INT32); - if (vm != NULL) sq_pushinteger(vm, (SQInteger)value); + if (vm != nullptr) sq_pushinteger(vm, (SQInteger)value); return true; } case SQSL_STRING: { - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); static char buf[256]; SlArray(buf, _script_sl_byte, SLE_CHAR); - if (vm != NULL) sq_pushstring(vm, buf, -1); + if (vm != nullptr) sq_pushstring(vm, buf, -1); return true; } case SQSL_ARRAY: { - if (vm != NULL) sq_newarray(vm, 0); + if (vm != nullptr) sq_newarray(vm, 0); while (LoadObjects(vm)) { - if (vm != NULL) sq_arrayappend(vm, -2); + if (vm != nullptr) sq_arrayappend(vm, -2); /* The value is popped from the stack by squirrel. */ } return true; } case SQSL_TABLE: { - if (vm != NULL) sq_newtable(vm); + if (vm != nullptr) sq_newtable(vm); while (LoadObjects(vm)) { LoadObjects(vm); - if (vm != NULL) sq_rawset(vm, -3); + if (vm != nullptr) sq_rawset(vm, -3); /* The key (-2) and value (-1) are popped from the stack by squirrel. */ } return true; } case SQSL_BOOL: { - SlObject(NULL, _script_byte); - if (vm != NULL) sq_pushbool(vm, (SQBool)(_script_sl_byte != 0)); + SlObject(nullptr, _script_byte); + if (vm != nullptr) sq_pushbool(vm, (SQBool)(_script_sl_byte != 0)); return true; } case SQSL_NULL: { - if (vm != NULL) sq_pushnull(vm); + if (vm != nullptr) sq_pushnull(vm); return true; } @@ -610,24 +612,24 @@ bool ScriptInstance::IsPaused() /* static */ void ScriptInstance::LoadEmpty() { - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); /* Check if there was anything saved at all. */ if (_script_sl_byte == 0) return; - LoadObjects(NULL); + LoadObjects(nullptr); } void ScriptInstance::Load(int version) { ScriptObject::ActiveInstance active(this); - if (this->engine == NULL || version == -1) { + if (this->engine == nullptr || version == -1) { LoadEmpty(); return; } HSQUIRRELVM vm = this->engine->GetVM(); - SlObject(NULL, _script_byte); + SlObject(nullptr, _script_byte); /* Check if there was anything saved at all. */ if (_script_sl_byte == 0) return; @@ -707,3 +709,9 @@ void ScriptInstance::InsertEvent(class ScriptEvent *event) ScriptEventController::InsertEvent(event); } + +size_t ScriptInstance::GetAllocatedMemory() const +{ + if (this->engine == nullptr) return this->last_allocated_memory; + return this->engine->GetAllocatedMemory(); +} diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp index 4fbf677a86..dc5b28dfbb 100644 --- a/src/script/script_instance.hpp +++ b/src/script/script_instance.hpp @@ -52,7 +52,7 @@ public: * Find a library. * @param library The library name to find. * @param version The version the library should have. - * @return The library if found, NULL otherwise. + * @return The library if found, nullptr otherwise. */ virtual class ScriptInfo *FindLibrary(const char *library, int version) = 0; @@ -200,6 +200,8 @@ public: */ bool IsSleeping() { return this->suspend != 0; } + size_t GetAllocatedMemory() const; + protected: class Squirrel *engine; ///< A wrapper around the squirrel vm. const char *versionAPI; ///< Current API used by this script. @@ -243,6 +245,7 @@ private: int suspend; ///< The amount of ticks to suspend this script before it's allowed to continue. bool is_paused; ///< Is the script paused? (a paused script will not be executed until unpaused) Script_SuspendCallbackProc *callback; ///< Callback that should be called in the next tick the script runs. + size_t last_allocated_memory; ///< Last known allocated memory value (for display for crashed scripts) /** * Call the script Load function if it exists and data was loaded diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index fe6d41cf92..c4205bbc45 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -17,12 +17,11 @@ #include "../script/squirrel.hpp" #include "script_scanner.hpp" #include "script_info.hpp" +#include "script_fatalerror.hpp" -#if defined(ENABLE_NETWORK) #include "../network/network_content.h" #include "../3rdparty/md5/md5.h" #include "../tar_type.h" -#endif /* ENABLE_NETWORK */ #include "../safeguards.h" @@ -30,19 +29,19 @@ bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const { free(this->main_script); this->main_script = stredup(filename); - if (this->main_script == NULL) return false; + if (this->main_script == nullptr) return false; free(this->tar_file); - if (tar_filename != NULL) { + if (tar_filename != nullptr) { this->tar_file = stredup(tar_filename); - if (this->tar_file == NULL) return false; + if (this->tar_file == nullptr) return false; } else { - this->tar_file = NULL; + this->tar_file = nullptr; } const char *end = this->main_script + strlen(this->main_script) + 1; char *p = strrchr(this->main_script, PATHSEPCHAR); - if (p == NULL) { + if (p == nullptr) { p = this->main_script; } else { /* Skip over the path separator character. We don't need that. */ @@ -54,15 +53,19 @@ bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const if (!FioCheckFileExists(filename, this->subdir) || !FioCheckFileExists(this->main_script, this->subdir)) return false; this->ResetEngine(); - this->engine->LoadScript(filename); - + try { + this->engine->LoadScript(filename); + } catch (Script_FatalError &e) { + DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage(), filename); + return false; + } return true; } ScriptScanner::ScriptScanner() : - engine(NULL), - main_script(NULL), - tar_file(NULL) + engine(nullptr), + main_script(nullptr), + tar_file(nullptr) { } @@ -180,8 +183,6 @@ char *ScriptScanner::GetConsoleList(char *p, const char *last, bool newest_only) return p; } -#if defined(ENABLE_NETWORK) - /** Helper for creating a MD5sum of all files within of a script. */ struct ScriptFileChecksumCreator : FileScanner { byte md5sum[16]; ///< The final md5sum. @@ -207,7 +208,7 @@ struct ScriptFileChecksumCreator : FileScanner { /* Open the file ... */ FILE *f = FioFOpenFile(filename, "rb", this->dir, &size); - if (f == NULL) return false; + if (f == nullptr) return false; /* ... calculate md5sum... */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { @@ -245,7 +246,7 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S ScriptFileChecksumCreator checksum(dir); const char *tar_filename = info->GetTarFile(); TarList::iterator iter; - if (tar_filename != NULL && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) { + if (tar_filename != nullptr && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) { /* The main script is in a tar file, so find all files that * are in the same tar and add them to the MD5 checksumming. */ TarFileList::iterator tar; @@ -255,7 +256,7 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S /* Check the extension. */ const char *ext = strrchr(tar->first.c_str(), '.'); - if (ext == NULL || strcasecmp(ext, ".nut") != 0) continue; + if (ext == nullptr || strcasecmp(ext, ".nut") != 0) continue; checksum.AddFile(tar->first.c_str(), 0, tar_filename); } @@ -285,7 +286,5 @@ const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum) for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) { if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return (*it).second->GetMainScript(); } - return NULL; + return nullptr; } - -#endif /* ENABLE_NETWORK */ diff --git a/src/script/script_scanner.hpp b/src/script/script_scanner.hpp index 50dad02ad2..3627d251bb 100644 --- a/src/script/script_scanner.hpp +++ b/src/script/script_scanner.hpp @@ -73,11 +73,11 @@ public: * Find a script of a #ContentInfo * @param ci The information to compare to. * @param md5sum Whether to check the MD5 checksum. - * @return A filename of a file of the content, else \c NULL. + * @return A filename of a file of the content, else \c nullptr. */ const char *FindMainScript(const ContentInfo *ci, bool md5sum); - /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); + bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; /** * Rescan the script dir. diff --git a/src/script/script_storage.hpp b/src/script/script_storage.hpp index 3fd8a95f73..d06cc9efa0 100644 --- a/src/script/script_storage.hpp +++ b/src/script/script_storage.hpp @@ -68,8 +68,8 @@ private: public: ScriptStorage() : - mode (NULL), - mode_instance (NULL), + mode (nullptr), + mode_instance (nullptr), root_company (INVALID_OWNER), company (INVALID_OWNER), delay (1), @@ -91,8 +91,8 @@ public: /* calback_value (can't be set) */ road_type (INVALID_ROADTYPE), rail_type (INVALID_RAILTYPE), - event_data (NULL), - log_data (NULL) + event_data (nullptr), + log_data (nullptr) { } ~ScriptStorage(); diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 23163f6b34..275a89c74c 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -10,17 +10,128 @@ /** @file squirrel.cpp the implementation of the Squirrel class. It handles all Squirrel-stuff and gives a nice API back to work with. */ #include +#include #include "../stdafx.h" #include "../debug.h" #include "squirrel_std.hpp" #include "../fileio_func.h" #include "../string_func.h" +#include "script_fatalerror.hpp" +#include "../settings_type.h" #include #include <../squirrel/sqpcheader.h> #include <../squirrel/sqvm.h> +#include "../core/alloc_func.hpp" #include "../safeguards.h" +/* + * If changing the call paths into the scripting engine, define this symbol to enable full debugging of allocations. + * This lets you track whether the allocator context is being switched correctly in all call paths. +#define SCRIPT_DEBUG_ALLOCATIONS +*/ + +struct ScriptAllocator { + size_t allocated_size; ///< Sum of allocated data size + size_t allocation_limit; ///< Maximum this allocator may use before allocations fail + + static const size_t SAFE_LIMIT = 0x8000000; ///< 128 MiB, a safe choice for almost any situation + +#ifdef SCRIPT_DEBUG_ALLOCATIONS + std::map allocations; +#endif + + void CheckLimit() const + { + if (this->allocated_size > this->allocation_limit) throw Script_FatalError("Maximum memory allocation exceeded"); + } + + void *Malloc(SQUnsignedInteger size) + { + void *p = MallocT(size); + this->allocated_size += size; + +#ifdef SCRIPT_DEBUG_ALLOCATIONS + assert(p != nullptr); + assert(this->allocations.find(p) == this->allocations.end()); + this->allocations[p] = size; +#endif + + return p; + } + + void *Realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size) + { + if (p == nullptr) { + return this->Malloc(size); + } + if (size == 0) { + this->Free(p, oldsize); + return nullptr; + } + +#ifdef SCRIPT_DEBUG_ALLOCATIONS + assert(this->allocations[p] == oldsize); + this->allocations.erase(p); +#endif + + void *new_p = ReallocT(static_cast(p), size); + + this->allocated_size -= oldsize; + this->allocated_size += size; + +#ifdef SCRIPT_DEBUG_ALLOCATIONS + assert(new_p != nullptr); + assert(this->allocations.find(p) == this->allocations.end()); + this->allocations[new_p] = size; +#endif + + return new_p; + } + + void Free(void *p, SQUnsignedInteger size) + { + if (p == nullptr) return; + free(p); + this->allocated_size -= size; + +#ifdef SCRIPT_DEBUG_ALLOCATIONS + assert(this->allocations.at(p) == size); + this->allocations.erase(p); +#endif + } + + ScriptAllocator() + { + this->allocated_size = 0; + this->allocation_limit = static_cast(_settings_game.script.script_max_memory_megabytes) << 20; + if (this->allocation_limit == 0) this->allocation_limit = SAFE_LIMIT; // in case the setting is somehow zero + } + + ~ScriptAllocator() + { +#ifdef SCRIPT_DEBUG_ALLOCATIONS + assert(this->allocations.size() == 0); +#endif + } +}; + +ScriptAllocator *_squirrel_allocator = nullptr; + +/* See 3rdparty/squirrel/squirrel/sqmem.cpp for the default allocator implementation, which this overrides */ +#ifndef SQUIRREL_DEFAULT_ALLOCATOR +void *sq_vm_malloc(SQUnsignedInteger size) { return _squirrel_allocator->Malloc(size); } +void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size) { return _squirrel_allocator->Realloc(p, oldsize, size); } +void sq_vm_free(void *p, SQUnsignedInteger size) { _squirrel_allocator->Free(p, size); } +#endif + +size_t Squirrel::GetAllocatedMemory() const noexcept +{ + assert(this->allocator != nullptr); + return this->allocator->allocated_size; +} + + void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column) { SQChar buf[1024]; @@ -31,7 +142,7 @@ void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *so Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); engine->crashed = true; SQPrintFunc *func = engine->print_func; - if (func == NULL) { + if (func == nullptr) { DEBUG(misc, 0, "[Squirrel] Compile error: %s", buf); } else { (*func)(true, buf); @@ -49,7 +160,7 @@ void Squirrel::ErrorPrintFunc(HSQUIRRELVM vm, const SQChar *s, ...) /* Check if we have a custom print function */ SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func; - if (func == NULL) { + if (func == nullptr) { fprintf(stderr, "%s", buf); } else { (*func)(true, buf); @@ -67,7 +178,7 @@ void Squirrel::RunError(HSQUIRRELVM vm, const SQChar *error) seprintf(buf, lastof(buf), "Your script made an error: %s\n", error); Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); SQPrintFunc *func = engine->print_func; - if (func == NULL) { + if (func == nullptr) { fprintf(stderr, "%s", buf); } else { (*func)(true, buf); @@ -106,7 +217,7 @@ void Squirrel::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...) /* Check if we have a custom print function */ SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func; - if (func == NULL) { + if (func == nullptr) { printf("%s", buf); } else { (*func)(false, buf); @@ -115,6 +226,8 @@ void Squirrel::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...) void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params, void *userdata, int size) { + ScriptAllocatorScope alloc_scope(this); + sq_pushstring(this->vm, method_name, -1); if (size != 0) { @@ -130,6 +243,8 @@ void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, void Squirrel::AddConst(const char *var_name, int value) { + ScriptAllocatorScope alloc_scope(this); + sq_pushstring(this->vm, var_name, -1); sq_pushinteger(this->vm, value); sq_newslot(this->vm, -3, SQTrue); @@ -137,6 +252,8 @@ void Squirrel::AddConst(const char *var_name, int value) void Squirrel::AddConst(const char *var_name, bool value) { + ScriptAllocatorScope alloc_scope(this); + sq_pushstring(this->vm, var_name, -1); sq_pushbool(this->vm, value); sq_newslot(this->vm, -3, SQTrue); @@ -144,6 +261,8 @@ void Squirrel::AddConst(const char *var_name, bool value) void Squirrel::AddClassBegin(const char *class_name) { + ScriptAllocatorScope alloc_scope(this); + sq_pushroottable(this->vm); sq_pushstring(this->vm, class_name, -1); sq_newclass(this->vm, SQFalse); @@ -151,6 +270,8 @@ void Squirrel::AddClassBegin(const char *class_name) void Squirrel::AddClassBegin(const char *class_name, const char *parent_class) { + ScriptAllocatorScope alloc_scope(this); + sq_pushroottable(this->vm); sq_pushstring(this->vm, class_name, -1); sq_pushstring(this->vm, parent_class, -1); @@ -164,6 +285,8 @@ void Squirrel::AddClassBegin(const char *class_name, const char *parent_class) void Squirrel::AddClassEnd() { + ScriptAllocatorScope alloc_scope(this); + sq_newslot(vm, -3, SQFalse); sq_pop(vm, 1); } @@ -171,6 +294,8 @@ void Squirrel::AddClassEnd() bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name) { assert(!this->crashed); + ScriptAllocatorScope alloc_scope(this); + int top = sq_gettop(this->vm); /* Go to the instance-root */ sq_pushobject(this->vm, instance); @@ -187,6 +312,8 @@ bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name) bool Squirrel::Resume(int suspend) { assert(!this->crashed); + ScriptAllocatorScope alloc_scope(this); + /* Did we use more operations than we should have in the * previous tick? If so, subtract that from the current run. */ if (this->overdrawn_ops > 0 && suspend > 0) { @@ -200,23 +327,29 @@ bool Squirrel::Resume(int suspend) this->crashed = !sq_resumecatch(this->vm, suspend); this->overdrawn_ops = -this->vm->_ops_till_suspend; + this->allocator->CheckLimit(); return this->vm->_suspended != 0; } void Squirrel::ResumeError() { assert(!this->crashed); + ScriptAllocatorScope alloc_scope(this); sq_resumeerror(this->vm); } void Squirrel::CollectGarbage() { + ScriptAllocatorScope alloc_scope(this); sq_collectgarbage(this->vm); } bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend) { assert(!this->crashed); + ScriptAllocatorScope alloc_scope(this); + this->allocator->CheckLimit(); + /* Store the stack-location for the return value. We need to * restore this after saving or the stack will be corrupted * if we're in the middle of a DoCommand. */ @@ -234,8 +367,8 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT } /* Call the method */ sq_pushobject(this->vm, instance); - if (SQ_FAILED(sq_call(this->vm, 1, ret == NULL ? SQFalse : SQTrue, SQTrue, suspend))) return false; - if (ret != NULL) sq_getstackobj(vm, -1, ret); + if (SQ_FAILED(sq_call(this->vm, 1, ret == nullptr ? SQFalse : SQTrue, SQTrue, suspend))) return false; + if (ret != nullptr) sq_getstackobj(vm, -1, ret); /* Reset the top, but don't do so for the script main function, as we need * a correct stack when resuming. */ if (suspend == -1 || !this->IsSuspended()) sq_settop(this->vm, top); @@ -305,7 +438,7 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool return false; } - if (instance != NULL) { + if (instance != nullptr) { /* Find our instance */ sq_getstackobj(vm, -1, instance); /* Add a reference to it, so it survives for ever */ @@ -316,28 +449,31 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool /* Store it in the class */ sq_setinstanceup(vm, -1, real_instance); - if (release_hook != NULL) sq_setreleasehook(vm, -1, release_hook); + if (release_hook != nullptr) sq_setreleasehook(vm, -1, release_hook); - if (instance != NULL) sq_settop(vm, oldtop); + if (instance != nullptr) sq_settop(vm, oldtop); return true; } bool Squirrel::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance) { - return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, NULL); + ScriptAllocatorScope alloc_scope(this); + return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, nullptr); } Squirrel::Squirrel(const char *APIName) : - APIName(APIName) + APIName(APIName), allocator(new ScriptAllocator()) { this->Initialize(); } void Squirrel::Initialize() { - this->global_pointer = NULL; - this->print_func = NULL; + ScriptAllocatorScope alloc_scope(this); + + this->global_pointer = nullptr; + this->print_func = nullptr; this->crashed = false; this->overdrawn_ops = 0; this->vm = sq_open(1024); @@ -432,19 +568,21 @@ static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror) { + ScriptAllocatorScope alloc_scope(this); + FILE *file; size_t size; if (strncmp(this->GetAPIName(), "AI", 2) == 0) { file = FioFOpenFile(filename, "rb", AI_DIR, &size); - if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size); + if (file == nullptr) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size); } else if (strncmp(this->GetAPIName(), "GS", 2) == 0) { file = FioFOpenFile(filename, "rb", GAME_DIR, &size); - if (file == NULL) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size); + if (file == nullptr) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size); } else { NOT_REACHED(); } - if (file == NULL) { + if (file == nullptr) { return sq_throwerror(vm, "cannot open the file"); } unsigned short bom = 0; @@ -517,6 +655,8 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root) { + ScriptAllocatorScope alloc_scope(this); + /* Make sure we are always in the root-table */ if (in_root) sq_pushroottable(vm); @@ -549,6 +689,8 @@ Squirrel::~Squirrel() void Squirrel::Uninitialize() { + ScriptAllocatorScope alloc_scope(this); + /* Clean up the stuff */ sq_pop(this->vm, 1); sq_close(this->vm); @@ -562,6 +704,8 @@ void Squirrel::Reset() void Squirrel::InsertResult(bool result) { + ScriptAllocatorScope alloc_scope(this); + sq_pushbool(this->vm, result); if (this->IsSuspended()) { // Called before resuming a suspended script? vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1); @@ -571,6 +715,8 @@ void Squirrel::InsertResult(bool result) void Squirrel::InsertResult(int result) { + ScriptAllocatorScope alloc_scope(this); + sq_pushinteger(this->vm, result); if (this->IsSuspended()) { // Called before resuming a suspended script? vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1); @@ -600,6 +746,7 @@ void Squirrel::CrashOccurred() bool Squirrel::CanSuspend() { + ScriptAllocatorScope alloc_scope(this); return sq_can_suspend(this->vm); } diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index 9e1d113a80..d0d02e80f8 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -20,16 +20,21 @@ enum ScriptType { ST_GS, ///< The script is for Game scripts. }; +struct ScriptAllocator; + class Squirrel { + friend class ScriptAllocatorScope; + private: typedef void (SQPrintFunc)(bool error_msg, const SQChar *message); HSQUIRRELVM vm; ///< The VirtualMachine instance for squirrel void *global_pointer; ///< Can be set by who ever initializes Squirrel - SQPrintFunc *print_func; ///< Points to either NULL, or a custom print handler + SQPrintFunc *print_func; ///< Points to either nullptr, or a custom print handler bool crashed; ///< True if the squirrel script made an error. int overdrawn_ops; ///< The amount of operations we have overdrawn. const char *APIName; ///< Name of the API used for this squirrel. + std::unique_ptr allocator; ///< Allocator object used by this script. /** * The internal RunError handler. It looks up the real error and calls RunError with it. @@ -93,7 +98,7 @@ public: * Adds a function to the stack. Depending on the current state this means * either a method or a global function. */ - void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam = 0, const char *params = NULL, void *userdata = NULL, int size = 0); + void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam = 0, const char *params = nullptr, void *userdata = nullptr, int size = 0); /** * Adds a const to the stack. Depending on the current state this means @@ -155,7 +160,7 @@ public: * @return False if the script crashed or returned a wrong type. */ bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend); - bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, NULL, suspend); } + bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); } bool CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend); bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend); bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend); @@ -272,6 +277,31 @@ public: * Completely reset the engine; start from scratch. */ void Reset(); + + /** + * Get number of bytes allocated by this VM. + */ + size_t GetAllocatedMemory() const noexcept; +}; + + +extern ScriptAllocator *_squirrel_allocator; + +class ScriptAllocatorScope { + ScriptAllocator *old_allocator; + +public: + ScriptAllocatorScope(const Squirrel *engine) + { + this->old_allocator = _squirrel_allocator; + /* This may get called with a nullptr engine, in case of a crashed script */ + _squirrel_allocator = engine != nullptr ? engine->allocator.get() : nullptr; + } + + ~ScriptAllocatorScope() + { + _squirrel_allocator = this->old_allocator; + } }; #endif /* SQUIRREL_HPP */ diff --git a/src/script/squirrel_class.hpp b/src/script/squirrel_class.hpp index ce63e3b034..8ec3f9dc72 100644 --- a/src/script/squirrel_class.hpp +++ b/src/script/squirrel_class.hpp @@ -35,7 +35,7 @@ public: void DefSQMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; - engine->AddMethod(function_name, DefSQNonStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); + engine->AddMethod(function_name, DefSQNonStaticCallback, 0, nullptr, &function_proc, sizeof(function_proc)); } /** @@ -45,7 +45,7 @@ public: void DefSQAdvancedMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; - engine->AddMethod(function_name, DefSQAdvancedNonStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); + engine->AddMethod(function_name, DefSQAdvancedNonStaticCallback, 0, nullptr, &function_proc, sizeof(function_proc)); } /** @@ -68,7 +68,7 @@ public: void DefSQStaticMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; - engine->AddMethod(function_name, DefSQStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); + engine->AddMethod(function_name, DefSQStaticCallback, 0, nullptr, &function_proc, sizeof(function_proc)); } /** @@ -78,7 +78,7 @@ public: void DefSQAdvancedStaticMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; - engine->AddMethod(function_name, DefSQAdvancedStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); + engine->AddMethod(function_name, DefSQAdvancedStaticCallback, 0, nullptr, &function_proc, sizeof(function_proc)); } /** @@ -120,7 +120,7 @@ public: void AddSQAdvancedConstructor(Squirrel *engine) { using namespace SQConvert; - engine->AddMethod("constructor", DefSQAdvancedConstructorCallback, 0, NULL); + engine->AddMethod("constructor", DefSQAdvancedConstructorCallback, 0, nullptr); } void PostRegister(Squirrel *engine) diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index 22d738d4f7..0f094a80cf 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -29,10 +29,10 @@ namespace SQConvert { * comes out of scope. Useful to make sure you can use stredup(), * without leaking memory. */ - struct SQAutoFreePointers : SmallVector { + struct SQAutoFreePointers : std::vector { ~SQAutoFreePointers() { - for (uint i = 0; i < this->items; i++) free(this->data[i]); + for (void * p : *this) free(p); } }; @@ -88,8 +88,8 @@ namespace SQConvert { template <> inline int Return (HSQUIRRELVM vm, int64 res) { sq_pushinteger(vm, res); return 1; } template <> inline int Return (HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } template <> inline int Return (HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, char *res) { if (res == NULL) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } - template <> inline int Return(HSQUIRRELVM vm, const char *res) { if (res == NULL) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } + template <> inline int Return (HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } + template <> inline int Return(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } template <> inline int Return (HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } template <> inline int Return (HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } @@ -117,7 +117,7 @@ namespace SQConvert { sq_getstring(vm, -1, &tmp); char *tmp_str = stredup(tmp); sq_poptop(vm); - *ptr->Append() = (void *)tmp_str; + ptr->push_back((void *)tmp_str); str_validate(tmp_str, tmp_str + strlen(tmp_str)); return tmp_str; } @@ -132,12 +132,12 @@ namespace SQConvert { sq_pushobject(vm, obj); sq_pushnull(vm); - SmallVector data; + std::vector data; while (SQ_SUCCEEDED(sq_next(vm, -2))) { SQInteger tmp; if (SQ_SUCCEEDED(sq_getinteger(vm, -1, &tmp))) { - *data.Append() = (int32)tmp; + data.push_back((int32)tmp); } else { sq_pop(vm, 4); throw sq_throwerror(vm, "a member of an array used as parameter to a function is not numeric"); @@ -147,11 +147,11 @@ namespace SQConvert { } sq_pop(vm, 2); - Array *arr = (Array*)MallocT(sizeof(Array) + sizeof(int32) * data.Length()); - arr->size = data.Length(); - memcpy(arr->array, data.Begin(), sizeof(int32) * data.Length()); + Array *arr = (Array*)MallocT(sizeof(Array) + sizeof(int32) * data.size()); + arr->size = data.size(); + memcpy(arr->array, data.data(), sizeof(int32) * data.size()); - *ptr->Append() = arr; + ptr->push_back(arr); return arr; } @@ -739,8 +739,8 @@ namespace SQConvert { { /* Find the amount of params we got */ int nparam = sq_gettop(vm); - SQUserPointer ptr = NULL; - SQUserPointer real_instance = NULL; + SQUserPointer ptr = nullptr; + SQUserPointer real_instance = nullptr; HSQOBJECT instance; /* Get the 'SQ' instance of this class */ @@ -759,14 +759,14 @@ namespace SQConvert { sq_getinstanceup(vm, 1, &real_instance, 0); /* Get the real function pointer */ sq_getuserdata(vm, nparam, &ptr, 0); - if (real_instance == NULL) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call"); + if (real_instance == nullptr) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call"); /* Remove the userdata from the stack */ sq_pop(vm, 1); try { /* Delegate it to a template that can handle this specific function */ return HelperT::SQCall((Tcls *)real_instance, *(Tmethod *)ptr, vm); - } catch (SQInteger e) { + } catch (SQInteger &e) { return e; } } @@ -781,8 +781,8 @@ namespace SQConvert { { /* Find the amount of params we got */ int nparam = sq_gettop(vm); - SQUserPointer ptr = NULL; - SQUserPointer real_instance = NULL; + SQUserPointer ptr = nullptr; + SQUserPointer real_instance = nullptr; HSQOBJECT instance; /* Get the 'SQ' instance of this class */ @@ -801,7 +801,7 @@ namespace SQConvert { sq_getinstanceup(vm, 1, &real_instance, 0); /* Get the real function pointer */ sq_getuserdata(vm, nparam, &ptr, 0); - if (real_instance == NULL) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call"); + if (real_instance == nullptr) return sq_throwerror(vm, "couldn't detect real instance of class for non-static call"); /* Remove the userdata from the stack */ sq_pop(vm, 1); @@ -819,15 +819,15 @@ namespace SQConvert { { /* Find the amount of params we got */ int nparam = sq_gettop(vm); - SQUserPointer ptr = NULL; + SQUserPointer ptr = nullptr; /* Get the real function pointer */ sq_getuserdata(vm, nparam, &ptr, 0); try { /* Delegate it to a template that can handle this specific function */ - return HelperT::SQCall((Tcls *)NULL, *(Tmethod *)ptr, vm); - } catch (SQInteger e) { + return HelperT::SQCall((Tcls *)nullptr, *(Tmethod *)ptr, vm); + } catch (SQInteger &e) { return e; } } @@ -843,7 +843,7 @@ namespace SQConvert { { /* Find the amount of params we got */ int nparam = sq_gettop(vm); - SQUserPointer ptr = NULL; + SQUserPointer ptr = nullptr; /* Get the real function pointer */ sq_getuserdata(vm, nparam, &ptr, 0); @@ -862,7 +862,7 @@ namespace SQConvert { static SQInteger DefSQDestructorCallback(SQUserPointer p, SQInteger size) { /* Remove the real instance too */ - if (p != NULL) ((Tcls *)p)->Release(); + if (p != nullptr) ((Tcls *)p)->Release(); return 0; } @@ -876,12 +876,12 @@ namespace SQConvert { { try { /* Create the real instance */ - Tcls *instance = HelperT::SQConstruct((Tcls *)NULL, (Tmethod)NULL, vm); + Tcls *instance = HelperT::SQConstruct((Tcls *)nullptr, (Tmethod)nullptr, vm); sq_setinstanceup(vm, -Tnparam, instance); sq_setreleasehook(vm, -Tnparam, DefSQDestructorCallback); instance->AddRef(); return 0; - } catch (SQInteger e) { + } catch (SQInteger &e) { return e; } } @@ -903,7 +903,7 @@ namespace SQConvert { sq_setreleasehook(vm, -nparam, DefSQDestructorCallback); instance->AddRef(); return 0; - } catch (SQInteger e) { + } catch (SQInteger &e) { return e; } } diff --git a/src/script/squirrel_helper_type.hpp b/src/script/squirrel_helper_type.hpp index 946a59547a..a42cd79a93 100644 --- a/src/script/squirrel_helper_type.hpp +++ b/src/script/squirrel_helper_type.hpp @@ -14,7 +14,7 @@ /** Definition of a simple array. */ struct Array { - int32 size; ///< The size of the array. + size_t size; ///< The size of the array. int32 array[]; ///< The data of the array. }; diff --git a/src/script/squirrel_std.cpp b/src/script/squirrel_std.cpp index 96f087a2a7..715b989340 100644 --- a/src/script/squirrel_std.cpp +++ b/src/script/squirrel_std.cpp @@ -51,7 +51,7 @@ SQInteger SquirrelStd::require(HSQUIRRELVM vm) /* Get the script-name of the current file, so we can work relative from it */ SQStackInfos si; sq_stackinfos(vm, 1, &si); - if (si.source == NULL) { + if (si.source == nullptr) { DEBUG(misc, 0, "[squirrel] Couldn't detect the script-name of the 'require'-caller; this should never happen!"); return SQ_ERROR; } @@ -60,7 +60,7 @@ SQInteger SquirrelStd::require(HSQUIRRELVM vm) strecpy(path, si.source, lastof(path)); /* Keep the dir, remove the rest */ SQChar *s = strrchr(path, PATHSEPCHAR); - if (s != NULL) { + if (s != nullptr) { /* Keep the PATHSEPCHAR there, remove the rest */ s++; *s = '\0'; diff --git a/src/settings.cpp b/src/settings.cpp index b93f4d7066..296b3abcfc 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -39,7 +39,7 @@ #include "sound_func.h" #include "company_func.h" #include "rev.h" -#ifdef WITH_FREETYPE +#if defined(WITH_FREETYPE) || defined(_WIN32) #include "fontcache.h" #endif #include "textbuf_gui.h" @@ -68,6 +68,10 @@ #include "void_map.h" #include "station_base.h" +#if defined(WITH_FREETYPE) || defined(_WIN32) +#define HAS_TRUETYPE_FONT +#endif + #include "table/strings.h" #include "table/settings.h" @@ -84,7 +88,7 @@ static ErrorList _settings_error_list; ///< Errors while loading minimal setting typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object); -typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList *list); +typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList &list); static bool IsSignedVarMemType(VarType vt); @@ -96,7 +100,7 @@ static const char * const _list_group_names[] = { "newgrf", "servers", "server_bind_addresses", - NULL + nullptr }; /** @@ -114,7 +118,7 @@ static size_t LookupOneOfMany(const char *many, const char *one, size_t onelen = if (onelen == 0) onelen = strlen(one); /* check if it's an integer */ - if (*one >= '0' && *one <= '9') return strtoul(one, NULL, 0); + if (*one >= '0' && *one <= '9') return strtoul(one, nullptr, 0); idx = 0; for (;;) { @@ -218,7 +222,7 @@ static bool LoadIntList(const char *str, void *array, int nelems, VarType type) int items[64]; int i, nitems; - if (str == NULL) { + if (str == nullptr) { memset(items, 0, sizeof(items)); nitems = nelems; } else { @@ -348,7 +352,7 @@ static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 */ static const void *StringToVal(const SettingDescBase *desc, const char *orig_str) { - const char *str = orig_str == NULL ? "" : orig_str; + const char *str = orig_str == nullptr ? "" : orig_str; switch (desc->cmd) { case SDT_NUMX: { @@ -373,7 +377,7 @@ static const void *StringToVal(const SettingDescBase *desc, const char *orig_str size_t r = LookupOneOfMany(desc->many, str); /* if the first attempt of conversion from string to the appropriate value fails, * look if we have defined a converter from old value to new value. */ - if (r == (size_t)-1 && desc->proc_cnvt != NULL) r = desc->proc_cnvt(str); + if (r == (size_t)-1 && desc->proc_cnvt != nullptr) r = desc->proc_cnvt(str); if (r != (size_t)-1) return (void*)r; // and here goes converted value ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); @@ -409,7 +413,7 @@ static const void *StringToVal(const SettingDescBase *desc, const char *orig_str default: break; } - return NULL; + return nullptr; } /** @@ -448,13 +452,30 @@ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) case SLE_VAR_U16: case SLE_VAR_I32: { /* Override the minimum value. No value below sdb->min, except special value 0 */ - if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) val = Clamp(val, sdb->min, sdb->max); + if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) { + if (!(sdb->flags & SGF_MULTISTRING)) { + /* Clamp value-type setting to its valid range */ + val = Clamp(val, sdb->min, sdb->max); + } else if (val < sdb->min || val > (int32)sdb->max) { + /* Reset invalid discrete setting (where different values change gameplay) to its default value */ + val = (int32)(size_t)sdb->def; + } + } break; } case SLE_VAR_U32: { /* Override the minimum value. No value below sdb->min, except special value 0 */ - uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min; - WriteValue(ptr, SLE_VAR_U32, (int64)ClampU(val, min, sdb->max)); + uint32 uval = (uint32)val; + if (!(sdb->flags & SGF_0ISDISABLED) || uval != 0) { + if (!(sdb->flags & SGF_MULTISTRING)) { + /* Clamp value-type setting to its valid range */ + uval = ClampU(uval, sdb->min, sdb->max); + } else if (uval < (uint)sdb->min || uval > sdb->max) { + /* Reset invalid discrete setting to its default value */ + uval = (uint32)(size_t)sdb->def; + } + } + WriteValue(ptr, SLE_VAR_U32, (int64)uval); return; } case SLE_VAR_I64: @@ -491,7 +512,7 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp /* For settings.xx.yy load the settings from [xx] yy = ? */ s = strchr(sdb->name, '.'); - if (s != NULL) { + if (s != nullptr) { group = ini->GetGroup(sdb->name, s - sdb->name); s++; } else { @@ -500,19 +521,19 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp } item = group->GetItem(s, false); - if (item == NULL && group != group_def) { + if (item == nullptr && group != group_def) { /* For settings.xx.yy load the settings from [settingss] yy = ? in case the previous * did not exist (e.g. loading old config files with a [settings] section */ item = group_def->GetItem(s, false); } - if (item == NULL) { + if (item == nullptr) { /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous * did not exist (e.g. loading old config files with a [yapf] section */ const char *sc = strchr(s, '.'); - if (sc != NULL) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false); + if (sc != nullptr) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false); } - p = (item == NULL) ? sdb->def : StringToVal(sdb, item->value); + p = (item == nullptr) ? sdb->def : StringToVal(sdb, item->value); ptr = GetVariableAddress(object, sld); switch (sdb->cmd) { @@ -527,16 +548,16 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp switch (GetVarMemType(sld->conv)) { case SLE_VAR_STRB: case SLE_VAR_STRBQ: - if (p != NULL) strecpy((char*)ptr, (const char*)p, (char*)ptr + sld->length - 1); + if (p != nullptr) strecpy((char*)ptr, (const char*)p, (char*)ptr + sld->length - 1); break; case SLE_VAR_STR: case SLE_VAR_STRQ: free(*(char**)ptr); - *(char**)ptr = p == NULL ? NULL : stredup((const char*)p); + *(char**)ptr = p == nullptr ? nullptr : stredup((const char*)p); break; - case SLE_VAR_CHAR: if (p != NULL) *(char *)ptr = *(const char *)p; break; + case SLE_VAR_CHAR: if (p != nullptr) *(char *)ptr = *(const char *)p; break; default: NOT_REACHED(); } @@ -550,7 +571,7 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp /* Use default */ LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); - } else if (sd->desc.proc_cnvt != NULL) { + } else if (sd->desc.proc_cnvt != nullptr) { sd->desc.proc_cnvt((const char*)p); } break; @@ -574,7 +595,7 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp */ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) { - IniGroup *group_def = NULL, *group; + IniGroup *group_def = nullptr, *group; IniItem *item; char buf[512]; const char *s; @@ -591,11 +612,11 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp /* XXX - wtf is this?? (group override?) */ s = strchr(sdb->name, '.'); - if (s != NULL) { + if (s != nullptr) { group = ini->GetGroup(sdb->name, s - sdb->name); s++; } else { - if (group_def == NULL) group_def = ini->GetGroup(grpname); + if (group_def == nullptr) group_def = ini->GetGroup(grpname); s = sdb->name; group = group_def; } @@ -603,7 +624,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp item = group->GetItem(s, true); ptr = GetVariableAddress(object, sld); - if (item->value != NULL) { + if (item->value != nullptr) { /* check if the value is the same as the old value */ const void *p = StringToVal(sdb, item->value); @@ -616,7 +637,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp case SDT_MANYOFMANY: switch (GetVarMemType(sld->conv)) { case SLE_VAR_BL: - if (*(bool*)ptr == (p != NULL)) continue; + if (*(bool*)ptr == (p != nullptr)) continue; break; case SLE_VAR_I8: @@ -667,7 +688,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp case SLE_VAR_STR: strecpy(buf, *(char**)ptr, lastof(buf)); break; case SLE_VAR_STRQ: - if (*(char**)ptr == NULL) { + if (*(char**)ptr == nullptr) { buf[0] = '\0'; } else { seprintf(buf, lastof(buf), "\"%s\"", *(char**)ptr); @@ -694,44 +715,44 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp /** * Loads all items from a 'grpname' section into a list - * The list parameter can be a NULL pointer, in this case nothing will be + * The list parameter can be a nullptr pointer, in this case nothing will be * saved and a callback function should be defined that will take over the * list-handling and store the data itself somewhere. * @param ini IniFile handle to the ini file with the source data * @param grpname character string identifying the section-header of the ini file that will be parsed * @param list new list with entries of the given section */ -static void IniLoadSettingList(IniFile *ini, const char *grpname, StringList *list) +static void IniLoadSettingList(IniFile *ini, const char *grpname, StringList &list) { IniGroup *group = ini->GetGroup(grpname); - if (group == NULL || list == NULL) return; + if (group == nullptr) return; - list->Clear(); + list.clear(); - for (const IniItem *item = group->item; item != NULL; item = item->next) { - if (item->name != NULL) *list->Append() = stredup(item->name); + for (const IniItem *item = group->item; item != nullptr; item = item->next) { + if (item->name != nullptr) list.emplace_back(item->name); } } /** * Saves all items from a list into the 'grpname' section - * The list parameter can be a NULL pointer, in this case a callback function + * The list parameter can be a nullptr pointer, in this case a callback function * should be defined that will provide the source data to be saved. * @param ini IniFile handle to the ini file where the destination data is saved * @param grpname character string identifying the section-header of the ini file * @param list pointer to an string(pointer) array that will be used as the * source to be saved into the relevant ini section */ -static void IniSaveSettingList(IniFile *ini, const char *grpname, StringList *list) +static void IniSaveSettingList(IniFile *ini, const char *grpname, StringList &list) { IniGroup *group = ini->GetGroup(grpname); - if (group == NULL || list == NULL) return; + if (group == nullptr) return; group->Clear(); - for (char **iter = list->Begin(); iter != list->End(); iter++) { - group->GetItem(*iter, true)->SetValue(""); + for (const auto &iter : list) { + group->GetItem(iter.c_str(), true)->SetValue(""); } } @@ -788,7 +809,7 @@ SettingType SettingDesc::GetType() const /** Reposition the main toolbar as the setting changed. */ static bool v_PositionMainToolbar(int32 p1) { - if (_game_mode != GM_MENU) PositionMainToolbar(NULL); + if (_game_mode != GM_MENU) PositionMainToolbar(nullptr); return true; } @@ -796,9 +817,9 @@ static bool v_PositionMainToolbar(int32 p1) static bool v_PositionStatusbar(int32 p1) { if (_game_mode != GM_MENU) { - PositionStatusbar(NULL); - PositionNewsMessage(NULL); - PositionNetworkChatWindow(NULL); + PositionStatusbar(nullptr); + PositionNewsMessage(nullptr); + PositionNetworkChatWindow(nullptr); } return true; } @@ -1302,7 +1323,8 @@ static bool ChangeMaxHeightLevel(int32 p1) static bool StationCatchmentChanged(int32 p1) { - Station::RecomputeIndustriesNearForAll(); + Station::RecomputeCatchmentForAll(); + MarkWholeScreenDirty(); return true; } @@ -1322,9 +1344,6 @@ static bool InvalidateShipPathCache(int32 p1) return true; } - -#ifdef ENABLE_NETWORK - static bool UpdateClientName(int32 p1) { NetworkUpdateClientName(); @@ -1356,9 +1375,6 @@ static bool UpdateClientConfigValues(int32 p1) return true; } -#endif /* ENABLE_NETWORK */ - - /* End - Callback Functions */ /** @@ -1405,14 +1421,14 @@ static void AILoadConfig(IniFile *ini, const char *grpname) /* Clean any configured AI */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(NULL); + AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(nullptr); } /* If no group exists, return */ - if (group == NULL) return; + if (group == nullptr) return; CompanyID c = COMPANY_FIRST; - for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) { + for (item = group->item; c < MAX_COMPANIES && item != nullptr; c++, item = item->next) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); config->Change(item->name); @@ -1422,7 +1438,7 @@ static void AILoadConfig(IniFile *ini, const char *grpname) continue; } } - if (item->value != NULL) config->StringToSettings(item->value); + if (item->value != nullptr) config->StringToSettings(item->value); } } @@ -1432,13 +1448,13 @@ static void GameLoadConfig(IniFile *ini, const char *grpname) IniItem *item; /* Clean any configured GameScript */ - GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(NULL); + GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(nullptr); /* If no group exists, return */ - if (group == NULL) return; + if (group == nullptr) return; item = group->item; - if (item == NULL) return; + if (item == nullptr) return; GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); @@ -1449,7 +1465,7 @@ static void GameLoadConfig(IniFile *ini, const char *grpname) return; } } - if (item->value != NULL) config->StringToSettings(item->value); + if (item->value != nullptr) config->StringToSettings(item->value); } /** @@ -1496,13 +1512,13 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati { IniGroup *group = ini->GetGroup(grpname); IniItem *item; - GRFConfig *first = NULL; + GRFConfig *first = nullptr; GRFConfig **curr = &first; - if (group == NULL) return NULL; + if (group == nullptr) return nullptr; - for (item = group->item; item != NULL; item = item->next) { - GRFConfig *c = NULL; + for (item = group->item; item != nullptr; item = item->next) { + GRFConfig *c = nullptr; uint8 grfid_buf[4], md5sum[16]; char *filename = item->name; @@ -1519,14 +1535,14 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati uint32 grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24); if (has_md5sum) { const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, md5sum); - if (s != NULL) c = new GRFConfig(*s); + if (s != nullptr) c = new GRFConfig(*s); } - if (c == NULL && !FioCheckFileExists(filename, NEWGRF_DIR)) { + if (c == nullptr && !FioCheckFileExists(filename, NEWGRF_DIR)) { const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID); - if (s != NULL) c = new GRFConfig(*s); + if (s != nullptr) c = new GRFConfig(*s); } } - if (c == NULL) c = new GRFConfig(filename); + if (c == nullptr) c = new GRFConfig(filename); /* Parse parameters */ if (!StrEmpty(item->value)) { @@ -1561,7 +1577,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati /* Check for duplicate GRFID (will also check for duplicate filenames) */ bool duplicate = false; - for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) { + for (const GRFConfig *gc = first; gc != nullptr; gc = gc->next) { if (gc->ident.grfid == c->ident.grfid) { SetDParamStr(0, c->filename); SetDParamStr(1, gc->filename); @@ -1590,7 +1606,7 @@ static void AISaveConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini->GetGroup(grpname); - if (group == NULL) return; + if (group == nullptr) return; group->Clear(); for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { @@ -1614,7 +1630,7 @@ static void GameSaveConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini->GetGroup(grpname); - if (group == NULL) return; + if (group == nullptr) return; group->Clear(); GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); @@ -1660,7 +1676,7 @@ static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *li IniGroup *group = ini->GetGroup(grpname); const GRFConfig *c; - for (c = list; c != NULL; c = c->next) { + for (c = list; c != nullptr; c = c->next) { /* Hex grfid (4 bytes in nibbles), "|", hex md5sum (16 bytes in nibbles), "|", file system path. */ char key[4 * 2 + 1 + 16 * 2 + 1 + MAX_PATH]; char params[512]; @@ -1677,9 +1693,9 @@ static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *li static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool basic_settings = true, bool other_settings = true) { if (basic_settings) { - proc(ini, (const SettingDesc*)_misc_settings, "misc", NULL); + proc(ini, (const SettingDesc*)_misc_settings, "misc", nullptr); #if defined(_WIN32) && !defined(DEDICATED) - proc(ini, (const SettingDesc*)_win32_settings, "win32", NULL); + proc(ini, (const SettingDesc*)_win32_settings, "win32", nullptr); #endif /* _WIN32 */ } @@ -1688,11 +1704,9 @@ static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescP proc(ini, _currency_settings,"currency", &_custom_currency); proc(ini, _company_settings, "company", &_settings_client.company); -#ifdef ENABLE_NETWORK - proc_list(ini, "server_bind_addresses", &_network_bind_list); - proc_list(ini, "servers", &_network_host_list); - proc_list(ini, "bans", &_network_ban_list); -#endif /* ENABLE_NETWORK */ + proc_list(ini, "server_bind_addresses", _network_bind_list); + proc_list(ini, "servers", _network_host_list); + proc_list(ini, "bans", _network_ban_list); } } @@ -1727,10 +1741,10 @@ void LoadFromConfig(bool minimal) ValidateSettings(); - /* Display sheduled errors */ + /* Display scheduled errors */ extern void ScheduleErrorMessage(ErrorList &datas); ScheduleErrorMessage(_settings_error_list); - if (FindWindowById(WC_ERRMSG, 0) == NULL) ShowFirstError(); + if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError(); } delete ini; @@ -1758,21 +1772,20 @@ void SaveToConfig() /** * Get the list of known NewGrf presets. - * @param[in,out] list Pointer to list for storing the preset names. + * @returns List of preset names. */ -void GetGRFPresetList(GRFPresetList *list) +StringList GetGRFPresetList() { - list->Clear(); + StringList list; - IniFile *ini = IniLoadConfig(); - IniGroup *group; - for (group = ini->group; group != NULL; group = group->next) { + std::unique_ptr ini(IniLoadConfig()); + for (IniGroup *group = ini->group; group != nullptr; group = group->next) { if (strncmp(group->name, "preset-", 7) == 0) { - *list->Append() = stredup(group->name + 7); + list.emplace_back(group->name + 7); } } - delete ini; + return list; } /** @@ -1830,7 +1843,7 @@ void DeleteGRFPresetFromConfig(const char *config_name) const SettingDesc *GetSettingDescription(uint index) { - if (index >= lengthof(_settings)) return NULL; + if (index >= lengthof(_settings)) return nullptr; return &_settings[index]; } @@ -1849,7 +1862,7 @@ CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uin { const SettingDesc *sd = GetSettingDescription(p1); - if (sd == NULL) return CMD_ERROR; + if (sd == nullptr) return CMD_ERROR; if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR; if (!sd->IsEditable(true)) return CMD_ERROR; @@ -1865,7 +1878,7 @@ CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (oldval == newval) return CommandCost(); - if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { + if (sd->desc.proc != nullptr && !sd->desc.proc(newval)) { WriteValue(var, sd->save.conv, (int64)oldval); return CommandCost(); } @@ -1908,7 +1921,7 @@ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 if (oldval == newval) return CommandCost(); - if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { + if (sd->desc.proc != nullptr && !sd->desc.proc(newval)) { WriteValue(var, sd->save.conv, (int64)oldval); return CommandCost(); } @@ -1941,7 +1954,7 @@ bool SetSettingValue(uint index, int32 value, bool force_newgame) void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); Write_ValidateSetting(var2, sd, value); } - if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); + if (sd->desc.proc != nullptr) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); SetWindowClassesDirty(WC_GAME_OPTIONS); @@ -1975,7 +1988,7 @@ void SetCompanySetting(uint index, int32 value) } else { void *var = GetVariableAddress(&_settings_client.company, &sd->save); Write_ValidateSetting(var, sd, value); - if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); + if (sd->desc.proc != nullptr) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); } } @@ -1992,7 +2005,6 @@ void SetDefaultCompanySettings(CompanyID cid) } } -#if defined(ENABLE_NETWORK) /** * Sync all company settings in a multiplayer game. */ @@ -2005,10 +2017,9 @@ void SyncCompanySettings() const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); - if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company); + if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, nullptr, nullptr, _local_company); } } -#endif /* ENABLE_NETWORK */ /** * Get the index in the _company_settings array of a setting @@ -2019,7 +2030,7 @@ uint GetCompanySettingIndex(const char *name) { uint i; const SettingDesc *sd = GetSettingFromName(name, &i); - assert(sd != NULL && (sd->desc.flags & SGF_PER_COMPANY) != 0); + assert(sd != nullptr && (sd->desc.flags & SGF_PER_COMPANY) != 0); return i; } @@ -2038,12 +2049,12 @@ bool SetSettingValue(uint index, const char *value, bool force_newgame) if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) { char **var = (char**)GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); free(*var); - *var = strcmp(value, "(null)") == 0 ? NULL : stredup(value); + *var = strcmp(value, "(null)") == 0 ? nullptr : stredup(value); } else { - char *var = (char*)GetVariableAddress(NULL, &sd->save); + char *var = (char*)GetVariableAddress(nullptr, &sd->save); strecpy(var, value, &var[sd->save.length - 1]); } - if (sd->desc.proc != NULL) sd->desc.proc(0); + if (sd->desc.proc != nullptr) sd->desc.proc(0); return true; } @@ -2053,7 +2064,7 @@ bool SetSettingValue(uint index, const char *value, bool force_newgame) * @param name Name of the setting to return a setting description of * @param i Pointer to an integer that will contain the index of the setting after the call, if it is successful. * @return Pointer to the setting description of setting \a name if it can be found, - * \c NULL indicates failure to obtain the description + * \c nullptr indicates failure to obtain the description */ const SettingDesc *GetSettingFromName(const char *name, uint *i) { @@ -2069,7 +2080,7 @@ const SettingDesc *GetSettingFromName(const char *name, uint *i) for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; const char *short_name = strchr(sd->desc.name, '.'); - if (short_name != NULL) { + if (short_name != nullptr) { short_name++; if (strcmp(short_name, name) == 0) return sd; } @@ -2082,7 +2093,7 @@ const SettingDesc *GetSettingFromName(const char *name, uint *i) if (strcmp(sd->desc.name, name) == 0) return sd; } - return NULL; + return nullptr; } /* Those 2 functions need to be here, else we have to make some stuff non-static @@ -2092,7 +2103,7 @@ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) uint index; const SettingDesc *sd = GetSettingFromName(name, &index); - if (sd == NULL) { + if (sd == nullptr) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } @@ -2125,7 +2136,7 @@ void IConsoleSetSetting(const char *name, int value) { uint index; const SettingDesc *sd = GetSettingFromName(name, &index); - assert(sd != NULL); + assert(sd != nullptr); SetSettingValue(index, value); } @@ -2141,7 +2152,7 @@ void IConsoleGetSetting(const char *name, bool force_newgame) const SettingDesc *sd = GetSettingFromName(name, &index); const void *ptr; - if (sd == NULL) { + if (sd == nullptr) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } @@ -2165,7 +2176,7 @@ void IConsoleGetSetting(const char *name, bool force_newgame) /** * List all settings and their value to the console * - * @param prefilter If not \c NULL, only list settings with names that begin with \a prefilter prefix + * @param prefilter If not \c nullptr, only list settings with names that begin with \a prefilter prefix */ void IConsoleListSettings(const char *prefilter) { @@ -2173,7 +2184,7 @@ void IConsoleListSettings(const char *prefilter) for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) { if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - if (prefilter != NULL && strstr(sd->desc.name, prefilter) == NULL) continue; + if (prefilter != nullptr && strstr(sd->desc.name, prefilter) == nullptr) continue; char value[80]; const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); @@ -2193,7 +2204,7 @@ void IConsoleListSettings(const char *prefilter) /** * Save and load handler for settings * @param osd SettingDesc struct containing all information - * @param object can be either NULL in which case we load global variables or + * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ static void LoadSettings(const SettingDesc *osd, void *object) @@ -2210,7 +2221,7 @@ static void LoadSettings(const SettingDesc *osd, void *object) /** * Save and load handler for settings * @param sd SettingDesc struct containing all information - * @param object can be either NULL in which case we load global variables or + * @param object can be either nullptr in which case we load global variables or * a pointer to a struct which is getting saved */ static void SaveSettings(const SettingDesc *sd, void *object) @@ -2258,21 +2269,9 @@ static void Save_PATS() SaveSettings(_settings, &_settings_game); } -void CheckConfig() -{ - /* - * Increase old default values for pf_maxdepth and pf_maxlength - * to support big networks. - */ - if (_settings_newgame.pf.opf.pf_maxdepth == 16 && _settings_newgame.pf.opf.pf_maxlength == 512) { - _settings_newgame.pf.opf.pf_maxdepth = 48; - _settings_newgame.pf.opf.pf_maxlength = 4096; - } -} - extern const ChunkHandler _setting_chunk_handlers[] = { - { 'OPTS', NULL, Load_OPTS, NULL, NULL, CH_RIFF}, - { 'PATS', Save_PATS, Load_PATS, NULL, Check_PATS, CH_RIFF | CH_LAST}, + { 'OPTS', nullptr, Load_OPTS, nullptr, nullptr, CH_RIFF}, + { 'PATS', Save_PATS, Load_PATS, nullptr, Check_PATS, CH_RIFF | CH_LAST}, }; static bool IsSignedVarMemType(VarType vt) diff --git a/src/settings_func.h b/src/settings_func.h index 3b3387b5fd..e75fd2b332 100644 --- a/src/settings_func.h +++ b/src/settings_func.h @@ -14,6 +14,7 @@ #include "core/smallvec_type.hpp" #include "company_type.h" +#include "string_type.h" struct IniFile; @@ -24,16 +25,11 @@ void IConsoleListSettings(const char *prefilter); void LoadFromConfig(bool minimal = false); void SaveToConfig(); -void CheckConfig(); void IniLoadWindowSettings(IniFile *ini, const char *grpname, void *desc); void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc); -/* Functions to load and save NewGRF settings to a separate - * configuration file, used for presets. */ -typedef AutoFreeSmallVector GRFPresetList; - -void GetGRFPresetList(GRFPresetList *list); +StringList GetGRFPresetList(); struct GRFConfig *LoadGRFPresetFromConfig(const char *config_name); void SaveGRFPresetToConfig(const char *config_name, struct GRFConfig *config); void DeleteGRFPresetFromConfig(const char *config_name); @@ -41,10 +37,6 @@ void DeleteGRFPresetFromConfig(const char *config_name); uint GetCompanySettingIndex(const char *name); void SetDefaultCompanySettings(CompanyID cid); -#if defined(ENABLE_NETWORK) void SyncCompanySettings(); -#else /* ENABLE_NETWORK */ -static inline void SyncCompanySettings() {} -#endif /* ENABLE_NETWORK */ #endif /* SETTINGS_FUNC_H */ diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 7670a3eb3f..acea219fb8 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -75,7 +75,7 @@ static const StringID _font_zoom_dropdown[] = { }; int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; ///< Number of original town names. -static StringID *_grf_names = NULL; ///< Pointer to town names defined by NewGRFs. +static StringID *_grf_names = nullptr; ///< Pointer to town names defined by NewGRFs. static int _nb_grf_names = 0; ///< Number of town names defined by NewGRFs. static Dimension _circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. @@ -106,17 +106,14 @@ static inline StringID TownName(int town_name) /** * Get index of the current screen resolution. - * @return Index of the current screen resolution if it is a known resolution, #_num_resolutions otherwise. + * @return Index of the current screen resolution if it is a known resolution, _resolutions.size() otherwise. */ -static int GetCurRes() +static uint GetCurRes() { - int i; + uint i; - for (i = 0; i != _num_resolutions; i++) { - if ((int)_resolutions[i].width == _screen.width && - (int)_resolutions[i].height == _screen.height) { - break; - } + for (i = 0; i != _resolutions.size(); i++) { + if (_resolutions[i] == Dimension(_screen.width, _screen.height)) break; } return i; } @@ -124,20 +121,20 @@ static int GetCurRes() static void ShowCustCurrency(); template -static DropDownList *BuildSetDropDownList(int *selected_index, bool allow_selection) +static DropDownList BuildSetDropDownList(int *selected_index, bool allow_selection) { int n = T::GetNumSets(); *selected_index = T::GetIndexOfUsedSet(); - DropDownList *list = new DropDownList(); + DropDownList list; for (int i = 0; i < n; i++) { - *list->Append() = new DropDownListCharStringItem(T::GetSet(i)->name, i, !allow_selection && (*selected_index != i)); + list.emplace_back(new DropDownListCharStringItem(T::GetSet(i)->name, i, !allow_selection && (*selected_index != i))); } return list; } -DropDownList *BuildMusicSetDropDownList(int *selected_index) +DropDownList BuildMusicSetDropDownList(int *selected_index) { return BuildSetDropDownList(selected_index, true); } @@ -154,7 +151,7 @@ struct BaseSetTextfileWindow : public TextfileWindow { this->LoadTextfile(textfile, BASESET_DIR); } - /* virtual */ void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_TF_CAPTION) { SetDParam(0, content_type); @@ -200,14 +197,13 @@ struct GameOptionsWindow : Window { * Build the dropdown list for a specific widget. * @param widget Widget to build list for * @param selected_index Currently selected item - * @return the built dropdown list, or NULL if the widget has no dropdown menu. + * @return the built dropdown list, or nullptr if the widget has no dropdown menu. */ - DropDownList *BuildDropDownList(int widget, int *selected_index) const + DropDownList BuildDropDownList(int widget, int *selected_index) const { - DropDownList *list = NULL; + DropDownList list; switch (widget) { case WID_GO_CURRENCY_DROPDOWN: { // Setup currencies dropdown - list = new DropDownList(); *selected_index = this->opt->locale.currency; StringID *items = BuildCurrencyDropdown(); uint64 disabled = _game_mode == GM_MENU ? 0LL : ~GetMaskOfAllowedCurrencies(); @@ -215,18 +211,17 @@ struct GameOptionsWindow : Window { /* Add non-custom currencies; sorted naturally */ for (uint i = 0; i < CURRENCY_END; items++, i++) { if (i == CURRENCY_CUSTOM) continue; - *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); + list.emplace_back(new DropDownListStringItem(*items, i, HasBit(disabled, i))); } - QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); + std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc); /* Append custom currency at the end */ - *list->Append() = new DropDownListItem(-1, false); // separator line - *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, CURRENCY_CUSTOM, HasBit(disabled, CURRENCY_CUSTOM)); + list.emplace_back(new DropDownListItem(-1, false)); // separator line + list.emplace_back(new DropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, CURRENCY_CUSTOM, HasBit(disabled, CURRENCY_CUSTOM))); break; } case WID_GO_ROADSIDE_DROPDOWN: { // Setup road-side dropdown - list = new DropDownList(); *selected_index = this->opt->vehicle.road_side; const StringID *items = _driveside_dropdown; uint disabled = 0; @@ -239,13 +234,12 @@ struct GameOptionsWindow : Window { } for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { - *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); + list.emplace_back(new DropDownListStringItem(*items, i, HasBit(disabled, i))); } break; } case WID_GO_TOWNNAME_DROPDOWN: { // Setup townname dropdown - list = new DropDownList(); *selected_index = this->opt->game_creation.town_name; int enabled_item = (_game_mode == GM_MENU || Town::GetNumItems() == 0) ? -1 : *selected_index; @@ -253,71 +247,66 @@ struct GameOptionsWindow : Window { /* Add and sort newgrf townnames generators */ for (int i = 0; i < _nb_grf_names; i++) { int result = _nb_orig_names + i; - *list->Append() = new DropDownListStringItem(_grf_names[i], result, enabled_item != result && enabled_item >= 0); + list.emplace_back(new DropDownListStringItem(_grf_names[i], result, enabled_item != result && enabled_item >= 0)); } - QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); + std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc); - int newgrf_size = list->Length(); + size_t newgrf_size = list.size(); /* Insert newgrf_names at the top of the list */ if (newgrf_size > 0) { - *list->Append() = new DropDownListItem(-1, false); // separator line + list.emplace_back(new DropDownListItem(-1, false)); // separator line newgrf_size++; } /* Add and sort original townnames generators */ for (int i = 0; i < _nb_orig_names; i++) { - *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i, i, enabled_item != i && enabled_item >= 0); + list.emplace_back(new DropDownListStringItem(STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i, i, enabled_item != i && enabled_item >= 0)); } - QSortT(list->Begin() + newgrf_size, list->Length() - newgrf_size, DropDownListStringItem::NatSortFunc); + std::sort(list.begin() + newgrf_size, list.end(), DropDownListStringItem::NatSortFunc); break; } case WID_GO_AUTOSAVE_DROPDOWN: { // Setup autosave dropdown - list = new DropDownList(); *selected_index = _settings_client.gui.autosave; const StringID *items = _autosave_dropdown; for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { - *list->Append() = new DropDownListStringItem(*items, i, false); + list.emplace_back(new DropDownListStringItem(*items, i, false)); } break; } case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown - list = new DropDownList(); - for (uint i = 0; i < _languages.Length(); i++) { + for (uint i = 0; i < _languages.size(); i++) { if (&_languages[i] == _current_language) *selected_index = i; - *list->Append() = new DropDownListStringItem(SPECSTR_LANGUAGE_START + i, i, false); + list.emplace_back(new DropDownListStringItem(SPECSTR_LANGUAGE_START + i, i, false)); } - QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); + std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc); break; } case WID_GO_RESOLUTION_DROPDOWN: // Setup resolution dropdown - if (_num_resolutions == 0) break; + if (_resolutions.empty()) break; - list = new DropDownList(); *selected_index = GetCurRes(); - for (int i = 0; i < _num_resolutions; i++) { - *list->Append() = new DropDownListStringItem(SPECSTR_RESOLUTION_START + i, i, false); + for (uint i = 0; i < _resolutions.size(); i++) { + list.emplace_back(new DropDownListStringItem(SPECSTR_RESOLUTION_START + i, i, false)); } break; case WID_GO_GUI_ZOOM_DROPDOWN: { - list = new DropDownList(); *selected_index = ZOOM_LVL_OUT_4X - _gui_zoom; const StringID *items = _gui_zoom_dropdown; for (int i = 0; *items != INVALID_STRING_ID; items++, i++) { - *list->Append() = new DropDownListStringItem(*items, i, _settings_client.gui.zoom_min > ZOOM_LVL_OUT_4X - i); + list.emplace_back(new DropDownListStringItem(*items, i, _settings_client.gui.zoom_min > ZOOM_LVL_OUT_4X - i)); } break; } case WID_GO_FONT_ZOOM_DROPDOWN: { - list = new DropDownList(); *selected_index = ZOOM_LVL_OUT_4X - _font_zoom; const StringID *items = _font_zoom_dropdown; for (int i = 0; *items != INVALID_STRING_ID; items++, i++) { - *list->Append() = new DropDownListStringItem(*items, i, false); + list.emplace_back(new DropDownListStringItem(*items, i, false)); } break; } @@ -333,15 +322,12 @@ struct GameOptionsWindow : Window { case WID_GO_BASE_MUSIC_DROPDOWN: list = BuildMusicSetDropDownList(selected_index); break; - - default: - return NULL; } return list; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_GO_CURRENCY_DROPDOWN: SetDParam(0, _currency_specs[this->opt->locale.currency].name); break; @@ -349,7 +335,7 @@ struct GameOptionsWindow : Window { case WID_GO_TOWNNAME_DROPDOWN: SetDParam(0, TownName(this->opt->game_creation.town_name)); break; case WID_GO_AUTOSAVE_DROPDOWN: SetDParam(0, _autosave_dropdown[_settings_client.gui.autosave]); break; case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break; - case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; + case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _resolutions.size() ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; case WID_GO_GUI_ZOOM_DROPDOWN: SetDParam(0, _gui_zoom_dropdown[ZOOM_LVL_OUT_4X - _gui_zoom]); break; case WID_GO_FONT_ZOOM_DROPDOWN: SetDParam(0, _font_zoom_dropdown[ZOOM_LVL_OUT_4X - _font_zoom]); break; case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; @@ -360,7 +346,7 @@ struct GameOptionsWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_GO_BASE_GRF_DESCRIPTION: @@ -380,7 +366,7 @@ struct GameOptionsWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_GO_BASE_GRF_DESCRIPTION: @@ -431,38 +417,37 @@ struct GameOptionsWindow : Window { default: { int selected; - DropDownList *list = this->BuildDropDownList(widget, &selected); - if (list != NULL) { + DropDownList list = this->BuildDropDownList(widget, &selected); + if (!list.empty()) { /* Find the biggest item for the default size. */ - for (const DropDownListItem * const *it = list->Begin(); it != list->End(); it++) { + for (const auto &ddli : list) { Dimension string_dim; - int width = (*it)->Width(); + int width = ddli->Width(); string_dim.width = width + padding.width; - string_dim.height = (*it)->Height(width) + padding.height; + string_dim.height = ddli->Height(width) + padding.height; *size = maxdim(*size, string_dim); } - delete list; } } } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_END) { - if (BaseGraphics::GetUsedSet() == NULL) return; + if (BaseGraphics::GetUsedSet() == nullptr) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_GRF_TEXTFILE), BaseGraphics::GetUsedSet(), STR_CONTENT_TYPE_BASE_GRAPHICS); return; } if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_END) { - if (BaseSounds::GetUsedSet() == NULL) return; + if (BaseSounds::GetUsedSet() == nullptr) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_SFX_TEXTFILE), BaseSounds::GetUsedSet(), STR_CONTENT_TYPE_BASE_SOUNDS); return; } if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_END) { - if (BaseMusic::GetUsedSet() == NULL) return; + if (BaseMusic::GetUsedSet() == nullptr) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_MUSIC_TEXTFILE), BaseMusic::GetUsedSet(), STR_CONTENT_TYPE_BASE_MUSIC); return; @@ -479,9 +464,9 @@ struct GameOptionsWindow : Window { default: { int selected; - DropDownList *list = this->BuildDropDownList(widget, &selected); - if (list != NULL) { - ShowDropDownList(this, list, selected, widget); + DropDownList list = this->BuildDropDownList(widget, &selected); + if (!list.empty()) { + ShowDropDownList(this, std::move(list), selected, widget); } else { if (widget == WID_GO_RESOLUTION_DROPDOWN) ShowErrorMessage(STR_ERROR_RESOLUTION_LIST_FAILED, INVALID_STRING_ID, WL_ERROR); } @@ -510,7 +495,7 @@ struct GameOptionsWindow : Window { } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_GO_CURRENCY_DROPDOWN: // Currency @@ -522,7 +507,7 @@ struct GameOptionsWindow : Window { case WID_GO_ROADSIDE_DROPDOWN: // Road side if (this->opt->vehicle.road_side != index) { // only change if setting changed uint i; - if (GetSettingFromName("vehicle.road_side", &i) == NULL) NOT_REACHED(); + if (GetSettingFromName("vehicle.road_side", &i) == nullptr) NOT_REACHED(); SetSettingValue(i, index); MarkWholeScreenDirty(); } @@ -549,7 +534,7 @@ struct GameOptionsWindow : Window { break; case WID_GO_RESOLUTION_DROPDOWN: // Change resolution - if (index < _num_resolutions && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { + if ((uint)index < _resolutions.size() && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { this->SetDirty(); } break; @@ -590,7 +575,7 @@ struct GameOptionsWindow : Window { * @param data Information about the changed data. @see GameOptionsInvalidationData * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); @@ -599,9 +584,9 @@ struct GameOptionsWindow : Window { this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { - this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->GetTextfile(tft) == NULL); - this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == NULL || BaseSounds::GetUsedSet()->GetTextfile(tft) == NULL); - this->SetWidgetDisabledState(WID_GO_BASE_MUSIC_TEXTFILE + tft, BaseMusic::GetUsedSet() == NULL || BaseMusic::GetUsedSet()->GetTextfile(tft) == NULL); + this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == nullptr || BaseGraphics::GetUsedSet()->GetTextfile(tft) == nullptr); + this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == nullptr || BaseSounds::GetUsedSet()->GetTextfile(tft) == nullptr); + this->SetWidgetDisabledState(WID_GO_BASE_MUSIC_TEXTFILE + tft, BaseMusic::GetUsedSet() == nullptr || BaseMusic::GetUsedSet()->GetTextfile(tft) == nullptr); } missing_files = BaseMusic::GetUsedSet()->GetNumInvalid() == 0; @@ -910,14 +895,14 @@ bool BaseSettingEntry::IsVisible(const BaseSettingEntry *item) const * Find setting entry at row \a row_num * @param row_num Index of entry to return * @param cur_row Current row number - * @return The requested setting entry or \c NULL if it not found (folded or filtered) + * @return The requested setting entry or \c nullptr if it not found (folded or filtered) */ BaseSettingEntry *BaseSettingEntry::FindEntry(uint row_num, uint *cur_row) { - if (this->IsFiltered()) return NULL; + if (this->IsFiltered()) return nullptr; if (row_num == *cur_row) return this; (*cur_row)++; - return NULL; + return nullptr; } /** @@ -992,7 +977,7 @@ uint BaseSettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int SettingEntry::SettingEntry(const char *name) { this->name = name; - this->setting = NULL; + this->setting = nullptr; this->index = 0; } @@ -1004,7 +989,7 @@ void SettingEntry::Init(byte level) { BaseSettingEntry::Init(level); this->setting = GetSettingFromName(this->name, &this->index); - assert(this->setting != NULL); + assert(this->setting != nullptr); } /** @@ -1284,14 +1269,14 @@ uint SettingsContainer::Length() const * Find the setting entry at row number \a row_num * @param row_num Index of entry to return * @param cur_row Variable used for keeping track of the current row number. Should point to memory initialized to \c 0 when first called. - * @return The requested setting entry or \c NULL if it does not exist + * @return The requested setting entry or \c nullptr if it does not exist */ BaseSettingEntry *SettingsContainer::FindEntry(uint row_num, uint *cur_row) { - BaseSettingEntry *pe = NULL; + BaseSettingEntry *pe = nullptr; for (EntryVector::iterator it = this->entries.begin(); it != this->entries.end(); ++it) { pe = (*it)->FindEntry(row_num, cur_row); - if (pe != NULL) { + if (pe != nullptr) { break; } } @@ -1447,14 +1432,14 @@ uint SettingsPage::Length() const * Find setting entry at row \a row_num * @param row_num Index of entry to return * @param cur_row Current row number - * @return The requested setting entry or \c NULL if it not found (folded or filtered) + * @return The requested setting entry or \c nullptr if it not found (folded or filtered) */ BaseSettingEntry *SettingsPage::FindEntry(uint row_num, uint *cur_row) { - if (this->IsFiltered()) return NULL; + if (this->IsFiltered()) return nullptr; if (row_num == *cur_row) return this; (*cur_row)++; - if (this->folded) return NULL; + if (this->folded) return nullptr; return SettingsContainer::FindEntry(row_num, cur_row); } @@ -1510,9 +1495,9 @@ void SettingsPage::DrawSetting(GameSettings *settings_ptr, int left, int right, /** Construct settings tree */ static SettingsContainer &GetSettingsTree() { - static SettingsContainer *main = NULL; + static SettingsContainer *main = nullptr; - if (main == NULL) + if (main == nullptr) { /* Build up the dynamic settings-array only once per OpenTTD session */ main = new SettingsContainer(); @@ -1780,6 +1765,7 @@ static SettingsContainer &GetSettingsTree() towns->Add(new SettingEntry("economy.allow_town_roads")); towns->Add(new SettingEntry("economy.allow_town_level_crossings")); towns->Add(new SettingEntry("economy.found_town")); + towns->Add(new SettingEntry("economy.town_cargogen_mode")); } SettingsPage *industries = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES)); @@ -1789,6 +1775,7 @@ static SettingsContainer &GetSettingsTree() industries->Add(new SettingEntry("economy.multiple_industry_per_town")); industries->Add(new SettingEntry("game_creation.oil_refinery_limit")); industries->Add(new SettingEntry("economy.smooth_economy")); + industries->Add(new SettingEntry("station.serve_neutral_industries")); } SettingsPage *cdist = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST)); @@ -1815,6 +1802,7 @@ static SettingsContainer &GetSettingsTree() { npc->Add(new SettingEntry("script.settings_profile")); npc->Add(new SettingEntry("script.script_max_opcode_till_suspend")); + npc->Add(new SettingEntry("script.script_max_memory_megabytes")); npc->Add(new SettingEntry("difficulty.competitor_speed")); npc->Add(new SettingEntry("ai.ai_in_multiplayer")); npc->Add(new SettingEntry("ai.ai_disable_veh_train")); @@ -1825,6 +1813,7 @@ static SettingsContainer &GetSettingsTree() ai->Add(new SettingEntry("economy.give_money")); ai->Add(new SettingEntry("economy.allow_shares")); + ai->Add(new SettingEntry("economy.min_years_for_shares")); } main->Init(); @@ -1858,10 +1847,10 @@ struct GameSettingsWindow : Window { static GameSettings *settings_ptr; ///< Pointer to the game settings being displayed and modified. - SettingEntry *valuewindow_entry; ///< If non-NULL, pointer to setting for which a value-entering window has been opened. - SettingEntry *clicked_entry; ///< If non-NULL, pointer to a clicked numeric setting (with a depressed left or right button). - SettingEntry *last_clicked; ///< If non-NULL, pointer to the last clicked setting. - SettingEntry *valuedropdown_entry; ///< If non-NULL, pointer to the value for which a dropdown window is currently opened. + SettingEntry *valuewindow_entry; ///< If non-nullptr, pointer to setting for which a value-entering window has been opened. + SettingEntry *clicked_entry; ///< If non-nullptr, pointer to a clicked numeric setting (with a depressed left or right button). + SettingEntry *last_clicked; ///< If non-nullptr, pointer to the last clicked setting. + SettingEntry *valuedropdown_entry; ///< If non-nullptr, pointer to the value for which a dropdown window is currently opened. bool closing_dropdown; ///< True, if the dropdown list is currently closing. SettingFilter filter; ///< Filter for the list. @@ -1885,10 +1874,10 @@ struct GameSettingsWindow : Window { _circle_size = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED)); GetSettingsTree().FoldAll(); // Close all sub-pages - this->valuewindow_entry = NULL; // No setting entry for which a entry window is opened - this->clicked_entry = NULL; // No numeric setting buttons are depressed - this->last_clicked = NULL; - this->valuedropdown_entry = NULL; + this->valuewindow_entry = nullptr; // No setting entry for which a entry window is opened + this->clicked_entry = nullptr; // No numeric setting buttons are depressed + this->last_clicked = nullptr; + this->valuedropdown_entry = nullptr; this->closing_dropdown = false; this->manually_changed_folding = false; @@ -1903,7 +1892,7 @@ struct GameSettingsWindow : Window { this->InvalidateData(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_GS_OPTIONSPANEL: @@ -1938,13 +1927,13 @@ struct GameSettingsWindow : Window { } } - virtual void OnPaint() + void OnPaint() override { if (this->closing_dropdown) { this->closing_dropdown = false; - assert(this->valuedropdown_entry != NULL); + assert(this->valuedropdown_entry != nullptr); this->valuedropdown_entry->SetButtons(0); - this->valuedropdown_entry = NULL; + this->valuedropdown_entry = nullptr; } /* Reserve the correct number of lines for the 'some search results are hidden' notice in the central settings display panel. */ @@ -1979,7 +1968,7 @@ struct GameSettingsWindow : Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_GS_RESTRICT_DROPDOWN: @@ -1997,34 +1986,31 @@ struct GameSettingsWindow : Window { } } - DropDownList *BuildDropDownList(int widget) const + DropDownList BuildDropDownList(int widget) const { - DropDownList *list = NULL; + DropDownList list; switch (widget) { case WID_GS_RESTRICT_DROPDOWN: - list = new DropDownList(); - for (int mode = 0; mode != RM_END; mode++) { /* If we are in adv. settings screen for the new game's settings, * we don't want to allow comparing with new game's settings. */ bool disabled = mode == RM_CHANGED_AGAINST_NEW && settings_ptr == &_settings_newgame; - *list->Append() = new DropDownListStringItem(_game_settings_restrict_dropdown[mode], mode, disabled); + list.emplace_back(new DropDownListStringItem(_game_settings_restrict_dropdown[mode], mode, disabled)); } break; case WID_GS_TYPE_DROPDOWN: - list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL, ST_ALL, false); - *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME, ST_GAME, false); - *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME, ST_COMPANY, false); - *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT, ST_CLIENT, false); + list.emplace_back(new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL, ST_ALL, false)); + list.emplace_back(new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME, ST_GAME, false)); + list.emplace_back(new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME, ST_COMPANY, false)); + list.emplace_back(new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT, ST_CLIENT, false)); break; } return list; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_GS_OPTIONSPANEL: { @@ -2037,7 +2023,7 @@ struct GameSettingsWindow : Window { } case WID_GS_HELP_TEXT: - if (this->last_clicked != NULL) { + if (this->last_clicked != nullptr) { const SettingDesc *sd = this->last_clicked->setting; int y = r.top; @@ -2066,7 +2052,7 @@ struct GameSettingsWindow : Window { /** * Set the entry that should have its help text displayed, and mark the window dirty so it gets repainted. - * @param pe Setting to display help text of, use \c NULL to stop displaying help of the currently displayed setting. + * @param pe Setting to display help text of, use \c nullptr to stop displaying help of the currently displayed setting. */ void SetDisplayedHelpText(SettingEntry *pe) { @@ -2074,7 +2060,7 @@ struct GameSettingsWindow : Window { this->last_clicked = pe; } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_GS_EXPAND_ALL: @@ -2090,17 +2076,17 @@ struct GameSettingsWindow : Window { break; case WID_GS_RESTRICT_DROPDOWN: { - DropDownList *list = this->BuildDropDownList(widget); - if (list != NULL) { - ShowDropDownList(this, list, this->filter.mode, widget); + DropDownList list = this->BuildDropDownList(widget); + if (!list.empty()) { + ShowDropDownList(this, std::move(list), this->filter.mode, widget); } break; } case WID_GS_TYPE_DROPDOWN: { - DropDownList *list = this->BuildDropDownList(widget); - if (list != NULL) { - ShowDropDownList(this, list, this->filter.type, widget); + DropDownList list = this->BuildDropDownList(widget); + if (!list.empty()) { + ShowDropDownList(this, std::move(list), this->filter.type, widget); } break; } @@ -2115,14 +2101,14 @@ struct GameSettingsWindow : Window { uint cur_row = 0; BaseSettingEntry *clicked_entry = GetSettingsTree().FindEntry(btn, &cur_row); - if (clicked_entry == NULL) return; // Clicked below the last setting of the page + if (clicked_entry == nullptr) return; // Clicked below the last setting of the page int x = (_current_text_dir == TD_RTL ? this->width - 1 - pt.x : pt.x) - SETTINGTREE_LEFT_OFFSET - (clicked_entry->level + 1) * LEVEL_WIDTH; // Shift x coordinate if (x < 0) return; // Clicked left of the entry SettingsPage *clicked_page = dynamic_cast(clicked_entry); - if (clicked_page != NULL) { - this->SetDisplayedHelpText(NULL); + if (clicked_page != nullptr) { + this->SetDisplayedHelpText(nullptr); clicked_page->folded = !clicked_page->folded; // Flip 'folded'-ness of the sub-page this->manually_changed_folding = true; @@ -2132,7 +2118,7 @@ struct GameSettingsWindow : Window { } SettingEntry *pe = dynamic_cast(clicked_entry); - assert(pe != NULL); + assert(pe != nullptr); const SettingDesc *sd = pe->setting; /* return if action is only active in network, or only settable by server */ @@ -2154,9 +2140,9 @@ struct GameSettingsWindow : Window { HideDropDownMenu(this); this->closing_dropdown = false; this->valuedropdown_entry->SetButtons(0); - this->valuedropdown_entry = NULL; + this->valuedropdown_entry = nullptr; } else { - if (this->valuedropdown_entry != NULL) this->valuedropdown_entry->SetButtons(0); + if (this->valuedropdown_entry != nullptr) this->valuedropdown_entry->SetButtons(0); this->closing_dropdown = false; const NWidgetBase *wid = this->GetWidget(WID_GS_OPTIONSPANEL); @@ -2173,12 +2159,12 @@ struct GameSettingsWindow : Window { this->valuedropdown_entry = pe; this->valuedropdown_entry->SetButtons(SEF_LEFT_DEPRESSED); - DropDownList *list = new DropDownList(); + DropDownList list; for (int i = sdb->min; i <= (int)sdb->max; i++) { - *list->Append() = new DropDownListStringItem(sdb->str_val + i - sdb->min, i, false); + list.emplace_back(new DropDownListStringItem(sdb->str_val + i - sdb->min, i, false)); } - ShowDropDownListAt(this, list, value, -1, wi_rect, COLOUR_ORANGE, true); + ShowDropDownListAt(this, std::move(list), value, -1, wi_rect, COLOUR_ORANGE, true); } } this->SetDirty(); @@ -2221,7 +2207,7 @@ struct GameSettingsWindow : Window { /* Set up scroller timeout for numeric values */ if (value != oldvalue) { - if (this->clicked_entry != NULL) { // Release previous buttons if any + if (this->clicked_entry != nullptr) { // Release previous buttons if any this->clicked_entry->SetButtons(0); } this->clicked_entry = pe; @@ -2257,21 +2243,21 @@ struct GameSettingsWindow : Window { } } - virtual void OnTimeout() + void OnTimeout() override { - if (this->clicked_entry != NULL) { // On timeout, release any depressed buttons + if (this->clicked_entry != nullptr) { // On timeout, release any depressed buttons this->clicked_entry->SetButtons(0); - this->clicked_entry = NULL; + this->clicked_entry = nullptr; this->SetDirty(); } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { /* The user pressed cancel */ - if (str == NULL) return; + if (str == nullptr) return; - assert(this->valuewindow_entry != NULL); + assert(this->valuewindow_entry != nullptr); const SettingDesc *sd = this->valuewindow_entry->setting; int32 value; @@ -2292,7 +2278,7 @@ struct GameSettingsWindow : Window { this->SetDirty(); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_GS_RESTRICT_DROPDOWN: @@ -2320,7 +2306,7 @@ struct GameSettingsWindow : Window { default: if (widget < 0) { /* Deal with drop down boxes on the panel. */ - assert(this->valuedropdown_entry != NULL); + assert(this->valuedropdown_entry != nullptr); const SettingDesc *sd = this->valuedropdown_entry->setting; assert(sd->desc.flags & SGF_MULTISTRING); @@ -2336,7 +2322,7 @@ struct GameSettingsWindow : Window { } } - virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) + void OnDropdownClose(Point pt, int widget, int index, bool instant_close) override { if (widget >= 0) { /* Normally the default implementation of OnDropdownClose() takes care of @@ -2349,13 +2335,13 @@ struct GameSettingsWindow : Window { * 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->valuedropdown_entry != NULL); + assert(this->valuedropdown_entry != nullptr); this->closing_dropdown = true; this->SetDirty(); } } - virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -2374,8 +2360,8 @@ struct GameSettingsWindow : Window { } this->vscroll->SetCount(GetSettingsTree().Length() + this->warn_lines); - if (this->last_clicked != NULL && !GetSettingsTree().IsVisible(this->last_clicked)) { - this->SetDisplayedHelpText(NULL); + if (this->last_clicked != nullptr && !GetSettingsTree().IsVisible(this->last_clicked)) { + this->SetDisplayedHelpText(nullptr); } bool all_folded = true; @@ -2385,7 +2371,7 @@ struct GameSettingsWindow : Window { this->SetWidgetDisabledState(WID_GS_COLLAPSE_ALL, all_folded); } - virtual void OnEditboxChanged(int wid) + void OnEditboxChanged(int wid) override { if (wid == WID_GS_FILTER) { this->filter.string.SetFilterTerm(this->filter_editbox.text.buf); @@ -2398,13 +2384,13 @@ struct GameSettingsWindow : Window { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET); } }; -GameSettings *GameSettingsWindow::settings_ptr = NULL; +GameSettings *GameSettingsWindow::settings_ptr = nullptr; static const NWidgetPart _nested_settings_selection_widgets[] = { NWidget(NWID_HORIZONTAL), @@ -2542,7 +2528,7 @@ struct CustomCurrencyWindow : Window { this->SetWidgetDisabledState(WID_CC_YEAR_UP, _custom_currency.to_euro == MAX_YEAR); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_CC_RATE: SetDParam(0, 1); SetDParam(1, 1); break; @@ -2560,7 +2546,7 @@ struct CustomCurrencyWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { /* Set the appropriate width for the edit 'buttons' */ @@ -2579,7 +2565,7 @@ struct CustomCurrencyWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { int line = 0; int len = 0; @@ -2661,9 +2647,9 @@ struct CustomCurrencyWindow : Window { this->SetDirty(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; switch (this->query_widget) { case WID_CC_RATE: @@ -2693,7 +2679,7 @@ struct CustomCurrencyWindow : Window { SetButtonState(); } - virtual void OnTimeout() + void OnTimeout() override { this->SetDirty(); } @@ -2740,7 +2726,7 @@ static const NWidgetPart _nested_cust_currency_widgets[] = { }; static WindowDesc _cust_currency_desc( - WDP_CENTER, NULL, 0, 0, + WDP_CENTER, nullptr, 0, 0, WC_CUSTOM_CURRENCY, WC_NONE, 0, _nested_cust_currency_widgets, lengthof(_nested_cust_currency_widgets) diff --git a/src/settings_gui.h b/src/settings_gui.h index 23a343219f..a81fc0a2b3 100644 --- a/src/settings_gui.h +++ b/src/settings_gui.h @@ -24,7 +24,7 @@ void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clic void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable); void DrawBoolButton(int x, int y, bool state, bool clickable); -DropDownList *BuildMusicSetDropDownList(int *selected_index); +DropDownList BuildMusicSetDropDownList(int *selected_index); /* Actually implemented in music_gui.cpp */ void ChangeMusicSet(int index); diff --git a/src/settings_internal.h b/src/settings_internal.h index 028e977e48..0f1d3c1923 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -20,7 +20,7 @@ * @see VarTypes * @see SettingDescBase */ -enum SettingDescTypeLong { +enum SettingDescType : byte { /* 4 bytes allocated a maximum of 16 types for GenericType */ SDT_BEGIN = 0, SDT_NUMX = 0, ///< any number-type @@ -32,10 +32,9 @@ enum SettingDescTypeLong { SDT_END, /* 10 more possible primitives */ }; -typedef SimpleTinyEnumT SettingDescType; -enum SettingGuiFlagLong { +enum SettingGuiFlag : uint16 { /* 1 byte allocated for a maximum of 8 flags * Flags directing saving/loading of a variable */ SGF_NONE = 0, @@ -49,8 +48,7 @@ enum SettingGuiFlagLong { SGF_SCENEDIT_TOO = 1 << 7, ///< this setting can be changed in the scenario editor (only makes sense when SGF_NEWGAME_ONLY is set) SGF_PER_COMPANY = 1 << 8, ///< this setting can be different for each company (saved in company struct) }; -DECLARE_ENUM_AS_BIT_SET(SettingGuiFlagLong) -typedef SimpleTinyEnumT SettingGuiFlag; +DECLARE_ENUM_AS_BIT_SET(SettingGuiFlag) /** * A SettingCategory defines a grouping of the settings. diff --git a/src/settings_type.h b/src/settings_type.h index 9e26b1b3c5..bf10b9b542 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -116,8 +116,8 @@ struct GUISettings { uint8 statusbar_pos; ///< position of statusbar, 0=left, 1=center, 2=right uint8 window_snap_radius; ///< windows snap at each other if closer than this uint8 window_soft_limit; ///< soft limit of maximum number of non-stickied non-vital windows (0 = no limit) - ZoomLevelByte zoom_min; ///< minimum zoom out level - ZoomLevelByte zoom_max; ///< maximum zoom out level + ZoomLevel zoom_min; ///< minimum zoom out level + ZoomLevel zoom_max; ///< maximum zoom out level bool disable_unsuitable_building; ///< disable infrastructure building when no suitable vehicles are available byte autosave; ///< how often should we do autosaves? bool threaded_saves; ///< should we do threaded saves? @@ -164,11 +164,9 @@ struct GUISettings { uint8 station_gui_group_order; ///< the order of grouping cargo entries in the station gui uint8 station_gui_sort_by; ///< sort cargo entries in the station gui by station name or amount uint8 station_gui_sort_order; ///< the sort order of entries in the station gui - ascending or descending -#ifdef ENABLE_NETWORK uint16 network_chat_box_width_pct; ///< width of the chat box in percent uint8 network_chat_box_height; ///< height of the chat box in lines uint16 network_chat_timeout; ///< timeout of chat messages in seconds -#endif uint8 developer; ///< print non-fatal warnings in console (>= 1), copy debug output to console (== 2) bool show_date_in_logs; ///< whether to show dates in console logs @@ -204,7 +202,7 @@ struct SoundSettings { bool news_ticker; ///< Play a ticker sound when a news item is published. bool news_full; ///< Play sound effects associated to certain news types. bool new_year; ///< Play sound on new year, summarising the performance during the last year. - bool confirm; ///< Play sound effect on succesful constructions or other actions. + bool confirm; ///< Play sound effect on successful constructions or other actions. bool click_beep; ///< Beep on a random selection of buttons. bool disaster; ///< Play disaster and accident sounds. bool vehicle; ///< Play vehicle sound effects. @@ -257,7 +255,6 @@ struct NewsSettings { /** All settings related to the network. */ struct NetworkSettings { -#ifdef ENABLE_NETWORK uint16 sync_freq; ///< how often do we check whether we are still in-sync uint8 frame_freq; ///< how often do we send commands to the clients uint16 commands_per_frame; ///< how many commands may be sent each frame_freq frames? @@ -297,8 +294,6 @@ struct NetworkSettings { char last_host[NETWORK_HOSTNAME_LENGTH]; ///< IP address of the last joined server uint16 last_port; ///< port of the last joined server bool no_http_content_downloads; ///< do not do content downloads over HTTP -#else /* ENABLE_NETWORK */ -#endif }; /** Settings related to the creation of games. */ @@ -364,12 +359,7 @@ struct AISettings { struct ScriptSettings { uint8 settings_profile; ///< difficulty profile to set initial settings of scripts, esp. random AIs uint32 script_max_opcode_till_suspend; ///< max opcode calls till scripts will suspend -}; - -/** Settings related to the old pathfinder. */ -struct OPFSettings { - uint16 pf_maxlength; ///< maximum length when searching for a train route for new pathfinder - byte pf_maxdepth; ///< maximum recursion depth when searching for a train route for new pathfinder + uint32 script_max_memory_megabytes; ///< limit on memory a single script instance may have allocated }; /** Settings related to the new pathfinder. */ @@ -438,6 +428,8 @@ struct YAPFSettings { uint32 rail_longer_platform_per_tile_penalty; ///< penalty for longer station platform than train (per tile) uint32 rail_shorter_platform_penalty; ///< penalty for shorter station platform than train uint32 rail_shorter_platform_per_tile_penalty; ///< penalty for shorter station platform than train (per tile) + uint32 ship_curve45_penalty; ///< penalty for 45-deg curve for ships + uint32 ship_curve90_penalty; ///< penalty for 90-deg curve for ships }; /** Settings related to all pathfinders. */ @@ -458,7 +450,6 @@ struct PathfinderSettings { byte wait_for_pbs_path; ///< how long to wait for a path reservation. byte path_backoff_interval; ///< ticks between checks for a free path. - OPFSettings opf; ///< pathfinder settings for the old pathfinder NPFSettings npf; ///< pathfinder settings for the new pathfinder YAPFSettings yapf; ///< pathfinder settings for the yet another pathfinder }; @@ -501,6 +492,7 @@ struct EconomySettings { bool bribe; ///< enable bribing the local authority bool smooth_economy; ///< smooth economy bool allow_shares; ///< allow the buying/selling of shares + uint8 min_years_for_shares; ///< minimum age of a company for it to trade shares uint8 feeder_payment_share; ///< percentage of leg payment to virtually pay in feeder systems byte dist_local_authority; ///< distance for town local authority, default 20 bool exclusive_rights; ///< allow buying exclusive rights @@ -512,9 +504,10 @@ struct EconomySettings { uint8 town_growth_rate; ///< town growth rate uint8 larger_towns; ///< the number of cities to build. These start off larger and grow twice as fast uint8 initial_city_size; ///< multiplier for the initial size of the cities compared to towns - TownLayoutByte town_layout; ///< select town layout, @see TownLayout + TownLayout town_layout; ///< select town layout, @see TownLayout + TownCargoGenMode town_cargogen_mode; ///< algorithm for generating cargo from houses, @see TownCargoGenMode bool allow_town_roads; ///< towns are allowed to build roads (always allowed when generating world / in SE) - TownFoundingByte found_town; ///< town founding, @see TownFounding + TownFounding found_town; ///< town founding. bool station_noise_level; ///< build new airports when the town noise level is still within accepted limits uint16 town_noise_population[3]; ///< population to base decision on noise evaluation (@see town_council_tolerance) bool allow_town_level_crossings; ///< towns are allowed to build level crossings @@ -522,16 +515,16 @@ struct EconomySettings { }; struct LinkGraphSettings { - uint16 recalc_time; ///< time (in days) for recalculating each link graph component. - uint16 recalc_interval; ///< time (in days) between subsequent checks for link graphs to be calculated. - DistributionTypeByte distribution_pax; ///< distribution type for passengers - DistributionTypeByte distribution_mail; ///< distribution type for mail - DistributionTypeByte distribution_armoured; ///< distribution type for armoured cargo class - DistributionTypeByte distribution_default; ///< distribution type for all other goods - uint8 accuracy; ///< accuracy when calculating things on the link graph. low accuracy => low running time - uint8 demand_size; ///< influence of supply ("station size") on the demand function - uint8 demand_distance; ///< influence of distance between stations on the demand function - uint8 short_path_saturation; ///< percentage up to which short paths are saturated before saturating most capacious paths + uint16 recalc_time; ///< time (in days) for recalculating each link graph component. + uint16 recalc_interval; ///< time (in days) between subsequent checks for link graphs to be calculated. + DistributionType distribution_pax; ///< distribution type for passengers + DistributionType distribution_mail; ///< distribution type for mail + DistributionType distribution_armoured; ///< distribution type for armoured cargo class + DistributionType distribution_default; ///< distribution type for all other goods + uint8 accuracy; ///< accuracy when calculating things on the link graph. low accuracy => low running time + uint8 demand_size; ///< influence of supply ("station size") on the demand function + uint8 demand_distance; ///< influence of distance between stations on the demand function + uint8 short_path_saturation; ///< percentage up to which short paths are saturated before saturating most capacious paths inline DistributionType GetDistributionType(CargoID cargo) const { if (IsCargoInClass(cargo, CC_PASSENGERS)) return this->distribution_pax; @@ -544,6 +537,7 @@ struct LinkGraphSettings { /** Settings related to stations. */ struct StationSettings { bool modified_catchment; ///< different-size catchment areas + bool serve_neutral_industries; ///< company stations can serve industries with attached neutral stations bool adjacent_stations; ///< allow stations to be built directly adjacent to other stations bool distant_join_stations; ///< allow to join non-adjacent stations bool never_expire_airports; ///< never expire airports diff --git a/src/settingsgen/settingsgen.cpp b/src/settingsgen/settingsgen.cpp index 298539417e..7f024b2dcc 100644 --- a/src/settingsgen/settingsgen.cpp +++ b/src/settingsgen/settingsgen.cpp @@ -23,13 +23,6 @@ #include #endif -#ifdef __MORPHOS__ -#ifdef stderr -#undef stderr -#endif -#define stderr stdout -#endif /* __MORPHOS__ */ - #include "../safeguards.h" /** @@ -48,7 +41,7 @@ void NORETURN CDECL error(const char *s, ...) exit(1); } -static const int OUTPUT_BLOCK_SIZE = 16000; ///< Block size of the buffer in #OutputBuffer. +static const size_t OUTPUT_BLOCK_SIZE = 16000; ///< Block size of the buffer in #OutputBuffer. /** Output buffer for a block of data. */ class OutputBuffer { @@ -65,10 +58,9 @@ public: * @param length Length of the text in bytes. * @return Number of bytes actually stored. */ - int Add(const char *text, int length) + size_t Add(const char *text, size_t length) { - int store_size = min(length, OUTPUT_BLOCK_SIZE - this->size); - assert(store_size >= 0); + size_t store_size = min(length, OUTPUT_BLOCK_SIZE - this->size); assert(store_size <= OUTPUT_BLOCK_SIZE); MemCpyT(this->data + this->size, text, store_size); this->size += store_size; @@ -81,7 +73,7 @@ public: */ void Write(FILE *out_fp) const { - if (fwrite(this->data, 1, this->size, out_fp) != (size_t)this->size) { + if (fwrite(this->data, 1, this->size, out_fp) != this->size) { fprintf(stderr, "Error: Cannot write output\n"); } } @@ -95,7 +87,7 @@ public: return this->size < OUTPUT_BLOCK_SIZE; } - int size; ///< Number of bytes stored in \a data. + size_t size; ///< Number of bytes stored in \a data. char data[OUTPUT_BLOCK_SIZE]; ///< Stored data. }; @@ -110,7 +102,7 @@ public: /** Clear the temporary storage. */ void Clear() { - this->output_buffer.Clear(); + this->output_buffer.clear(); } /** @@ -118,19 +110,20 @@ public: * @param text Text to store. * @param length Length of the text in bytes, \c 0 means 'length of the string'. */ - void Add(const char *text, int length = 0) + void Add(const char *text, size_t length = 0) { if (length == 0) length = strlen(text); if (length > 0 && this->BufferHasRoom()) { - int stored_size = this->output_buffer[this->output_buffer.Length() - 1].Add(text, length); + size_t stored_size = this->output_buffer[this->output_buffer.size() - 1].Add(text, length); length -= stored_size; text += stored_size; } while (length > 0) { - OutputBuffer *block = this->output_buffer.Append(); - block->Clear(); // Initialize the new block. - int stored_size = block->Add(text, length); + /*C++17: OutputBuffer &block =*/ this->output_buffer.emplace_back(); + OutputBuffer &block = this->output_buffer.back(); + block.Clear(); // Initialize the new block. + size_t stored_size = block.Add(text, length); length -= stored_size; text += stored_size; } @@ -142,8 +135,8 @@ public: */ void Write(FILE *out_fp) const { - for (const OutputBuffer *out_data = this->output_buffer.Begin(); out_data != this->output_buffer.End(); out_data++) { - out_data->Write(out_fp); + for (const OutputBuffer &out_data : output_buffer) { + out_data.Write(out_fp); } } @@ -154,11 +147,11 @@ private: */ bool BufferHasRoom() const { - uint num_blocks = this->output_buffer.Length(); + size_t num_blocks = this->output_buffer.size(); return num_blocks > 0 && this->output_buffer[num_blocks - 1].HasRoom(); } - typedef SmallVector OutputBufferVector; ///< Vector type for output buffers. + typedef std::vector OutputBufferVector; ///< Vector type for output buffers. OutputBufferVector output_buffer; ///< Vector of blocks containing the stored output. }; @@ -167,10 +160,10 @@ private: struct SettingsIniFile : IniLoadFile { /** * Construct a new ini loader. - * @param list_group_names A \c NULL terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST - * @param seq_group_names A \c NULL terminated list with group names that should be loaded as lists of names. @see IGT_SEQUENCE + * @param list_group_names A \c nullptr terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST + * @param seq_group_names A \c nullptr terminated list with group names that should be loaded as lists of names. @see IGT_SEQUENCE */ - SettingsIniFile(const char * const *list_group_names = NULL, const char * const *seq_group_names = NULL) : + SettingsIniFile(const char * const *list_group_names = nullptr, const char * const *seq_group_names = nullptr) : IniLoadFile(list_group_names, seq_group_names) { } @@ -180,7 +173,7 @@ struct SettingsIniFile : IniLoadFile { /* Open the text file in binary mode to prevent end-of-line translations * done by ftell() and friends, as defined by K&R. */ FILE *in = fopen(filename, "rb"); - if (in == NULL) return NULL; + if (in == nullptr) return nullptr; fseek(in, 0L, SEEK_END); *size = ftell(in); @@ -209,9 +202,9 @@ static const char *DEFAULTS_GROUP_NAME = "defaults"; ///< Name of the group c */ static IniLoadFile *LoadIniFile(const char *filename) { - static const char * const seq_groups[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, NULL}; + static const char * const seq_groups[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, nullptr}; - IniLoadFile *ini = new SettingsIniFile(NULL, seq_groups); + IniLoadFile *ini = new SettingsIniFile(nullptr, seq_groups); ini->LoadFromDisk(filename, NO_DIRECTORY); return ini; } @@ -224,8 +217,8 @@ static IniLoadFile *LoadIniFile(const char *filename) static void DumpGroup(IniLoadFile *ifile, const char * const group_name) { IniGroup *grp = ifile->GetGroup(group_name, 0, false); - if (grp != NULL && grp->type == IGT_SEQUENCE) { - for (IniItem *item = grp->item; item != NULL; item = item->next) { + if (grp != nullptr && grp->type == IGT_SEQUENCE) { + for (IniItem *item = grp->item; item != nullptr; item = item->next) { if (item->name) { _stored_output.Add(item->name); _stored_output.Add("\n", 1); @@ -238,14 +231,14 @@ static void DumpGroup(IniLoadFile *ifile, const char * const group_name) * Find the value of a template variable. * @param name Name of the item to find. * @param grp Group currently being expanded (searched first). - * @param defaults Fallback group to search, \c NULL skips the search. - * @return Text of the item if found, else \c NULL. + * @param defaults Fallback group to search, \c nullptr skips the search. + * @return Text of the item if found, else \c nullptr. */ static const char *FindItemValue(const char *name, IniGroup *grp, IniGroup *defaults) { IniItem *item = grp->GetItem(name, false); - if (item == NULL && defaults != NULL) item = defaults->GetItem(name, false); - if (item == NULL || item->value == NULL) return NULL; + if (item == nullptr && defaults != nullptr) item = defaults->GetItem(name, false); + if (item == nullptr || item->value == nullptr) return nullptr; return item->value; } @@ -256,30 +249,30 @@ static const char *FindItemValue(const char *name, IniGroup *grp, IniGroup *defa static void DumpSections(IniLoadFile *ifile) { static const int MAX_VAR_LENGTH = 64; - static const char * const special_group_names[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, DEFAULTS_GROUP_NAME, TEMPLATES_GROUP_NAME, NULL}; + static const char * const special_group_names[] = {PREAMBLE_GROUP_NAME, POSTAMBLE_GROUP_NAME, DEFAULTS_GROUP_NAME, TEMPLATES_GROUP_NAME, nullptr}; IniGroup *default_grp = ifile->GetGroup(DEFAULTS_GROUP_NAME, 0, false); IniGroup *templates_grp = ifile->GetGroup(TEMPLATES_GROUP_NAME, 0, false); - if (templates_grp == NULL) return; + if (templates_grp == nullptr) return; /* Output every group, using its name as template name. */ - for (IniGroup *grp = ifile->group; grp != NULL; grp = grp->next) { + for (IniGroup *grp = ifile->group; grp != nullptr; grp = grp->next) { const char * const *sgn; - for (sgn = special_group_names; *sgn != NULL; sgn++) if (strcmp(grp->name, *sgn) == 0) break; - if (*sgn != NULL) continue; + for (sgn = special_group_names; *sgn != nullptr; sgn++) if (strcmp(grp->name, *sgn) == 0) break; + if (*sgn != nullptr) continue; IniItem *template_item = templates_grp->GetItem(grp->name, false); // Find template value. - if (template_item == NULL || template_item->value == NULL) { + if (template_item == nullptr || template_item->value == nullptr) { fprintf(stderr, "settingsgen: Warning: Cannot find template %s\n", grp->name); continue; } /* Prefix with #if/#ifdef/#ifndef */ - static const char * const pp_lines[] = {"if", "ifdef", "ifndef", NULL}; + static const char * const pp_lines[] = {"if", "ifdef", "ifndef", nullptr}; int count = 0; - for (const char * const *name = pp_lines; *name != NULL; name++) { + for (const char * const *name = pp_lines; *name != nullptr; name++) { const char *condition = FindItemValue(*name, grp, default_grp); - if (condition != NULL) { + if (condition != nullptr) { _stored_output.Add("#", 1); _stored_output.Add(*name); _stored_output.Add(" ", 1); @@ -318,7 +311,7 @@ static void DumpSections(IniLoadFile *ifile) if (i > 0) { /* Find the text to output. */ const char *valitem = FindItemValue(variable, grp, default_grp); - if (valitem != NULL) _stored_output.Add(valitem); + if (valitem != nullptr) _stored_output.Add(valitem); } else { _stored_output.Add("$", 1); } @@ -338,10 +331,10 @@ static void DumpSections(IniLoadFile *ifile) */ static void CopyFile(const char *fname, FILE *out_fp) { - if (fname == NULL) return; + if (fname == nullptr) return; FILE *in_fp = fopen(fname, "r"); - if (in_fp == NULL) { + if (in_fp == nullptr) { fprintf(stderr, "settingsgen: Warning: Cannot open file %s for copying\n", fname); return; } @@ -368,10 +361,10 @@ static void CopyFile(const char *fname, FILE *out_fp) static bool CompareFiles(const char *n1, const char *n2) { FILE *f2 = fopen(n2, "rb"); - if (f2 == NULL) return false; + if (f2 == nullptr) return false; FILE *f1 = fopen(n1, "rb"); - if (f1 == NULL) { + if (f1 == nullptr) { fclose(f2); error("can't open %s", n1); } @@ -399,7 +392,7 @@ static bool CompareFiles(const char *n1, const char *n2) static const OptionData _opts[] = { GETOPT_NOVAL( 'v', "--version"), GETOPT_NOVAL( 'h', "--help"), - GETOPT_GENERAL('h', '?', NULL, ODF_NO_VALUE), + GETOPT_GENERAL('h', '?', nullptr, ODF_NO_VALUE), GETOPT_VALUE( 'o', "--output"), GETOPT_VALUE( 'b', "--before"), GETOPT_VALUE( 'a', "--after"), @@ -442,9 +435,9 @@ static void ProcessIniFile(const char *fname) */ int CDECL main(int argc, char *argv[]) { - const char *output_file = NULL; - const char *before_file = NULL; - const char *after_file = NULL; + const char *output_file = nullptr; + const char *before_file = nullptr; + const char *after_file = nullptr; GetOptData mgo(argc - 1, argv + 1, _opts); for (;;) { @@ -490,7 +483,7 @@ int CDECL main(int argc, char *argv[]) for (int i = 0; i < mgo.numleft; i++) ProcessIniFile(mgo.argv[i]); /* Write output. */ - if (output_file == NULL) { + if (output_file == nullptr) { CopyFile(before_file, stdout); _stored_output.Write(stdout); CopyFile(after_file, stdout); @@ -498,7 +491,7 @@ int CDECL main(int argc, char *argv[]) static const char * const tmp_output = "tmp2.xxx"; FILE *fp = fopen(tmp_output, "w"); - if (fp == NULL) { + if (fp == nullptr) { fprintf(stderr, "settingsgen: Warning: Cannot open file %s\n", tmp_output); return 1; } diff --git a/src/ship.h b/src/ship.h index 60d4466d68..ef009046a0 100644 --- a/src/ship.h +++ b/src/ship.h @@ -20,17 +20,17 @@ void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); WaterClass GetEffectiveWaterClass(TileIndex tile); -typedef std::deque ShipPathCache; +typedef std::deque ShipPathCache; /** * All ships have this type. */ struct Ship FINAL : public SpecializedVehicle { - TrackBitsByte state; ///< The "track" the ship is following. - ShipPathCache path; ///< Cached path. - DirectionByte rotation; ///< Visible direction. - int16 rotation_x_pos; ///< NOSAVE: X Position before rotation. - int16 rotation_y_pos; ///< NOSAVE: Y Position before rotation. + TrackBits state; ///< The "track" the ship is following. + ShipPathCache path; ///< Cached path. + Direction rotation; ///< Visible direction. + int16 rotation_x_pos; ///< NOSAVE: X Position before rotation. + int16 rotation_y_pos; ///< NOSAVE: Y Position before rotation. /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ Ship() : SpecializedVehicleBase() {} @@ -57,7 +57,7 @@ struct Ship FINAL : public SpecializedVehicle { void SetDestTile(TileIndex tile); }; -static const uint SHIP_MAX_ORDER_DISTANCE = 130; +bool IsShipDestinationTile(TileIndex tile, StationID station); /** * Iterate over all ships. diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index e85e5f9c3b..32d0db689a 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -29,12 +29,13 @@ #include "sound_func.h" #include "ai/ai.hpp" #include "game/game.hpp" -#include "pathfinder/opf/opf_ship.h" #include "engine_base.h" #include "company_base.h" #include "tunnelbridge_map.h" #include "zoom_func.h" #include "framerate_type.h" +#include "industry.h" +#include "industry_map.h" #include "table/strings.h" @@ -146,7 +147,7 @@ static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance) { /* Find the closest depot */ const Depot *depot; - const Depot *best_depot = NULL; + const Depot *best_depot = nullptr; /* If we don't have a maximum distance, i.e. distance = 0, * we want to find any depot so the best distance of no * depot must be more than any correct distance. On the @@ -178,7 +179,6 @@ static void CheckIfShipNeedsService(Vehicle *v) uint max_distance; switch (_settings_game.pf.pathfinder_for_ships) { - case VPF_OPF: max_distance = 12; break; case VPF_NPF: max_distance = _settings_game.pf.npf.maximum_go_to_depot_penalty / NPF_TILE_LENGTH; break; case VPF_YAPF: max_distance = _settings_game.pf.yapf.maximum_go_to_depot_penalty / YAPF_TILE_LENGTH; break; default: NOT_REACHED(); @@ -186,7 +186,7 @@ static void CheckIfShipNeedsService(Vehicle *v) const Depot *depot = FindClosestShipDepot(v, max_distance); - if (depot == NULL) { + if (depot == nullptr) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { v->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); @@ -291,8 +291,8 @@ TileIndex Ship::GetOrderStationLocation(StationID station) if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION; const Station *st = Station::Get(station); - if (st->dock_tile != INVALID_TILE) { - return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); + if (CanVehicleUseStation(this, st)) { + return st->xy; } else { this->IncrementRealOrderIndex(); return 0; @@ -335,7 +335,7 @@ void Ship::UpdateDeltaXY() */ static Vehicle *EnsureNoVisibleShipProc(Vehicle *v, void *data) { - return v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0 ? v : NULL; + return v->type == VEH_SHIP && (v->vehstatus & VS_HIDDEN) == 0 ? v : nullptr; } static bool CheckShipLeaveDepot(Ship *v) @@ -354,7 +354,7 @@ static bool CheckShipLeaveDepot(Ship *v) /* Don't leave depot if another vehicle is already entering/leaving */ /* This helps avoid CPU load if many ships are set to start at the same time */ - if (HasVehicleOnPos(v->tile, NULL, &EnsureNoVisibleShipProc)) return true; + if (HasVehicleOnPos(v->tile, nullptr, &EnsureNoVisibleShipProc)) return true; TileIndex tile = v->tile; Axis axis = GetShipDepotAxis(tile); @@ -369,9 +369,7 @@ static bool CheckShipLeaveDepot(Ship *v) if (north_tracks && south_tracks) { /* Ask pathfinder for best direction */ bool reverse = false; - bool path_found; switch (_settings_game.pf.pathfinder_for_ships) { - case VPF_OPF: reverse = OPFShipChooseTrack(v, north_neighbour, north_dir, north_tracks, path_found) == INVALID_TRACK; break; // OPF always allows reversing case VPF_NPF: reverse = NPFShipCheckReverse(v); break; case VPF_YAPF: reverse = YapfShipCheckReverse(v); break; default: NOT_REACHED(); @@ -470,18 +468,11 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr bool path_found = true; Track track; - if (v->dest_tile == 0 || DistanceManhattan(tile, v->dest_tile) > SHIP_MAX_ORDER_DISTANCE + 5) { - /* No destination or destination too far, don't invoke pathfinder. */ + if (v->dest_tile == 0) { + /* No destination, don't invoke pathfinder. */ track = TrackBitsToTrack(v->state); if (!IsDiagonalTrack(track)) track = TrackToOppositeTrack(track); - if (!HasBit(tracks, track)) { - /* Can't continue in same direction so pick first available track. */ - if (_settings_game.pf.forbid_90_deg) { - tracks &= ~TrackCrossesTracks(TrackdirToTrack(v->GetVehicleTrackdir())); - if (tracks == TRACK_BIT_NONE) return INVALID_TRACK; - } - track = FindFirstTrack(tracks); - } + if (!HasBit(tracks, track)) track = FindFirstTrack(tracks); path_found = false; } else { /* Attempt to follow cached path. */ @@ -499,7 +490,6 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr } switch (_settings_game.pf.pathfinder_for_ships) { - case VPF_OPF: track = OPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; case VPF_NPF: track = NPFShipChooseTrack(v, path_found); break; case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found, v->path); break; default: NOT_REACHED(); @@ -521,9 +511,6 @@ static inline TrackBits GetAvailShipTracks(TileIndex tile, DiagDirection dir, Tr { TrackBits tracks = GetTileShipTrackStatus(tile) & DiagdirReachesTracks(dir); - /* Do not remove 90 degree turns for OPF, as it isn't able to find paths taking it into account. */ - if (_settings_game.pf.forbid_90_deg && _settings_game.pf.pathfinder_for_ships != VPF_OPF) tracks &= ~TrackCrossesTracks(TrackdirToTrack(trackdir)); - return tracks; } @@ -612,6 +599,28 @@ static bool ShipMoveUpDownOnLock(Ship *v) return true; } +/** + * Test if a tile is a docking tile for the given station. + * @param tile Docking tile to test. + * @param station Destination station. + * @return true iff docking tile is next to station. + */ +bool IsShipDestinationTile(TileIndex tile, StationID station) +{ + assert(IsDockingTile(tile)); + /* Check each tile adjacent to docking tile. */ + for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) { + TileIndex t = tile + TileOffsByDiagDir(d); + if (!IsValidTile(t)) continue; + if (IsDockTile(t) && GetStationIndex(t) == station && IsValidDockingDirectionForDock(t, d)) return true; + if (IsTileType(t, MP_INDUSTRY)) { + const Industry *i = Industry::GetByTile(t); + if (i->neutral_station != nullptr && i->neutral_station->index == station) return true; + } + } + return false; +} + static void ShipController(Ship *v) { uint32 r; @@ -680,26 +689,24 @@ static void ShipController(Ship *v) UpdateVehicleTimetable(v, true); v->IncrementRealOrderIndex(); v->current_order.MakeDummy(); - } else { - /* Non-buoy orders really need to reach the tile */ - if (v->dest_tile == gp.new_tile) { - if (v->current_order.IsType(OT_GOTO_DEPOT)) { - if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) { - VehicleEnterDepot(v); - return; - } - } else if (v->current_order.IsType(OT_GOTO_STATION)) { - v->last_station_visited = v->current_order.GetDestination(); - - /* Process station in the orderlist. */ - Station *st = Station::Get(v->current_order.GetDestination()); - if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations - ShipArrivesAt(v, st); - v->BeginLoading(); - } else { // leave stations without docks right aways - v->current_order.MakeLeaveStation(); - v->IncrementRealOrderIndex(); - } + } else if (v->current_order.IsType(OT_GOTO_DEPOT) && + v->dest_tile == gp.new_tile) { + /* Depot orders really need to reach the tile */ + if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) { + VehicleEnterDepot(v); + return; + } + } else if (v->current_order.IsType(OT_GOTO_STATION) && IsDockingTile(gp.new_tile)) { + /* Process station in the orderlist. */ + Station *st = Station::Get(v->current_order.GetDestination()); + if (st->docking_station.Contains(gp.new_tile) && IsShipDestinationTile(gp.new_tile, st->index)) { + v->last_station_visited = st->index; + if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations + ShipArrivesAt(v, st); + v->BeginLoading(); + } else { // leave stations without docks right away + v->current_order.MakeLeaveStation(); + v->IncrementRealOrderIndex(); } } } @@ -767,7 +774,7 @@ static void ShipController(Ship *v) return; } - /* Ship is back on the bridge head, we need to comsume its path + /* Ship is back on the bridge head, we need to consume its path * cache entry here as we didn't have to choose a ship track. */ if (!v->path.empty()) v->path.pop_front(); } @@ -884,10 +891,10 @@ bool Ship::FindClosestDepot(TileIndex *location, DestinationID *destination, boo { const Depot *depot = FindClosestShipDepot(this, 0); - if (depot == NULL) return false; + if (depot == nullptr) return false; - if (location != NULL) *location = depot->xy; - if (destination != NULL) *destination = depot->index; + if (location != nullptr) *location = depot->xy; + if (destination != nullptr) *destination = depot->index; return true; } diff --git a/src/signal.cpp b/src/signal.cpp index b37e15074a..8952000a51 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -192,7 +192,7 @@ static SmallSet _globset("_globset"); ///< set of /** Check whether there is a train on rail, not in a depot */ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) { - if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL; + if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; return v; } @@ -283,13 +283,13 @@ static SigFlags ExploreSegment(Owner owner) if (IsRailDepot(tile)) { if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; exitdir = GetRailDepotDirection(tile); tile += TileOffsByDiagDir(exitdir); enterdir = ReverseDiagDir(exitdir); break; } else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; continue; } else { continue; @@ -306,7 +306,7 @@ static SigFlags ExploreSegment(Owner owner) if (!(flags & SF_TRAIN) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) flags |= SF_TRAIN; } else { if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; } if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile @@ -358,7 +358,7 @@ static SigFlags ExploreSegment(Owner owner) if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; tile += TileOffsByDiagDir(exitdir); break; @@ -367,7 +367,7 @@ static SigFlags ExploreSegment(Owner owner) if (GetTileOwner(tile) != owner) continue; if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; tile += TileOffsByDiagDir(exitdir); break; @@ -377,13 +377,13 @@ static SigFlags ExploreSegment(Owner owner) DiagDirection dir = GetTunnelBridgeDirection(tile); if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; enterdir = dir; exitdir = ReverseDiagDir(dir); tile += TileOffsByDiagDir(exitdir); // just skip to next tile } else { // NOT incoming from the wormhole! if (ReverseDiagDir(enterdir) != dir) continue; - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; + if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum)) flags |= SF_TRAIN; tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile enterdir = INVALID_DIAGDIR; exitdir = INVALID_DIAGDIR; diff --git a/src/signs_base.h b/src/signs_base.h index 3e7b4c4651..a4ee0718b7 100644 --- a/src/signs_base.h +++ b/src/signs_base.h @@ -26,7 +26,7 @@ struct Sign : SignPool::PoolItem<&_sign_pool> { int32 x; int32 y; int32 z; - OwnerByte owner; // placed by this company. Anyone can delete them though. OWNER_NONE for gray signs from old games. + Owner owner; // placed by this company. Anyone can delete them though. OWNER_NONE for gray signs from old games. Sign(Owner owner = INVALID_OWNER); ~Sign(); diff --git a/src/signs_cmd.cpp b/src/signs_cmd.cpp index f359ad4e64..6ae2124d8d 100644 --- a/src/signs_cmd.cpp +++ b/src/signs_cmd.cpp @@ -16,6 +16,7 @@ #include "signs_func.h" #include "command_func.h" #include "tilehighlight_func.h" +#include "viewport_kdtree.h" #include "window_func.h" #include "string_func.h" @@ -58,6 +59,7 @@ CommandCost CmdPlaceSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 si->name = stredup(text); } si->UpdateVirtCoord(); + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeSign(si->index)); InvalidateWindowData(WC_SIGN_LIST, 0, 0); _new_sign_id = si->index; } @@ -79,7 +81,7 @@ CommandCost CmdPlaceSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 CommandCost CmdRenameSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Sign *si = Sign::GetIfValid(p1); - if (si == NULL) return CMD_ERROR; + if (si == nullptr) return CMD_ERROR; if (si->owner == OWNER_DEITY && _current_company != OWNER_DEITY && _game_mode != GM_EDITOR) return CMD_ERROR; /* Rename the signs when empty, otherwise remove it */ @@ -99,6 +101,7 @@ CommandCost CmdRenameSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } else { // Delete sign if (flags & DC_EXEC) { si->sign.MarkDirty(); + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeSign(si->index)); delete si; InvalidateWindowData(WC_SIGN_LIST, 0, 0); diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 56af6e6655..d346ec185b 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -45,7 +45,7 @@ struct SignList { StringFilter string_filter; ///< The match string to be used when the GUIList is (re)-sorted. static bool match_case; ///< Should case sensitive matching be used? - static char default_name[64]; ///< Default sign name, used if Sign::name is NULL. + static char default_name[64]; ///< Default sign name, used if Sign::name is nullptr. /** * Creates a SignList with filtering disabled by default. @@ -60,33 +60,33 @@ struct SignList { DEBUG(misc, 3, "Building sign list"); - this->signs.Clear(); + this->signs.clear(); const Sign *si; - FOR_ALL_SIGNS(si) *this->signs.Append() = si; + FOR_ALL_SIGNS(si) this->signs.push_back(si); this->signs.SetFilterState(true); this->FilterSignList(); - this->signs.Compact(); + this->signs.shrink_to_fit(); this->signs.RebuildDone(); } /** Sort signs by their name */ - static int CDECL SignNameSorter(const Sign * const *a, const Sign * const *b) + static bool SignNameSorter(const Sign * const &a, const Sign * const &b) { /* Signs are very very rarely using the default text, but there can also be * a lot of them. Therefore a worthwhile performance gain can be made by * directly comparing Sign::name instead of going through the string * system for each comparison. */ - const char *a_name = (*a)->name; - const char *b_name = (*b)->name; + const char *a_name = a->name; + const char *b_name = b->name; - if (a_name == NULL) a_name = SignList::default_name; - if (b_name == NULL) b_name = SignList::default_name; + if (a_name == nullptr) a_name = SignList::default_name; + if (b_name == nullptr) b_name = SignList::default_name; int r = strnatcmp(a_name, b_name); // Sort by name (natural sorting). - return r != 0 ? r : ((*a)->index - (*b)->index); + return r != 0 ? r < 0 : (a->index < b->index); } void SortSignsList() @@ -100,7 +100,7 @@ struct SignList { /* Same performance benefit as above for sorting. */ const char *a_name = (*a)->name; - if (a_name == NULL) a_name = SignList::default_name; + if (a_name == nullptr) a_name = SignList::default_name; filter.ResetState(); filter.AddLine(a_name); @@ -166,9 +166,9 @@ struct SignListWindow : Window, SignList { this->BuildSortSignList(); } - virtual void OnInit() + void OnInit() override { - /* Default sign name, used if Sign::name is NULL. */ + /* Default sign name, used if Sign::name is nullptr. */ GetString(SignList::default_name, STR_DEFAULT_SIGN_NAME, lastof(SignList::default_name)); this->signs.ForceResort(); this->SortSignsList(); @@ -190,13 +190,13 @@ struct SignListWindow : Window, SignList { this->InvalidateData(); } - virtual void OnPaint() + void OnPaint() override { if (!this->IsShaded() && this->signs.NeedRebuild()) this->BuildSortSignList(); this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_SIL_LIST: { @@ -228,12 +228,12 @@ struct SignListWindow : Window, SignList { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_SIL_CAPTION) SetDParam(0, this->vscroll->GetCount()); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SIL_LIST: { @@ -246,7 +246,7 @@ struct SignListWindow : Window, SignList { } case WID_SIL_FILTER_ENTER_BTN: - if (this->signs.Length() >= 1) { + if (this->signs.size() >= 1) { const Sign *si = this->signs[0]; ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); } @@ -260,12 +260,12 @@ struct SignListWindow : Window, SignList { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SIL_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SIL_LIST: { @@ -286,7 +286,7 @@ struct SignListWindow : Window, SignList { } } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { switch (hotkey) { case SLHK_FOCUS_FILTER_BOX: @@ -301,7 +301,7 @@ struct SignListWindow : Window, SignList { return ES_HANDLED; } - virtual void OnEditboxChanged(int widget) + void OnEditboxChanged(int widget) override { if (widget == WID_SIL_FILTER_TEXT) this->SetFilterString(this->filter_editbox.text.buf); } @@ -310,13 +310,13 @@ struct SignListWindow : Window, SignList { { if (this->signs.NeedRebuild()) { this->BuildSignsList(); - this->vscroll->SetCount(this->signs.Length()); + this->vscroll->SetCount((uint)this->signs.size()); this->SetWidgetDirty(WID_SIL_CAPTION); } this->SortSignsList(); } - virtual void OnHundredthTick() + void OnHundredthTick() override { this->BuildSortSignList(); this->SetDirty(); @@ -327,7 +327,7 @@ struct SignListWindow : Window, SignList { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { /* When there is a filter string, we always need to rebuild the list even if * the amount of signs in total is unchanged, as the subset of signs that is @@ -352,7 +352,7 @@ static EventState SignListGlobalHotkeys(int hotkey) { if (_game_mode == GM_MENU) return ES_NOT_HANDLED; Window *w = ShowSignList(); - if (w == NULL) return ES_NOT_HANDLED; + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -402,7 +402,7 @@ static WindowDesc _sign_list_desc( /** * Open the sign list window * - * @return newly opened sign list window, or NULL if the window could not be opened. + * @return newly opened sign list window, or nullptr if the window could not be opened. */ Window *ShowSignList() { @@ -418,7 +418,7 @@ Window *ShowSignList() static bool RenameSign(SignID index, const char *text) { bool remove = StrEmpty(text); - DoCommandP(0, index, 0, CMD_RENAME_SIGN | (StrEmpty(text) ? CMD_MSG(STR_ERROR_CAN_T_DELETE_SIGN) : CMD_MSG(STR_ERROR_CAN_T_CHANGE_SIGN_NAME)), NULL, text); + DoCommandP(0, index, 0, CMD_RENAME_SIGN | (StrEmpty(text) ? CMD_MSG(STR_ERROR_CAN_T_DELETE_SIGN) : CMD_MSG(STR_ERROR_CAN_T_CHANGE_SIGN_NAME)), nullptr, text); return remove; } @@ -442,7 +442,7 @@ struct SignWindow : Window, SignList { void UpdateSignEditWindow(const Sign *si) { /* Display an empty string when the sign hasn't been edited yet */ - if (si->name != NULL) { + if (si->name != nullptr) { SetDParam(0, si->index); this->name_editbox.text.Assign(STR_SIGN_NAME); } else { @@ -471,7 +471,7 @@ struct SignWindow : Window, SignList { /* Search through the list for the current sign, excluding * - the first sign if we want the previous sign or * - the last sign if we want the next sign */ - uint end = this->signs.Length() - (next ? 1 : 0); + size_t end = this->signs.size() - (next ? 1 : 0); for (uint i = next ? 0 : 1; i < end; i++) { if (this->cur_sign == this->signs[i]->index) { /* We've found the current sign, so return the sign before/after it */ @@ -479,10 +479,10 @@ struct SignWindow : Window, SignList { } } /* If we haven't found the current sign by now, return the last/first sign */ - return this->signs[next ? 0 : this->signs.Length() - 1]; + return next ? this->signs.front() : this->signs.back(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_QES_CAPTION: @@ -491,7 +491,7 @@ struct SignWindow : Window, SignList { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_QES_PREVIOUS: @@ -559,7 +559,7 @@ static WindowDesc _query_sign_edit_desc( void HandleClickOnSign(const Sign *si) { if (_ctrl_pressed && (si->owner == _local_company || (si->owner == OWNER_DEITY && _game_mode == GM_EDITOR))) { - RenameSign(si->index, NULL); + RenameSign(si->index, nullptr); return; } ShowRenameSignWindow(si); @@ -585,5 +585,5 @@ void DeleteRenameSignWindow(SignID sign) { SignWindow *w = dynamic_cast(FindWindowById(WC_QUERY_STRING, WN_QUERY_STRING_SIGN)); - if (w != NULL && w->cur_sign == sign) delete w; + if (w != nullptr && w->cur_sign == sign) delete w; } diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 276e1ace9c..6205246e8c 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -47,7 +47,7 @@ static const uint8 PC_GRASS_LAND = 0x54; ///< Dark green palette colour for static const uint8 PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land. static const uint8 PC_FIELDS = 0x25; ///< Light brown palette colour for fields. static const uint8 PC_TREES = 0x57; ///< Green palette colour for trees. -static const uint8 PC_WATER = 0xCA; ///< Dark blue palette colour for water. +static const uint8 PC_WATER = 0xC9; ///< Dark blue palette colour for water. /** Macro for ordinary entry of LegendAndColour */ #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} @@ -178,8 +178,7 @@ void BuildIndustriesLegend() uint j = 0; /* Add each name */ - for (uint i = 0; i < NUM_INDUSTRYTYPES; i++) { - IndustryType ind = _sorted_industry_types[i]; + for (IndustryType ind : _sorted_industry_types) { const IndustrySpec *indsp = GetIndustrySpec(ind); if (indsp->enabled) { _legend_from_industries[j].legend = indsp->name; @@ -210,7 +209,7 @@ void BuildLinkStatsLegend() memset(_legend_linkstats, 0, sizeof(_legend_linkstats)); uint i = 0; - for (; i < _sorted_cargo_specs_size; ++i) { + for (; i < _sorted_cargo_specs.size(); ++i) { const CargoSpec *cs = _sorted_cargo_specs[i]; _legend_linkstats[i].legend = cs->name; @@ -272,9 +271,9 @@ struct SmallMapColourScheme { /** Available colour schemes for height maps. */ static SmallMapColourScheme _heightmap_schemes[] = { - {NULL, _green_map_heights, lengthof(_green_map_heights), MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme. - {NULL, _dark_green_map_heights, lengthof(_dark_green_map_heights), MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme. - {NULL, _violet_map_heights, lengthof(_violet_map_heights), MKCOLOUR_XXXX(0x82)}, ///< Violet colour scheme. + {nullptr, _green_map_heights, lengthof(_green_map_heights), MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme. + {nullptr, _dark_green_map_heights, lengthof(_dark_green_map_heights), MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme. + {nullptr, _violet_map_heights, lengthof(_violet_map_heights), MKCOLOUR_XXXX(0x81)}, ///< Violet colour scheme. }; /** @@ -283,7 +282,7 @@ static SmallMapColourScheme _heightmap_schemes[] = { void BuildLandLegend() { /* The smallmap window has never been initialized, so no need to change the legend. */ - if (_heightmap_schemes[0].height_colours == NULL) return; + if (_heightmap_schemes[0].height_colours == nullptr) return; /* * The general idea of this function is to fill the legend with an appropriate evenly spaced @@ -461,28 +460,51 @@ static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t) */ static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t) { - if (t == MP_STATION) { - switch (GetStationType(tile)) { - case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); - case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); - case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); - case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); - case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); - default: return MKCOLOUR_FFFF; + switch (t) { + case MP_STATION: + switch (GetStationType(tile)) { + case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); + case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); + case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); + case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); + case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); + default: return MKCOLOUR_FFFF; + } + + case MP_RAILWAY: { + AndOr andor = { + MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), + _smallmap_contours_andor[t].mand + }; + + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &andor); } - } else if (t == MP_RAILWAY) { - AndOr andor = { - MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), - _smallmap_contours_andor[t].mand - }; - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &andor); + case MP_ROAD: { + const RoadTypeInfo *rti = nullptr; + if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) { + rti = GetRoadTypeInfo(GetRoadTypeRoad(tile)); + } else { + rti = GetRoadTypeInfo(GetRoadTypeTram(tile)); + } + if (rti != nullptr) { + AndOr andor = { + MKCOLOUR_0XX0(rti->map_colour), + _smallmap_contours_andor[t].mand + }; + + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &andor); + } + FALLTHROUGH; + } + + default: + /* Ground colour */ + const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; + return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); } - - /* Ground colour */ - const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; - return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); } /** @@ -567,7 +589,7 @@ static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t) return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour); } -/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleTypeByte. */ +/** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleType. */ static const byte _vehicle_type_colours[6] = { PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED }; @@ -1071,7 +1093,7 @@ SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(des this->SetupWidgetData(); - this->SetZoomLevel(ZLC_INITIALIZE, NULL); + this->SetZoomLevel(ZLC_INITIALIZE, nullptr); this->SmallMapCenterOnCurrentPos(); this->SetOverlayCargoMask(); } @@ -1474,7 +1496,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt) case WID_SM_ENABLE_ALL: case WID_SM_DISABLE_ALL: { - LegendAndColour *tbl = NULL; + LegendAndColour *tbl = nullptr; switch (this->map_type) { case SMT_INDUSTRY: tbl = _legend_from_industries; @@ -1682,10 +1704,10 @@ class NWidgetSmallmapDisplay : public NWidgetContainer { public: NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL) { - this->smallmap_window = NULL; + this->smallmap_window = nullptr; } - virtual void SetupSmallestSize(Window *w, bool init_array) + void SetupSmallestSize(Window *w, bool init_array) override { NWidgetBase *display = this->head; NWidgetBase *bar = display->next; @@ -1694,7 +1716,7 @@ public: bar->SetupSmallestSize(w, init_array); this->smallmap_window = dynamic_cast(w); - assert(this->smallmap_window != NULL); + assert(this->smallmap_window != nullptr); this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth()); this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns)); this->fill_x = max(display->fill_x, bar->fill_x); @@ -1703,7 +1725,7 @@ public: this->resize_y = min(display->resize_y, bar->resize_y); } - virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override { this->pos_x = x; this->pos_y = y; @@ -1727,19 +1749,19 @@ public: bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl); } - virtual NWidgetCore *GetWidgetFromPos(int x, int y) + NWidgetCore *GetWidgetFromPos(int x, int y) override { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y); - if (widget != NULL) return widget; + if (widget != nullptr) return widget; } - return NULL; + return nullptr; } - virtual void Draw(const Window *w) + void Draw(const Window *w) override { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w); + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) child_wid->Draw(w); } }; @@ -1862,7 +1884,7 @@ bool ScrollMainWindowTo(int x, int y, int z, bool instant) if (res) return res; SmallMapWindow *w = dynamic_cast(FindWindowById(WC_SMALLMAP, 0)); - if (w != NULL) w->SmallMapCenterOnCurrentPos(); + if (w != nullptr) w->SmallMapCenterOnCurrentPos(); return res; } diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index 486f2a6524..a167d81988 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -180,17 +180,17 @@ public: void SmallMapCenterOnCurrentPos(); Point GetStationMiddle(const Station *st) const; - virtual void SetStringParameters(int widget) const; - virtual void OnInit(); - virtual void OnPaint(); - virtual void DrawWidget(const Rect &r, int widget) const; - virtual void OnClick(Point pt, int widget, int click_count); - virtual void OnInvalidateData(int data = 0, bool gui_scope = true); - virtual bool OnRightClick(Point pt, int widget); - virtual void OnMouseWheel(int wheel); - virtual void OnRealtimeTick(uint delta_ms); - virtual void OnScroll(Point delta); - virtual void OnMouseOver(Point pt, int widget); + void SetStringParameters(int widget) const override; + void OnInit() override; + void OnPaint() override; + void DrawWidget(const Rect &r, int widget) const override; + void OnClick(Point pt, int widget, int click_count) override; + void OnInvalidateData(int data = 0, bool gui_scope = true) override; + bool OnRightClick(Point pt, int widget) override; + void OnMouseWheel(int wheel) override; + void OnRealtimeTick(uint delta_ms) override; + void OnScroll(Point delta) override; + void OnMouseOver(Point pt, int widget) override; }; #endif /* SMALLMAP_GUI_H */ diff --git a/src/sortlist_type.h b/src/sortlist_type.h index 1a30c3b1a8..47f6638634 100644 --- a/src/sortlist_type.h +++ b/src/sortlist_type.h @@ -14,7 +14,6 @@ #include "core/enum_type.hpp" #include "core/bitmath_func.hpp" -#include "core/sort_func.hpp" #include "core/smallvec_type.hpp" #include "date_type.h" @@ -47,10 +46,10 @@ struct Filtering { * @tparam F Type of data fed as additional value to the filter function. @see FilterFunction */ template -class GUIList : public SmallVector { +class GUIList : public std::vector { public: - typedef int CDECL SortFunction(const T*, const T*); ///< Signature of sort function. - typedef bool CDECL FilterFunction(const T*, F); ///< Signature of filter function. + typedef bool SortFunction(const T&, const T&); ///< Signature of sort function. + typedef bool CDECL FilterFunction(const T*, F); ///< Signature of filter function. protected: SortFunction * const *sort_func_list; ///< the sort criteria functions @@ -67,7 +66,7 @@ protected: */ bool IsSortable() const { - return (this->data != NULL && this->items >= 2); + return std::vector::size() >= 2; } /** @@ -81,8 +80,8 @@ protected: public: GUIList() : - sort_func_list(NULL), - filter_func_list(NULL), + sort_func_list(nullptr), + filter_func_list(nullptr), flags(VL_FIRST_SORT), sort_type(0), filter_type(0), @@ -240,7 +239,7 @@ public: { this->flags ^= VL_DESC; - if (this->IsSortable()) MemReverseT(this->data, this->items); + if (this->IsSortable()) MemReverseT(std::vector::data(), std::vector::size()); } /** @@ -270,11 +269,11 @@ public: if (this->flags & VL_FIRST_SORT) { CLRBITS(this->flags, VL_FIRST_SORT); - QSortT(this->data, this->items, compare, desc); + std::sort(std::vector::begin(), std::vector::end(), [&](const T &a, const T &b) { return desc ? compare(b, a) : compare(a, b); }); return true; } - GSortT(this->data, this->items, compare, desc); + std::sort(std::vector::begin(), std::vector::end(), [&](const T &a, const T &b) { return desc ? compare(b, a) : compare(a, b); }); return true; } @@ -296,7 +295,7 @@ public: */ bool Sort() { - assert(this->sort_func_list != NULL); + assert(this->sort_func_list != nullptr); return this->Sort(this->sort_func_list[this->sort_type]); } @@ -337,13 +336,12 @@ public: if (!(this->flags & VL_FILTER)) return false; bool changed = false; - for (uint iter = 0; iter < this->items;) { - T *item = &this->data[iter]; - if (!decide(item, filter_data)) { - this->Erase(item); + for (auto it = std::vector::begin(); it != std::vector::end(); /* Nothing */) { + if (!decide(&*it, filter_data)) { + it = std::vector::erase(it); changed = true; } else { - iter++; + it++; } } @@ -368,7 +366,7 @@ public: */ bool Filter(F filter_data) { - if (this->filter_func_list == NULL) return false; + if (this->filter_func_list == nullptr) return false; return this->Filter(this->filter_func_list[this->filter_type], filter_data); } diff --git a/src/sound.cpp b/src/sound.cpp index 79dd988bfa..0b21ef1229 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -30,7 +30,7 @@ static void OpenBankFile(const char *filename) memset(_original_sounds, 0, sizeof(_original_sounds)); /* If there is no sound file (nosound set), don't load anything */ - if (filename == NULL) return; + if (filename == nullptr) return; FioOpenFile(SOUND_SLOT, filename, BASESET_DIR); size_t pos = FioGetPos(); @@ -110,7 +110,7 @@ static void OpenBankFile(const char *filename) static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound) { - assert(sound != NULL); + assert(sound != nullptr); /* Check for valid sound size. */ if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false; @@ -162,7 +162,7 @@ static void StartSound(SoundID sound_id, float pan, uint volume) if (volume == 0) return; SoundEntry *sound = GetSound(sound_id); - if (sound == NULL) return; + if (sound == nullptr) return; /* NewGRF sound that wasn't loaded yet? */ if (sound->rate == 0 && sound->file_slot != 0) { @@ -177,7 +177,7 @@ static void StartSound(SoundID sound_id, float pan, uint volume) if (sound->rate == 0) return; MixerChannel *mc = MxAllocateChannel(); - if (mc == NULL) return; + if (mc == nullptr) return; if (!SetBankSource(mc, sound)) return; @@ -244,7 +244,7 @@ static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, in FOR_ALL_WINDOWS_FROM_BACK(w) { const ViewPort *vp = w->viewport; - if (vp != NULL && + if (vp != nullptr && left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left && top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) { int screen_x = (left + right) / 2 - vp->virtual_left; @@ -304,14 +304,14 @@ template template /* static */ bool BaseMedia::DetermineBestSet() { - if (BaseMedia::used_set != NULL) return true; + if (BaseMedia::used_set != nullptr) return true; - const Tbase_set *best = NULL; - for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { + const Tbase_set *best = nullptr; + for (const Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { /* Skip unusable sets */ if (c->GetNumMissing() != 0) continue; - if (best == NULL || + if (best == nullptr || (best->fallback && !c->fallback) || best->valid_files < c->valid_files || (best->valid_files == c->valid_files && @@ -321,6 +321,6 @@ template } BaseMedia::used_set = best; - return BaseMedia::used_set != NULL; + return BaseMedia::used_set != nullptr; } diff --git a/src/sound/allegro_s.cpp b/src/sound/allegro_s.cpp index 88a723ff85..f6bb963062 100644 --- a/src/sound/allegro_s.cpp +++ b/src/sound/allegro_s.cpp @@ -22,18 +22,18 @@ static FSoundDriver_Allegro iFSoundDriver_Allegro; /** The stream we are writing too */ -static AUDIOSTREAM *_stream = NULL; +static AUDIOSTREAM *_stream = nullptr; /** The number of samples in the buffer */ static int _buffer_size; void SoundDriver_Allegro::MainLoop() { /* We haven't opened a stream yet */ - if (_stream == NULL) return; + if (_stream == nullptr) return; void *data = get_audio_stream_buffer(_stream); /* We don't have to fill the stream yet */ - if (data == NULL) return; + if (data == nullptr) return; /* Mix the samples */ MxMixSamples(data, _buffer_size); @@ -54,14 +54,14 @@ extern int _allegro_instance_count; const char *SoundDriver_Allegro::Start(const char * const *parm) { - if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, NULL)) { + if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); return "Failed to set up Allegro"; } _allegro_instance_count++; /* Initialise the sound */ - if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) != 0) { + if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, nullptr) != 0) { DEBUG(driver, 0, "allegro: install_sound failed '%s'", allegro_error); return "Failed to set up Allegro sound"; } @@ -76,14 +76,14 @@ const char *SoundDriver_Allegro::Start(const char * const *parm) _buffer_size = GetDriverParamInt(parm, "samples", 1024) * hz / 11025; _stream = play_audio_stream(_buffer_size, 16, true, hz, 255, 128); MxInitialize(hz); - return NULL; + return nullptr; } void SoundDriver_Allegro::Stop() { - if (_stream != NULL) { + if (_stream != nullptr) { stop_audio_stream(_stream); - _stream = NULL; + _stream = nullptr; } remove_sound(); diff --git a/src/sound/allegro_s.h b/src/sound/allegro_s.h index e0a247f7b3..2ad3717401 100644 --- a/src/sound/allegro_s.h +++ b/src/sound/allegro_s.h @@ -7,7 +7,7 @@ * See the GNU 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 allegro_s.h Base fo playing sound via Allegro. */ +/** @file allegro_s.h Base for playing sound via Allegro. */ #ifndef SOUND_ALLEGRO_H #define SOUND_ALLEGRO_H @@ -17,12 +17,12 @@ /** Implementation of the allegro sound driver. */ class SoundDriver_Allegro : public SoundDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param); - /* virtual */ void Stop(); + void Stop(); - /* virtual */ void MainLoop(); - /* virtual */ const char *GetName() const { return "allegro"; } + void MainLoop(); + const char *GetName() const { return "allegro"; } }; /** Factory for the allegro sound driver. */ diff --git a/src/sound/cocoa_s.cpp b/src/sound/cocoa_s.cpp index 8133bf62f6..13fe176f55 100644 --- a/src/sound/cocoa_s.cpp +++ b/src/sound/cocoa_s.cpp @@ -80,9 +80,9 @@ const char *SoundDriver_Cocoa::Start(const char * const *parm) desc.componentFlags = 0; desc.componentFlagsMask = 0; - AudioComponent comp = AudioComponentFindNext (NULL, &desc); - if (comp == NULL) { - return "cocoa_s: Failed to start CoreAudio: AudioComponentFindNext returned NULL"; + AudioComponent comp = AudioComponentFindNext (nullptr, &desc); + if (comp == nullptr) { + return "cocoa_s: Failed to start CoreAudio: AudioComponentFindNext returned nullptr"; } /* Open & initialize the default output audio unit */ @@ -101,9 +101,9 @@ const char *SoundDriver_Cocoa::Start(const char * const *parm) desc.componentFlags = 0; desc.componentFlagsMask = 0; - Component comp = FindNextComponent (NULL, &desc); - if (comp == NULL) { - return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL"; + Component comp = FindNextComponent (nullptr, &desc); + if (comp == nullptr) { + return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned nullptr"; } /* Open & initialize the default output audio unit */ @@ -126,7 +126,7 @@ const char *SoundDriver_Cocoa::Start(const char * const *parm) /* Set the audio callback */ callback.inputProc = audioCallback; - callback.inputProcRefCon = NULL; + callback.inputProcRefCon = nullptr; if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) { return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)"; } @@ -137,7 +137,7 @@ const char *SoundDriver_Cocoa::Start(const char * const *parm) } /* We're running! */ - return NULL; + return nullptr; } diff --git a/src/sound/cocoa_s.h b/src/sound/cocoa_s.h index 7010914258..dd2d740204 100644 --- a/src/sound/cocoa_s.h +++ b/src/sound/cocoa_s.h @@ -16,16 +16,16 @@ class SoundDriver_Cocoa : public SoundDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); - /* virtual */ const char *GetName() const { return "cocoa"; } + void Stop() override; + const char *GetName() const override { return "cocoa"; } }; class FSoundDriver_Cocoa : public DriverFactoryBase { public: FSoundDriver_Cocoa() : DriverFactoryBase(Driver::DT_SOUND, 10, "cocoa", "Cocoa Sound Driver") {} - /* virtual */ Driver *CreateInstance() const { return new SoundDriver_Cocoa(); } + Driver *CreateInstance() const override { return new SoundDriver_Cocoa(); } }; #endif /* SOUND_COCOA_H */ diff --git a/src/sound/null_s.h b/src/sound/null_s.h index b2acd90937..e1e2ad4607 100644 --- a/src/sound/null_s.h +++ b/src/sound/null_s.h @@ -17,17 +17,17 @@ /** Implementation of the null sound driver. */ class SoundDriver_Null : public SoundDriver { public: - /* virtual */ const char *Start(const char * const *param) { return NULL; } + const char *Start(const char * const *param) override { return nullptr; } - /* virtual */ void Stop() { } - /* virtual */ const char *GetName() const { return "null"; } + void Stop() override { } + const char *GetName() const override { return "null"; } }; /** Factory for the null sound driver. */ class FSoundDriver_Null : public DriverFactoryBase { public: FSoundDriver_Null() : DriverFactoryBase(Driver::DT_SOUND, 1, "null", "Null Sound Driver") {} - /* virtual */ Driver *CreateInstance() const { return new SoundDriver_Null(); } + Driver *CreateInstance() const override { return new SoundDriver_Null(); } }; #endif /* SOUND_NULL_H */ diff --git a/src/sound/sdl2_s.cpp b/src/sound/sdl2_s.cpp new file mode 100644 index 0000000000..98839b1c22 --- /dev/null +++ b/src/sound/sdl2_s.cpp @@ -0,0 +1,70 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 sdl2_s.cpp Playing sound via SDL2. */ + +#ifdef WITH_SDL2 + +#include "../stdafx.h" + +#include "../mixer.h" +#include "sdl_s.h" +#include + +#include "../safeguards.h" + +/** Factory for the SDL sound driver. */ +static FSoundDriver_SDL iFSoundDriver_SDL; + +/** + * Callback that fills the sound buffer. + * @param userdata Ignored. + * @param stream The stream to put data into. + * @param len The length of the stream in bytes. + */ +static void CDECL fill_sound_buffer(void *userdata, Uint8 *stream, int len) +{ + MxMixSamples(stream, len / 4); +} + +const char *SoundDriver_SDL::Start(const char * const *parm) +{ + SDL_AudioSpec spec; + SDL_AudioSpec spec_actual; + + /* Only initialise SDL if the video driver hasn't done it already */ + int ret_code = 0; + if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) { + ret_code = SDL_Init(SDL_INIT_AUDIO); + } else if (SDL_WasInit(SDL_INIT_AUDIO) == 0) { + ret_code = SDL_InitSubSystem(SDL_INIT_AUDIO); + } + if (ret_code == -1) return SDL_GetError(); + + spec.freq = GetDriverParamInt(parm, "hz", 44100); + spec.format = AUDIO_S16SYS; + spec.channels = 2; + spec.samples = GetDriverParamInt(parm, "samples", 1024); + spec.callback = fill_sound_buffer; + SDL_AudioDeviceID dev = SDL_OpenAudioDevice(nullptr, 0, &spec, &spec_actual, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE); + MxInitialize(spec_actual.freq); + SDL_PauseAudioDevice(dev, 0); + return nullptr; +} + +void SoundDriver_SDL::Stop() +{ + SDL_CloseAudio(); + SDL_QuitSubSystem(SDL_INIT_AUDIO); + if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) { + SDL_Quit(); // If there's nothing left, quit SDL + } +} + +#endif /* WITH_SDL2 */ diff --git a/src/sound/sdl_s.cpp b/src/sound/sdl_s.cpp index b37016c24e..f8041aa846 100644 --- a/src/sound/sdl_s.cpp +++ b/src/sound/sdl_s.cpp @@ -54,7 +54,7 @@ const char *SoundDriver_SDL::Start(const char * const *parm) MxInitialize(spec.freq); SDL_OpenAudio(&spec, &spec); SDL_PauseAudio(0); - return NULL; + return nullptr; } void SoundDriver_SDL::Stop() diff --git a/src/sound/sdl_s.h b/src/sound/sdl_s.h index 544ce2070d..47352b5175 100644 --- a/src/sound/sdl_s.h +++ b/src/sound/sdl_s.h @@ -7,7 +7,7 @@ * See the GNU 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 sdl_s.h Base fo playing sound via SDL. */ +/** @file sdl_s.h Base for playing sound via SDL. */ #ifndef SOUND_SDL_H #define SOUND_SDL_H @@ -17,17 +17,17 @@ /** Implementation of the SDL sound driver. */ class SoundDriver_SDL : public SoundDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); - /* virtual */ const char *GetName() const { return "sdl"; } + void Stop() override; + const char *GetName() const override { return "sdl"; } }; /** Factory for the SDL sound driver. */ class FSoundDriver_SDL : public DriverFactoryBase { public: FSoundDriver_SDL() : DriverFactoryBase(Driver::DT_SOUND, 5, "sdl", "SDL Sound Driver") {} - /* virtual */ Driver *CreateInstance() const { return new SoundDriver_SDL(); } + Driver *CreateInstance() const override { return new SoundDriver_SDL(); } }; #endif /* SOUND_SDL_H */ diff --git a/src/sound/win32_s.cpp b/src/sound/win32_s.cpp index c9c1a8afdc..d16e5be2dc 100644 --- a/src/sound/win32_s.cpp +++ b/src/sound/win32_s.cpp @@ -20,6 +20,7 @@ #include #include #include "../os/windows/win32.h" +#include "../thread.h" #include "../safeguards.h" @@ -42,19 +43,19 @@ static void PrepareHeader(WAVEHDR *hdr) static DWORD WINAPI SoundThread(LPVOID arg) { - SetWin32ThreadName(-1, "ottd:win-sound"); + SetCurrentThreadName("ottd:win-sound"); do { for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) { if ((hdr->dwFlags & WHDR_INQUEUE) != 0) continue; MxMixSamples(hdr->lpData, hdr->dwBufferLength / 4); if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) { - MessageBox(NULL, _T("Sounds are disabled until restart."), _T("waveOutWrite failed"), MB_ICONINFORMATION); + MessageBox(nullptr, _T("Sounds are disabled until restart."), _T("waveOutWrite failed"), MB_ICONINFORMATION); return 0; } } WaitForSingleObject(_event, INFINITE); - } while (_waveout != NULL); + } while (_waveout != nullptr); return 0; } @@ -74,7 +75,7 @@ const char *SoundDriver_Win32::Start(const char * const *parm) _bufsize = min(_bufsize, UINT16_MAX); try { - if (NULL == (_event = CreateEvent(NULL, FALSE, FALSE, NULL))) throw "Failed to create event"; + if (nullptr == (_event = CreateEvent(nullptr, FALSE, FALSE, nullptr))) throw "Failed to create event"; if (waveOutOpen(&_waveout, WAVE_MAPPER, &wfex, (DWORD_PTR)_event, 0, CALLBACK_EVENT) != MMSYSERR_NOERROR) throw "waveOutOpen failed"; @@ -83,13 +84,13 @@ const char *SoundDriver_Win32::Start(const char * const *parm) PrepareHeader(&_wave_hdr[0]); PrepareHeader(&_wave_hdr[1]); - if (NULL == (_thread = CreateThread(NULL, 8192, SoundThread, 0, 0, &_threadId))) throw "Failed to create thread"; + if (nullptr == (_thread = CreateThread(nullptr, 8192, SoundThread, 0, 0, &_threadId))) throw "Failed to create thread"; } catch (const char *error) { this->Stop(); return error; } - return NULL; + return nullptr; } void SoundDriver_Win32::Stop() @@ -97,7 +98,7 @@ void SoundDriver_Win32::Stop() HWAVEOUT waveout = _waveout; /* Stop the sound thread. */ - _waveout = NULL; + _waveout = nullptr; SetEvent(_event); WaitForSingleObject(_thread, INFINITE); diff --git a/src/sound/win32_s.h b/src/sound/win32_s.h index c6c8e8d149..a0d53a2dae 100644 --- a/src/sound/win32_s.h +++ b/src/sound/win32_s.h @@ -17,17 +17,17 @@ /** Implementation of the sound driver for Windows. */ class SoundDriver_Win32 : public SoundDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); - /* virtual */ const char *GetName() const { return "win32"; } + void Stop() override; + const char *GetName() const override { return "win32"; } }; /** Factory for the sound driver for Windows. */ class FSoundDriver_Win32 : public DriverFactoryBase { public: FSoundDriver_Win32() : DriverFactoryBase(Driver::DT_SOUND, 9, "win32", "Win32 WaveOut Sound Driver") {} - /* virtual */ Driver *CreateInstance() const { return new SoundDriver_Win32(); } + Driver *CreateInstance() const override { return new SoundDriver_Win32(); } }; #endif /* SOUND_WIN32_H */ diff --git a/src/sound/xaudio2_s.cpp b/src/sound/xaudio2_s.cpp index 60311ced20..2acfd20a3f 100644 --- a/src/sound/xaudio2_s.cpp +++ b/src/sound/xaudio2_s.cpp @@ -125,7 +125,7 @@ static StreamingVoiceContext* _voice_context = nullptr; * Initialises the XAudio2 driver. * * @param parm Driver parameters. -* @return An error message if unsuccessful, or NULL otherwise. +* @return An error message if unsuccessful, or nullptr otherwise. * */ const char *SoundDriver_XAudio2::Start(const char * const *parm) @@ -140,7 +140,7 @@ const char *SoundDriver_XAudio2::Start(const char * const *parm) _xaudio_dll_handle = LoadLibraryA(XAUDIO2_DLL_A); - if (_xaudio_dll_handle == NULL) + if (_xaudio_dll_handle == nullptr) { CoUninitialize(); @@ -150,7 +150,7 @@ const char *SoundDriver_XAudio2::Start(const char * const *parm) API_XAudio2Create xAudio2Create = (API_XAudio2Create) GetProcAddress(_xaudio_dll_handle, "XAudio2Create"); - if (xAudio2Create == NULL) + if (xAudio2Create == nullptr) { FreeLibrary(_xaudio_dll_handle); CoUninitialize(); @@ -248,7 +248,7 @@ const char *SoundDriver_XAudio2::Start(const char * const *parm) return "Failed to submit the first audio buffer"; } - return NULL; + return nullptr; } /** diff --git a/src/sound/xaudio2_s.h b/src/sound/xaudio2_s.h index 2385f49ee2..f3525251cf 100644 --- a/src/sound/xaudio2_s.h +++ b/src/sound/xaudio2_s.h @@ -17,17 +17,17 @@ /** Implementation of the XAudio2 sound driver. */ class SoundDriver_XAudio2 : public SoundDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); - /* virtual */ const char *GetName() const { return "xaudio2"; } + void Stop() override; + const char *GetName() const override { return "xaudio2"; } }; /** Factory for the XAudio2 sound driver. */ class FSoundDriver_XAudio2 : public DriverFactoryBase { public: FSoundDriver_XAudio2() : DriverFactoryBase(Driver::DT_SOUND, 10, "xaudio2", "XAudio2 Sound Driver") {} - /* virtual */ Driver *CreateInstance() const { return new SoundDriver_XAudio2(); } + Driver *CreateInstance() const override { return new SoundDriver_XAudio2(); } }; #endif /* SOUND_XAUDIO2_H */ diff --git a/src/sprite.cpp b/src/sprite.cpp index 22210712a9..26b4c4869f 100644 --- a/src/sprite.cpp +++ b/src/sprite.cpp @@ -75,7 +75,7 @@ void DrawCommonTileSeq(const TileInfo *ti, const DrawTileSprites *dts, Transpare SetBit(image, PALETTE_MODIFIER_TRANSPARENT); pal = PALETTE_TO_TRANSPARENT; } - DrawGroundSprite(image, pal, NULL, offs_x, offs_y); + DrawGroundSprite(image, pal, nullptr, offs_x, offs_y); } } } diff --git a/src/spritecache.cpp b/src/spritecache.cpp index 8a5a25ac00..bcc0048278 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -29,22 +29,20 @@ /* Default of 4MB spritecache */ uint _sprite_cache_size = 4; -typedef SimpleTinyEnumT SpriteTypeByte; - struct SpriteCache { void *ptr; size_t file_pos; uint32 id; uint16 file_slot; int16 lru; - SpriteTypeByte type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble. + SpriteType type; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble. bool warned; ///< True iff the user has been warned about incorrect use of this sprite byte container_ver; ///< Container version of the GRF the sprite is from. }; static uint _spritecache_items = 0; -static SpriteCache *_spritecache = NULL; +static SpriteCache *_spritecache = nullptr; static inline SpriteCache *GetSpriteCache(uint index) @@ -424,7 +422,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty } if (sprite_avail == 0) { - if (sprite_type == ST_MAPGEN) return NULL; + if (sprite_type == ST_MAPGEN) return nullptr; if (id == SPR_IMG_QUERY) usererror("Okay... something went horribly wrong. I couldn't load the fallback sprite. What should I do?"); return (void*)GetRawSprite(SPR_IMG_QUERY, ST_NORMAL, allocator); } @@ -535,7 +533,7 @@ bool LoadNextSprite(int load_index, byte file_slot, uint file_sprite_id, byte co byte grf_type = FioReadByte(); SpriteType type; - void *data = NULL; + void *data = nullptr; if (grf_type == 0xFF) { /* Some NewGRF files have "empty" pseudo-sprites which are 1 * byte long. Catch these so the sprites won't be displayed. */ @@ -595,7 +593,7 @@ void DupSprite(SpriteID old_spr, SpriteID new_spr) scnew->file_slot = scold->file_slot; scnew->file_pos = scold->file_pos; - scnew->ptr = NULL; + scnew->ptr = nullptr; scnew->id = scold->id; scnew->type = scold->type; scnew->warned = false; @@ -643,7 +641,7 @@ void IncreaseSpriteLRU() for (i = 0; i != _spritecache_items; i++) { SpriteCache *sc = GetSpriteCache(i); - if (sc->ptr != NULL) { + if (sc->ptr != nullptr) { if (sc->lru >= 0) { sc->lru = -1; } else if (sc->lru != -32768) { @@ -715,7 +713,7 @@ static void DeleteEntryFromSpriteCache(uint item) MemBlock *s = (MemBlock*)GetSpriteCache(item)->ptr - 1; assert(!(s->size & S_FREE_MASK)); s->size |= S_FREE_MASK; - GetSpriteCache(item)->ptr = NULL; + GetSpriteCache(item)->ptr = nullptr; /* And coalesce adjacent free blocks */ for (s = _spritecache_ptr; s->size != 0; s = NextBlock(s)) { @@ -737,7 +735,7 @@ static void DeleteEntryFromSpriteCache() cur_lru = 0xffff; for (SpriteID i = 0; i != _spritecache_items; i++) { SpriteCache *sc = GetSpriteCache(i); - if (sc->type != ST_RECOLOUR && sc->ptr != NULL && sc->lru < cur_lru) { + if (sc->type != ST_RECOLOUR && sc->ptr != nullptr && sc->lru < cur_lru) { cur_lru = sc->lru; best = i; } @@ -807,7 +805,7 @@ static void *HandleInvalidSpriteRequest(SpriteID sprite, SpriteType requested, S SpriteType available = sc->type; if (requested == ST_FONT && available == ST_NORMAL) { - if (sc->ptr == NULL) sc->type = ST_FONT; + if (sc->ptr == nullptr) sc->type = ST_FONT; return GetRawSprite(sprite, sc->type, allocator); } @@ -837,7 +835,7 @@ static void *HandleInvalidSpriteRequest(SpriteID sprite, SpriteType requested, S * If the sprite is not available or of wrong type, a fallback sprite is returned. * @param sprite Sprite to read. * @param type Expected sprite type. - * @param allocator Allocator function to use. Set to NULL to use the usual sprite cache. + * @param allocator Allocator function to use. Set to nullptr to use the usual sprite cache. * @return Sprite raw data */ void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator) @@ -856,14 +854,14 @@ void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator) if (sc->type != type) return HandleInvalidSpriteRequest(sprite, type, sc, allocator); - if (allocator == NULL) { + if (allocator == nullptr) { /* Load sprite into/from spritecache */ /* Update LRU */ sc->lru = ++_sprite_lru_counter; /* Load the sprite, if it is not loaded, yet */ - if (sc->ptr == NULL) sc->ptr = ReadSprite(sc, sprite, type, AllocSprite); + if (sc->ptr == nullptr) sc->ptr = ReadSprite(sc, sprite, type, AllocSprite); return sc->ptr; } else { @@ -882,7 +880,7 @@ static void GfxInitSpriteCache() /* Remember 'target_size' from the previous allocation attempt, so we do not try to reach the target_size multiple times in case of failure. */ static uint last_alloc_attempt = 0; - if (_spritecache_ptr == NULL || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) { + if (_spritecache_ptr == nullptr || (_allocated_sprite_cache_size != target_size && target_size != last_alloc_attempt)) { delete[] reinterpret_cast(_spritecache_ptr); last_alloc_attempt = target_size; @@ -893,10 +891,10 @@ static void GfxInitSpriteCache() /* Try to allocate 50% more to make sure we do not allocate almost all available. */ _spritecache_ptr = reinterpret_cast(new byte[_allocated_sprite_cache_size + _allocated_sprite_cache_size / 2]); } catch (std::bad_alloc &) { - _spritecache_ptr = NULL; + _spritecache_ptr = nullptr; } - if (_spritecache_ptr != NULL) { + if (_spritecache_ptr != nullptr) { /* Allocation succeeded, but we wanted less. */ delete[] reinterpret_cast(_spritecache_ptr); _spritecache_ptr = reinterpret_cast(new byte[_allocated_sprite_cache_size]); @@ -906,7 +904,7 @@ static void GfxInitSpriteCache() /* Try again to allocate half. */ _allocated_sprite_cache_size >>= 1; } - } while (_spritecache_ptr == NULL); + } while (_spritecache_ptr == nullptr); if (_allocated_sprite_cache_size != target_size) { DEBUG(misc, 0, "Not enough memory to allocate %d MiB of spritecache. Spritecache was reduced to %d MiB.", target_size / 1024 / 1024, _allocated_sprite_cache_size / 1024 / 1024); @@ -931,7 +929,7 @@ void GfxInitSpriteMem() /* Reset the spritecache 'pool' */ free(_spritecache); _spritecache_items = 0; - _spritecache = NULL; + _spritecache = nullptr; _compact_cache_counter = 0; } @@ -945,7 +943,7 @@ void GfxClearSpriteCache() /* Clear sprite ptr for all cached items */ for (uint i = 0; i != _spritecache_items; i++) { SpriteCache *sc = GetSpriteCache(i); - if (sc->type != ST_RECOLOUR && sc->ptr != NULL) DeleteEntryFromSpriteCache(i); + if (sc->type != ST_RECOLOUR && sc->ptr != nullptr) DeleteEntryFromSpriteCache(i); } } diff --git a/src/spritecache.h b/src/spritecache.h index 8013105183..f718e687bc 100644 --- a/src/spritecache.h +++ b/src/spritecache.h @@ -27,7 +27,7 @@ extern uint _sprite_cache_size; typedef void *AllocatorProc(size_t size); -void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator = NULL); +void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator = nullptr); bool SpriteExists(SpriteID sprite); SpriteType GetSpriteType(SpriteID sprite); diff --git a/src/spriteloader/grf.cpp b/src/spriteloader/grf.cpp index b21e70b1db..4a4d7daad5 100644 --- a/src/spriteloader/grf.cpp +++ b/src/spriteloader/grf.cpp @@ -69,8 +69,8 @@ static bool WarnCorruptSprite(uint8 file_slot, size_t file_pos, int line) */ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, int64 num, byte type, ZoomLevel zoom_lvl, byte colour_fmt, byte container_format) { - AutoFreePtr dest_orig(MallocT(num)); - byte *dest = dest_orig; + std::unique_ptr dest_orig(new byte[num]); + byte *dest = dest_orig.get(); const int64 dest_size = num; /* Read the file, which has some kind of compression */ @@ -89,7 +89,7 @@ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t fi } else { /* Copy bytes from earlier in the sprite */ const uint data_offset = ((code & 7) << 8) | FioReadByte(); - if (dest - data_offset < dest_orig) return WarnCorruptSprite(file_slot, file_pos, __LINE__); + if (dest - data_offset < dest_orig.get()) return WarnCorruptSprite(file_slot, file_pos, __LINE__); int size = -(code >> 3); num -= size; if (num < 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__); @@ -123,10 +123,10 @@ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t fi } /* Go to that row */ - dest = dest_orig + offset; + dest = dest_orig.get() + offset; do { - if (dest + (container_format >= 2 && sprite->width > 256 ? 4 : 2) > dest_orig + dest_size) { + if (dest + (container_format >= 2 && sprite->width > 256 ? 4 : 2) > dest_orig.get() + dest_size) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } @@ -152,7 +152,7 @@ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t fi data = &sprite->data[y * sprite->width + skip]; - if (skip + length > sprite->width || dest + length * bpp > dest_orig + dest_size) { + if (skip + length > sprite->width || dest + length * bpp > dest_orig.get() + dest_size) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } @@ -188,7 +188,7 @@ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t fi warning_level = 6; } - dest = dest_orig; + dest = dest_orig.get(); for (int i = 0; i < sprite->width * sprite->height; i++) { byte *pixel = &dest[i * bpp]; diff --git a/src/station.cpp b/src/station.cpp index 405f40f96e..1cbd4a57b3 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -14,6 +14,7 @@ #include "company_base.h" #include "roadveh.h" #include "viewport_func.h" +#include "viewport_kdtree.h" #include "date_func.h" #include "command_func.h" #include "news_func.h" @@ -22,8 +23,10 @@ #include "town.h" #include "core/pool_func.hpp" #include "station_base.h" +#include "station_kdtree.h" #include "roadstop_base.h" #include "industry.h" +#include "town.h" #include "core/random_func.hpp" #include "linkgraph/linkgraph.h" #include "linkgraph/linkgraphschedule.h" @@ -36,6 +39,20 @@ StationPool _station_pool("Station"); INSTANTIATE_POOL_METHODS(Station) + +StationKdtree _station_kdtree(Kdtree_StationXYFunc); + +void RebuildStationKdtree() +{ + std::vector stids; + BaseStation *st; + FOR_ALL_STATIONS(st) { + stids.push_back(st->index); + } + _station_kdtree.Build(stids.begin(), stids.end()); +} + + BaseStation::~BaseStation() { free(this->name); @@ -55,7 +72,7 @@ Station::Station(TileIndex tile) : SpecializedStation(tile), bus_station(INVALID_TILE, 0, 0), truck_station(INVALID_TILE, 0, 0), - dock_tile(INVALID_TILE), + ship_station(INVALID_TILE, 0, 0), indtype(IT_INVALID), time_since_load(255), time_since_unload(255), @@ -101,7 +118,7 @@ Station::~Station() for (CargoID c = 0; c < NUM_CARGO; ++c) { LinkGraph *lg = LinkGraph::GetIfValid(this->goods[c].link_graph); - if (lg == NULL) continue; + if (lg == nullptr) continue; for (NodeID node = 0; node < lg->Size(); ++node) { Station *st = Station::Get((*lg)[node].Station()); @@ -129,6 +146,9 @@ Station::~Station() } } + /* Remove station from industries and towns that reference it. */ + this->RemoveFromAllNearbyLists(); + /* Clear the persistent storage. */ delete this->airport.psa; @@ -152,6 +172,9 @@ Station::~Station() } CargoPacket::InvalidateAllFrom(this->index); + + _station_kdtree.Remove(this->index); + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(this->index)); } @@ -174,9 +197,9 @@ RoadStop *Station::GetPrimaryRoadStop(const RoadVehicle *v) const { RoadStop *rs = this->GetPrimaryRoadStop(v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK); - for (; rs != NULL; rs = rs->next) { + for (; rs != nullptr; rs = rs->next) { /* The vehicle cannot go to this roadstop (different roadtype) */ - if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue; + if (!HasTileAnyRoadType(rs->xy, v->compatible_roadtypes)) continue; /* The vehicle is articulated and can therefore not go to a standard road stop. */ if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue; @@ -194,7 +217,7 @@ RoadStop *Station::GetPrimaryRoadStop(const RoadVehicle *v) const void Station::AddFacility(StationFacility new_facility_bit, TileIndex facil_xy) { if (this->facilities == FACIL_NONE) { - this->xy = facil_xy; + this->MoveSign(facil_xy); this->random_bits = Random(); } this->facilities |= new_facility_bit; @@ -271,6 +294,39 @@ void Station::MarkTilesDirty(bool cargo_change) const return length; } +/** + * Get the catchment size of an individual station tile. + * @param tile Station tile to get catchment size of. + * @param st Associated station of station tile. + * @pre IsTileType(tile, MP_STATION) + * @return The catchment size of the station tile. + */ +static uint GetTileCatchmentRadius(TileIndex tile, const Station *st) +{ + assert(IsTileType(tile, MP_STATION)); + + if (_settings_game.station.modified_catchment) { + switch (GetStationType(tile)) { + case STATION_RAIL: return CA_TRAIN; + case STATION_OILRIG: return CA_UNMODIFIED; + case STATION_AIRPORT: return st->airport.GetSpec()->catchment; + case STATION_TRUCK: return CA_TRUCK; + case STATION_BUS: return CA_BUS; + case STATION_DOCK: return CA_DOCK; + + default: NOT_REACHED(); + case STATION_BUOY: + case STATION_WAYPOINT: return CA_NONE; + } + } else { + switch (GetStationType(tile)) { + default: return CA_UNMODIFIED; + case STATION_BUOY: + case STATION_WAYPOINT: return CA_NONE; + } + } +} + /** * Determines the catchment radius of the station * @return The radius @@ -280,13 +336,13 @@ uint Station::GetCatchmentRadius() const uint ret = CA_NONE; if (_settings_game.station.modified_catchment) { - if (this->bus_stops != NULL) ret = max(ret, CA_BUS); - if (this->truck_stops != NULL) ret = max(ret, CA_TRUCK); + if (this->bus_stops != nullptr) ret = max(ret, CA_BUS); + if (this->truck_stops != nullptr) ret = max(ret, CA_TRUCK); if (this->train_station.tile != INVALID_TILE) ret = max(ret, CA_TRAIN); - if (this->dock_tile != INVALID_TILE) ret = max(ret, CA_DOCK); + if (this->ship_station.tile != INVALID_TILE) ret = max(ret, CA_DOCK); if (this->airport.tile != INVALID_TILE) ret = max(ret, this->airport.GetSpec()->catchment); } else { - if (this->bus_stops != NULL || this->truck_stops != NULL || this->train_station.tile != INVALID_TILE || this->dock_tile != INVALID_TILE || this->airport.tile != INVALID_TILE) { + if (this->bus_stops != nullptr || this->truck_stops != nullptr || this->train_station.tile != INVALID_TILE || this->ship_station.tile != INVALID_TILE || this->airport.tile != INVALID_TILE) { ret = CA_UNMODIFIED; } } @@ -315,79 +371,129 @@ Rect Station::GetCatchmentRect() const return ret; } -/** Rect and pointer to IndustryVector */ -struct RectAndIndustryVector { - Rect rect; ///< The rectangle to search the industries in. - IndustryVector *industries_near; ///< The nearby industries. -}; - /** - * Callback function for Station::RecomputeIndustriesNear() - * Tests whether tile is an industry and possibly adds - * the industry to station's industries_near list. - * @param ind_tile tile to check - * @param user_data pointer to RectAndIndustryVector - * @return always false, we want to search all tiles + * Add nearby industry to station's industries_near list if it accepts cargo. + * @param ind Industry + * @param st Station */ -static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data) +static void AddIndustryToDeliver(Industry *ind, Station *st) { - /* Only process industry tiles */ - if (!IsTileType(ind_tile, MP_INDUSTRY)) return false; - - RectAndIndustryVector *riv = (RectAndIndustryVector *)user_data; - Industry *ind = Industry::GetByTile(ind_tile); - /* Don't check further if this industry is already in the list */ - if (riv->industries_near->Contains(ind)) return false; - - /* Only process tiles in the station acceptance rectangle */ - int x = TileX(ind_tile); - int y = TileY(ind_tile); - if (x < riv->rect.left || x > riv->rect.right || y < riv->rect.top || y > riv->rect.bottom) return false; + if (st->industries_near.find(ind) != st->industries_near.end()) return; /* Include only industries that can accept cargo */ uint cargo_index; for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { if (ind->accepts_cargo[cargo_index] != CT_INVALID) break; } - if (cargo_index >= lengthof(ind->accepts_cargo)) return false; + if (cargo_index >= lengthof(ind->accepts_cargo)) return; - *riv->industries_near->Append() = ind; + st->industries_near.insert(ind); +} +/** + * Remove this station from the nearby stations lists of all towns and industries. + */ +void Station::RemoveFromAllNearbyLists() +{ + Town *t; + FOR_ALL_TOWNS(t) { t->stations_near.erase(this); } + Industry *i; + FOR_ALL_INDUSTRIES(i) { i->stations_near.erase(this); } +} + +/** + * Test if the given town ID is covered by our catchment area. + * This is used when removing a house tile to determine if it was the last house tile + * within our catchment. + * @param t TownID to test. + * @return true if at least one house tile of TownID is covered. + */ +bool Station::CatchmentCoversTown(TownID t) const +{ + BitmapTileIterator it(this->catchment_tiles); + for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { + if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) == t) return true; + } return false; } /** - * Recomputes Station::industries_near, list of industries possibly - * accepting cargo in station's catchment radius + * Recompute tiles covered in our catchment area. + * This will additionally recompute nearby towns and industries. */ -void Station::RecomputeIndustriesNear() +void Station::RecomputeCatchment() { - this->industries_near.Clear(); - if (this->rect.IsEmpty()) return; + this->industries_near.clear(); + this->RemoveFromAllNearbyLists(); - RectAndIndustryVector riv = { - this->GetCatchmentRect(), - &this->industries_near - }; + if (this->rect.IsEmpty()) { + this->catchment_tiles.Reset(); + return; + } - /* Compute maximum extent of acceptance rectangle wrt. station sign */ - TileIndex start_tile = this->xy; - uint max_radius = max( - max(DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.bottom))), - max(DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.bottom))) - ); + if (!_settings_game.station.serve_neutral_industries && this->industry != nullptr) { + /* Station is associated with an industry, so we only need to deliver to that industry. */ + this->catchment_tiles.Initialize(this->industry->location); + TILE_AREA_LOOP(tile, this->industry->location) { + if (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->industry->index) { + this->catchment_tiles.SetTile(tile); + } + } + /* The industry's stations_near may have been computed before its neutral station was built so clear and re-add here. */ + for (Station *st : this->industry->stations_near) { + st->industries_near.erase(this->industry); + } + this->industry->stations_near.clear(); + this->industry->stations_near.insert(this); + this->industries_near.insert(this->industry); + return; + } - CircularTileSearch(&start_tile, 2 * max_radius + 1, &FindIndustryToDeliver, &riv); + this->catchment_tiles.Initialize(GetCatchmentRect()); + + /* Loop finding all station tiles */ + TileArea ta(TileXY(this->rect.left, this->rect.top), TileXY(this->rect.right, this->rect.bottom)); + TILE_AREA_LOOP(tile, ta) { + if (!IsTileType(tile, MP_STATION) || GetStationIndex(tile) != this->index) continue; + + uint r = GetTileCatchmentRadius(tile, this); + if (r == CA_NONE) continue; + + /* This tile sub-loop doesn't need to test any tiles, they are simply added to the catchment set. */ + TileArea ta2 = TileArea(tile, 1, 1).Expand(r); + TILE_AREA_LOOP(tile2, ta2) this->catchment_tiles.SetTile(tile2); + } + + /* Search catchment tiles for towns and industries */ + BitmapTileIterator it(this->catchment_tiles); + for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { + if (IsTileType(tile, MP_HOUSE)) { + Town *t = Town::GetByTile(tile); + t->stations_near.insert(this); + } + if (IsTileType(tile, MP_INDUSTRY)) { + Industry *i = Industry::GetByTile(tile); + + /* Ignore industry if it has a neutral station. It already can't be this station. */ + if (!_settings_game.station.serve_neutral_industries && i->neutral_station != nullptr) continue; + + i->stations_near.insert(this); + + /* Add if we can deliver to this industry as well */ + AddIndustryToDeliver(i, this); + } + } } /** - * Recomputes Station::industries_near for all stations + * Recomputes catchment of all stations. + * This will additionally recompute nearby stations for all towns and industries. */ -/* static */ void Station::RecomputeIndustriesNearForAll() +/* static */ void Station::RecomputeCatchmentForAll() { Station *st; - FOR_ALL_STATIONS(st) st->RecomputeIndustriesNear(); + FOR_ALL_STATIONS(st) { st->RecomputeCatchment(); } } /************************************************************************/ @@ -575,3 +681,8 @@ Money AirportMaintenanceCost(Owner owner) /* 3 bits fraction for the maintenance cost factor. */ return total_cost >> 3; } + +bool StationCompare::operator() (const Station *lhs, const Station *rhs) const +{ + return lhs->index < rhs->index; +} diff --git a/src/station_base.h b/src/station_base.h index bf860538d1..1f597a2897 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -19,7 +19,9 @@ #include "industry_type.h" #include "linkgraph/linkgraph_type.h" #include "newgrf_storage.h" +#include "bitmap_type.h" #include +#include typedef Pool StationPool; extern StationPool _station_pool; @@ -308,7 +310,7 @@ struct Airport : public TileArea { uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 byte type; ///< Type of this airport, @see AirportTypes byte layout; ///< Airport layout number. - DirectionByte rotation; ///< How this airport is rotated. + Direction rotation; ///< How this airport is rotated. PersistentStorage *psa; ///< Persistent storage for NewGRF airports. @@ -440,7 +442,11 @@ private: } }; -typedef SmallVector IndustryVector; +struct IndustryCompare { + bool operator() (const Industry *lhs, const Industry *rhs) const; +}; + +typedef std::set IndustryList; /** Station data structure */ struct Station FINAL : SpecializedStation { @@ -457,12 +463,15 @@ public: RoadStop *truck_stops; ///< All the truck stops TileArea truck_station; ///< Tile area the truck 'station' part covers - Airport airport; ///< Tile area the airport covers - TileIndex dock_tile; ///< The location of the dock + Airport airport; ///< Tile area the airport covers + TileArea ship_station; ///< Tile area the ship 'station' part covers + TileArea docking_station; ///< Tile area the docking tiles cover IndustryType indtype; ///< Industry type to get the name from - StationHadVehicleOfTypeByte had_vehicle_of_type; + BitmapTileArea catchment_tiles; ///< NOSAVE: Set of individual tiles covered by catchment area + + StationHadVehicleOfType had_vehicle_of_type; byte time_since_load; byte time_since_unload; @@ -472,7 +481,8 @@ public: GoodsEntry goods[NUM_CARGO]; ///< Goods at this station CargoTypes always_accepted; ///< Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept cargo) - IndustryVector industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() + IndustryList industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() + Industry *industry; ///< NOSAVE: Associated industry for neutral stations. (Rebuilt on load from Industry->st) Station(TileIndex tile = INVALID_TILE); ~Station(); @@ -481,19 +491,28 @@ public: void MarkTilesDirty(bool cargo_change) const; - void UpdateVirtCoord(); + void UpdateVirtCoord() override; + + void MoveSign(TileIndex new_xy) override; void AfterStationTileSetChange(bool adding, StationType type); - /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const; - /* virtual */ uint GetPlatformLength(TileIndex tile) const; - void RecomputeIndustriesNear(); - static void RecomputeIndustriesNearForAll(); + uint GetPlatformLength(TileIndex tile, DiagDirection dir) const override; + uint GetPlatformLength(TileIndex tile) const override; + void RecomputeCatchment(); + static void RecomputeCatchmentForAll(); uint GetCatchmentRadius() const; Rect GetCatchmentRect() const; + bool CatchmentCoversTown(TownID t) const; + void RemoveFromAllNearbyLists(); - /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const + inline bool TileIsInCatchment(TileIndex tile) const + { + return this->catchment_tiles.HasTile(tile); + } + + inline bool TileBelongsToRailStation(TileIndex tile) const override { return IsRailStationTile(tile) && GetStationIndex(tile) == this->index; } @@ -503,9 +522,9 @@ public: return IsAirportTile(tile) && GetStationIndex(tile) == this->index; } - /* virtual */ uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const; + uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const override; - /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; + void GetTileArea(TileArea *ta, StationType type) const override; }; #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var) @@ -540,4 +559,6 @@ public: } }; +void RebuildStationKdtree(); + #endif /* STATION_BASE_H */ diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 1796f2cc8e..636b1c4766 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -14,6 +14,7 @@ #include "bridge_map.h" #include "cmd_helper.h" #include "viewport_func.h" +#include "viewport_kdtree.h" #include "command_func.h" #include "town.h" #include "news_func.h" @@ -37,8 +38,10 @@ #include "animated_tile_func.h" #include "elrail_func.h" #include "station_base.h" +#include "station_kdtree.h" #include "roadstop_base.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "waypoint_base.h" #include "waypoint_func.h" #include "pbs.h" @@ -53,6 +56,7 @@ #include "linkgraph/linkgraph_base.h" #include "linkgraph/refresh.h" #include "widgets/station_widget.h" +#include "tunnelbridge_map.h" #include "table/strings.h" @@ -99,9 +103,7 @@ bool IsHangar(TileIndex t) template CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st) { - ta.tile -= TileDiffXY(1, 1); - ta.w += 2; - ta.h += 2; + ta.Expand(1); /* check around to see if there are any stations there owned by the company */ TILE_AREA_LOOP(tile_cur, ta) { @@ -115,7 +117,7 @@ CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID c } } } - *st = (closest_station == INVALID_STATION) ? NULL : T::Get(closest_station); + *st = (closest_station == INVALID_STATION) ? nullptr : T::Get(closest_station); return CommandCost(); } @@ -354,24 +356,26 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n /** * Find the closest deleted station of the current company * @param tile the tile to search from. - * @return the closest station or NULL if too far. + * @return the closest station or nullptr if too far. */ static Station *GetClosestDeletedStation(TileIndex tile) { uint threshold = 8; - Station *best_station = NULL; - Station *st; - FOR_ALL_STATIONS(st) { + Station *best_station = nullptr; + ForAllStationsRadius(tile, threshold, [&](Station *st) { if (!st->IsInUse() && st->owner == _current_company) { uint cur_dist = DistanceManhattan(tile, st->xy); if (cur_dist < threshold) { threshold = cur_dist; best_station = st; + } else if (cur_dist == threshold && best_station != nullptr) { + /* In case of a tie, lowest station ID wins */ + if (st->index < best_station->index) best_station = st; } } - } + }); return best_station; } @@ -398,7 +402,7 @@ void Station::GetTileArea(TileArea *ta, StationType type) const case STATION_DOCK: case STATION_OILRIG: - ta->tile = this->dock_tile; + *ta = this->docking_station; break; default: NOT_REACHED(); @@ -425,6 +429,23 @@ void Station::UpdateVirtCoord() SetWindowDirty(WC_STATION_VIEW, this->index); } +/** + * Move the station main coordinate somewhere else. + * @param new_xy new tile location of the sign + */ +void Station::MoveSign(TileIndex new_xy) +{ + if (this->xy == new_xy) return; + + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeStation(this->index)); + _station_kdtree.Remove(this->index); + + this->BaseStation::MoveSign(new_xy); + + _station_kdtree.Insert(this->index); + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(this->index)); +} + /** Update the virtual coords needed to draw the station sign for all stations. */ void UpdateAllStationVirtCoords() { @@ -474,38 +495,23 @@ static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *c CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad) { CargoArray produced; - - int x = TileX(tile); - int y = TileY(tile); - - /* expand the region by rad tiles on each side - * while making sure that we remain inside the board. */ - int x2 = min(x + w + rad, MapSizeX()); - int x1 = max(x - rad, 0); - - int y2 = min(y + h + rad, MapSizeY()); - int y1 = max(y - rad, 0); - - assert(x1 < x2); - assert(y1 < y2); - assert(w > 0); - assert(h > 0); - - TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1)); + std::set industries; + TileArea ta = TileArea(tile, w, h).Expand(rad); /* Loop over all tiles to get the produced cargo of * everything except industries */ - TILE_AREA_LOOP(tile, ta) AddProducedCargo(tile, produced); + TILE_AREA_LOOP(tile, ta) { + if (IsTileType(tile, MP_INDUSTRY)) industries.insert(GetIndustryIndex(tile)); + AddProducedCargo(tile, produced); + } - /* Loop over the industries. They produce cargo for - * anything that is within 'rad' from their bounding - * box. As such if you have e.g. a oil well the tile - * area loop might not hit an industry tile while - * the industry would produce cargo for the station. + /* Loop over the seen industries. They produce cargo for + * anything that is within 'rad' of any one of their tiles. */ - const Industry *i; - FOR_ALL_INDUSTRIES(i) { - if (!ta.Intersects(i->location)) continue; + for (IndustryID industry : industries) { + const Industry *i = Industry::Get(industry); + /* Skip industry with neutral station */ + if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue; for (uint j = 0; j < lengthof(i->produced_cargo); j++) { CargoID cargo = i->produced_cargo[j]; @@ -522,33 +528,39 @@ CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad) * @param w X extent of area * @param h Y extent of area * @param rad Search radius in addition to given area - * @param always_accepted bitmask of cargo accepted by houses and headquarters; can be NULL + * @param always_accepted bitmask of cargo accepted by houses and headquarters; can be nullptr + * @param ind Industry associated with neutral station (e.g. oil rig) or nullptr */ CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted) { CargoArray acceptance; - if (always_accepted != NULL) *always_accepted = 0; + if (always_accepted != nullptr) *always_accepted = 0; - int x = TileX(tile); - int y = TileY(tile); + TileArea ta = TileArea(tile, w, h).Expand(rad); - /* expand the region by rad tiles on each side - * while making sure that we remain inside the board. */ - int x2 = min(x + w + rad, MapSizeX()); - int y2 = min(y + h + rad, MapSizeY()); - int x1 = max(x - rad, 0); - int y1 = max(y - rad, 0); + TILE_AREA_LOOP(tile, ta) { + /* Ignore industry if it has a neutral station. */ + if (!_settings_game.station.serve_neutral_industries && IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile)->neutral_station != nullptr) continue; - assert(x1 < x2); - assert(y1 < y2); - assert(w > 0); - assert(h > 0); + AddAcceptedCargo(tile, acceptance, always_accepted); + } - for (int yc = y1; yc != y2; yc++) { - for (int xc = x1; xc != x2; xc++) { - TileIndex tile = TileXY(xc, yc); - AddAcceptedCargo(tile, acceptance, always_accepted); - } + return acceptance; +} + +/** + * Get the acceptance of cargoes around the station in. + * @param st Station to get acceptance of. + * @param always_accepted bitmask of cargo accepted by houses and headquarters; can be nullptr + */ +static CargoArray GetAcceptanceAroundStation(const Station *st, CargoTypes *always_accepted) +{ + CargoArray acceptance; + if (always_accepted != nullptr) *always_accepted = 0; + + BitmapTileIterator it(st->catchment_tiles); + for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { + AddAcceptedCargo(tile, acceptance, always_accepted); } return acceptance; @@ -567,13 +579,7 @@ void UpdateStationAcceptance(Station *st, bool show_msg) /* And retrieve the acceptance. */ CargoArray acceptance; if (!st->rect.IsEmpty()) { - acceptance = GetAcceptanceAroundTiles( - TileXY(st->rect.left, st->rect.top), - st->rect.right - st->rect.left + 1, - st->rect.bottom - st->rect.top + 1, - st->GetCatchmentRadius(), - &st->always_accepted - ); + acceptance = GetAcceptanceAroundStation(st, &st->always_accepted); } /* Adjust in case our station only accepts fewer kinds of goods */ @@ -648,8 +654,8 @@ static void UpdateStationSignCoord(BaseStation *st) if (r->IsEmpty()) return; // no tiles belong to this station /* clamp sign coord to be inside the station rect */ - st->xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom)); - st->UpdateVirtCoord(); + TileIndex new_xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom)); + st->MoveSign(new_xy); if (!Station::IsExpected(st)) return; Station *full_station = Station::From(st); @@ -672,9 +678,9 @@ static void UpdateStationSignCoord(BaseStation *st) static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class) { /* Find a deleted station close to us */ - if (*st == NULL && reuse) *st = GetClosestDeletedStation(area.tile); + if (*st == nullptr && reuse) *st = GetClosestDeletedStation(area.tile); - if (*st != NULL) { + if (*st != nullptr) { if ((*st)->owner != _current_company) { return_cmd_error(CMD_ERROR); } @@ -687,6 +693,8 @@ static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reus if (flags & DC_EXEC) { *st = new Station(area.tile); + _station_kdtree.Insert((*st)->index); + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation((*st)->index)); (*st)->town = ClosestTownFromTile(area.tile, UINT_MAX); (*st)->string_id = GenerateStationName(*st, area.tile, name_class); @@ -723,7 +731,7 @@ static void DeleteStationIfEmpty(BaseStation *st) void Station::AfterStationTileSetChange(bool adding, StationType type) { this->UpdateVirtCoord(); - this->RecomputeIndustriesNear(); + this->RecomputeCatchment(); DirtyCompanyInfrastructureWindows(this->owner); if (adding) InvalidateWindowData(WC_STATION_LIST, this->owner, 0); @@ -845,14 +853,14 @@ static CommandCost CheckFlatLandAirport(AirportTileTableIterator tile_iter, DoCo * @param numtracks Number of platforms. * @return The cost in case of success, or an error code if it failed. */ -static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, SmallVector &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks) +static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, std::vector &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; uint invalid_dirs = 5 << axis; const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index); - bool slope_cb = statspec != NULL && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK); + bool slope_cb = statspec != nullptr && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK); TILE_AREA_LOOP(tile_cur, tile_area) { CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false); @@ -868,7 +876,7 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl /* if station is set, then we have special handling to allow building on top of already existing stations. * so station points to INVALID_STATION if we can build on any station. * Or it points to a station if we're only allowed to build on exactly that station. */ - if (station != NULL && IsTileType(tile_cur, MP_STATION)) { + if (station != nullptr && IsTileType(tile_cur, MP_STATION)) { if (!IsRailStation(tile_cur)) { return ClearTile_Station(tile_cur, DC_AUTO); // get error message } else { @@ -899,8 +907,8 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl /* Check for trains having a reservation for this tile. */ if (HasBit(GetRailReservationTrackBits(tile_cur), track)) { Train *v = GetTrainForReservation(tile_cur, track); - if (v != NULL) { - *affected_vehicles.Append() = v; + if (v != nullptr) { + affected_vehicles.push_back(v); } } CommandCost ret = DoCommand(tile_cur, 0, track, flags, CMD_REMOVE_SINGLE_RAIL); @@ -928,10 +936,10 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl * @param is_truck_stop True when building a truck stop, false otherwise. * @param axis Axis of a drive-through road stop. * @param station StationID to be queried and returned if available. - * @param rts Road types to build. + * @param rt Road type to build. * @return The cost in case of success, or an error code if it failed. */ -static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadTypes rts) +static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; @@ -944,7 +952,7 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags /* If station is set, then we have special handling to allow building on top of already existing stations. * Station points to INVALID_STATION if we can build on any station. * Or it points to a station if we're only allowed to build on exactly that station. */ - if (station != NULL && IsTileType(cur_tile, MP_STATION)) { + if (station != nullptr && IsTileType(cur_tile, MP_STATION)) { if (!IsRoadStop(cur_tile)) { return ClearTile_Station(cur_tile, DC_AUTO); // Get error message. } else { @@ -982,50 +990,57 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags } } - RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE; - uint num_roadbits = 0; if (build_over_road) { /* There is a road, check if we can build road+tram stop over it. */ - if (HasBit(cur_rts, ROADTYPE_ROAD)) { - Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD); + RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD); + if (road_rt != INVALID_ROADTYPE) { + Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD); if (road_owner == OWNER_TOWN) { if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD); } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) { CommandCost ret = CheckOwnership(road_owner); if (ret.Failed()) return ret; } - num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD)); + uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD)); + + if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD); if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) { CommandCost ret = CheckOwnership(road_owner); if (ret.Failed()) return ret; } + + cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces)); + } else if (RoadTypeIsRoad(rt)) { + cost.AddCost(RoadBuildCost(rt) * 2); } /* There is a tram, check if we can build road+tram stop over it. */ - if (HasBit(cur_rts, ROADTYPE_TRAM)) { - Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM); + RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM); + if (tram_rt != INVALID_ROADTYPE) { + Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM); if (Company::IsValidID(tram_owner) && (!_settings_game.construction.road_stop_on_competitor_road || /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ - HasExactlyOneBit(GetRoadBits(cur_tile, ROADTYPE_TRAM)))) { + HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) { CommandCost ret = CheckOwnership(tram_owner); if (ret.Failed()) return ret; } - num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM)); - } + uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM)); - /* Take into account existing roadbits. */ - rts |= cur_rts; + if (RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD); + + cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces)); + } else if (RoadTypeIsTram(rt)) { + cost.AddCost(RoadBuildCost(rt) * 2); + } } else { ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); + cost.AddCost(RoadBuildCost(rt) * 2); } - - uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits; - cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build); } } @@ -1086,7 +1101,7 @@ static inline byte *CreateMulti(byte *layout, int n, byte b) */ void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec) { - if (statspec != NULL && statspec->lengths >= plat_len && + if (statspec != nullptr && statspec->lengths >= plat_len && statspec->platforms[plat_len - 1] >= numtracks && statspec->layouts[plat_len - 1][numtracks - 1]) { /* Custom layout defined, follow it. */ @@ -1122,7 +1137,7 @@ void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSp template CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st) { - assert(*st == NULL); + assert(*st == nullptr); bool check_surrounding = true; if (_settings_game.station.adjacent_stations) { @@ -1135,7 +1150,7 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station /* Extend the current station, and don't check whether it will * be near any other stations. */ *st = T::GetIfValid(existing_station); - check_surrounding = (*st == NULL); + check_surrounding = (*st == nullptr); } } else { /* There's no station here. Don't check the tiles surrounding this @@ -1151,7 +1166,7 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station } /* Distant join */ - if (*st == NULL && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join); + if (*st == nullptr && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join); return CommandCost(); } @@ -1271,7 +1286,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */ StationID est = INVALID_STATION; - SmallVector affected_vehicles; + std::vector affected_vehicles; /* Clear the land below the station. */ CommandCost cost = CheckFlatLandRailStation(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks); if (cost.Failed()) return cost; @@ -1279,14 +1294,14 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len); cost.AddCost(numtracks * plat_len * RailBuildCost(rt)); - Station *st = NULL; + Station *st = nullptr; ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st); if (ret.Failed()) return ret; ret = BuildStationPart(&st, flags, reuse, new_location, STATIONNAMING_RAIL); if (ret.Failed()) return ret; - if (st != NULL && st->train_station.tile != INVALID_TILE) { + if (st != nullptr && st->train_station.tile != INVALID_TILE) { CommandCost ret = CanExpandRailStation(st, new_location, axis); if (ret.Failed()) return ret; } @@ -1296,7 +1311,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0); if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS); - if (statspec != NULL) { + if (statspec != nullptr) { /* Perform NewStation checks */ /* Check if the station size is permitted */ @@ -1306,7 +1321,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 /* Check if the station is buildable */ if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) { - uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE); + uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, nullptr, INVALID_TILE); if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR; } } @@ -1322,7 +1337,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY); - if (statspec != NULL) { + if (statspec != nullptr) { /* Include this station spec's animation trigger bitmask * in the station's cached copy. */ st->cached_anim_triggers |= statspec->animation.triggers; @@ -1346,8 +1361,8 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 if (IsRailStationTile(tile) && HasStationReservation(tile)) { /* Check for trains having a reservation for this tile. */ Train *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile))); - if (v != NULL) { - *affected_vehicles.Append() = v; + if (v != nullptr) { + affected_vehicles.push_back(v); FreeTrainReservation(v); } } @@ -1372,12 +1387,12 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++; c->infrastructure.station++; - if (statspec != NULL) { + if (statspec != nullptr) { /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */ uint32 platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false); /* As the station is not yet completely finished, the station does not yet exist. */ - uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile); + uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, nullptr, tile); if (callback != CALLBACK_FAILED) { if (callback < 8) { SetStationGfx(tile, (callback & ~1) + axis); @@ -1397,7 +1412,7 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta } while (--numtracks); - for (uint i = 0; i < affected_vehicles.Length(); ++i) { + for (uint i = 0; i < affected_vehicles.size(); ++i) { /* Restore reservations of trains. */ RestoreTrainReservation(affected_vehicles[i]); } @@ -1445,16 +1460,14 @@ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 return cost; } -static void MakeRailStationAreaSmaller(BaseStation *st) +static TileArea MakeStationAreaSmaller(BaseStation *st, TileArea ta, bool (*func)(BaseStation *, TileIndex)) { - TileArea ta = st->train_station; - restart: /* too small? */ if (ta.w != 0 && ta.h != 0) { /* check the left side, x = constant, y changes */ - for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) { + for (uint i = 0; !func(st, ta.tile + TileDiffXY(0, i));) { /* the left side is unused? */ if (++i == ta.h) { ta.tile += TileDiffXY(1, 0); @@ -1464,7 +1477,7 @@ restart: } /* check the right side, x = constant, y changes */ - for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) { + for (uint i = 0; !func(st, ta.tile + TileDiffXY(ta.w - 1, i));) { /* the right side is unused? */ if (++i == ta.h) { ta.w--; @@ -1473,7 +1486,7 @@ restart: } /* check the upper side, y = constant, x changes */ - for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) { + for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, 0));) { /* the left side is unused? */ if (++i == ta.w) { ta.tile += TileDiffXY(0, 1); @@ -1483,7 +1496,7 @@ restart: } /* check the lower side, y = constant, x changes */ - for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) { + for (uint i = 0; !func(st, ta.tile + TileDiffXY(i, ta.h - 1));) { /* the left side is unused? */ if (++i == ta.w) { ta.h--; @@ -1494,7 +1507,28 @@ restart: ta.Clear(); } - st->train_station = ta; + return ta; +} + +static bool TileBelongsToRailStation(BaseStation *st, TileIndex tile) +{ + return st->TileBelongsToRailStation(tile); +} + +static void MakeRailStationAreaSmaller(BaseStation *st) +{ + st->train_station = MakeStationAreaSmaller(st, st->train_station, TileBelongsToRailStation); +} + +static bool TileBelongsToShipStation(BaseStation *st, TileIndex tile) +{ + return IsDockTile(tile) && GetStationIndex(tile) == st->index; +} + +static void MakeShipStationAreaSmaller(Station *st) +{ + st->ship_station = MakeStationAreaSmaller(st, st->ship_station, TileBelongsToShipStation); + UpdateStationDockingTiles(st); } /** @@ -1508,7 +1542,7 @@ restart: * @return the number of cleared tiles or an error. */ template -CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail) +CommandCost RemoveFromRailBaseStation(TileArea ta, std::vector &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail) { /* Count of the number of tiles removed */ int quantity = 0; @@ -1530,7 +1564,7 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected /* Check ownership of station */ T *st = T::GetByTile(tile); - if (st == NULL) continue; + if (st == nullptr) continue; if (_current_company != OWNER_WATER) { CommandCost ret = CheckOwnership(st->owner); @@ -1553,11 +1587,11 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected Track track = GetRailStationTrack(tile); Owner owner = GetTileOwner(tile); RailType rt = GetRailType(tile); - Train *v = NULL; + Train *v = nullptr; if (HasStationReservation(tile)) { v = GetTrainForReservation(tile, track); - if (v != NULL) FreeTrainReservation(v); + if (v != nullptr) FreeTrainReservation(v); } bool build_rail = keep_rail && !IsStationTileBlocked(tile); @@ -1575,16 +1609,15 @@ CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected DeallocateSpecFromStation(st, specindex); - affected_stations.Include(st); + include(affected_stations, st); - if (v != NULL) RestoreTrainReservation(v); + if (v != nullptr) RestoreTrainReservation(v); } } if (quantity == 0) return error.Failed() ? error : CommandCost(STR_ERROR_THERE_IS_NO_STATION); - for (T **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) { - T *st = *stp; + for (T *st : affected_stations) { /* now we need to make the "spanned" area of the railway station smaller * if we deleted something at the edges. @@ -1622,18 +1655,17 @@ CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint3 if (start >= MapSize() || end >= MapSize()) return CMD_ERROR; TileArea ta(start, end); - SmallVector affected_stations; + std::vector affected_stations; CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], HasBit(p2, 0)); if (ret.Failed()) return ret; /* Do all station specific functions here. */ - for (Station **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) { - Station *st = *stp; + for (Station *st : affected_stations) { if (st->train_station.tile == INVALID_TILE) SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS); st->MarkTilesDirty(false); - st->RecomputeIndustriesNear(); + st->RecomputeCatchment(); } /* Now apply the rail cost to the number that we deleted */ @@ -1657,7 +1689,7 @@ CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint if (start >= MapSize() || end >= MapSize()) return CMD_ERROR; TileArea ta(start, end); - SmallVector affected_stations; + std::vector affected_stations; return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], HasBit(p2, 0)); } @@ -1690,7 +1722,7 @@ CommandCost RemoveRailStation(T *st, DoCommandFlag flags, Money removal_cost) TILE_AREA_LOOP(tile, ta) { /* only remove tiles that are actually train station tiles */ if (st->TileBelongsToRailStation(tile)) { - SmallVector affected_stations; // dummy + std::vector affected_stations; // dummy CommandCost ret = RemoveFromRailBaseStation(TileArea(tile, 1, 1), affected_stations, flags, removal_cost, false); if (ret.Failed()) return ret; cost.AddCost(ret); @@ -1716,7 +1748,7 @@ static CommandCost RemoveRailStation(TileIndex tile, DoCommandFlag flags) Station *st = Station::GetByTile(tile); CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]); - if (flags & DC_EXEC) st->RecomputeIndustriesNear(); + if (flags & DC_EXEC) st->RecomputeCatchment(); return cost; } @@ -1747,13 +1779,13 @@ static RoadStop **FindRoadStopSpot(bool truck_station, Station *st) { RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops; - if (*primary_stop == NULL) { + if (*primary_stop == nullptr) { /* we have no roadstop of the type yet, so write a "primary stop" */ return primary_stop; } else { /* there are stops already, so append to the end of the list */ RoadStop *stop = *primary_stop; - while (stop->next != NULL) stop = stop->next; + while (stop->next != nullptr) stop = stop->next; return &stop->next; } } @@ -1782,10 +1814,10 @@ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID statio * bit 8..15: Length of the road stop. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 1: 0 For normal stops, 1 for drive-through. - * bit 2..3: The roadtypes. - * bit 5: Allow stations directly adjacent to other stations. - * bit 6..7: Entrance direction (#DiagDirection) for normal stops. - * bit 6: #Axis of the road for drive-through stops. + * bit 2: Allow stations directly adjacent to other stations. + * bit 3..4: Entrance direction (#DiagDirection) for normal stops. + * bit 3: #Axis of the road for drive-through stops. + * bit 5..10: The roadtype. * bit 16..31: Station ID to join (NEW_STATION if build new one). * @param text Unused. * @return The cost of this operation or an error. @@ -1794,7 +1826,8 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin { bool type = HasBit(p2, 0); bool is_drive_through = HasBit(p2, 1); - RoadTypes rts = Extract(p2); + RoadType rt = Extract(p2); + if (!ValParamRoadType(rt)) return CMD_ERROR; StationID station_to_join = GB(p2, 16, 16); bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; @@ -1814,20 +1847,18 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; - if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR; - /* Trams only have drive through stops */ - if (!is_drive_through && HasBit(rts, ROADTYPE_TRAM)) return CMD_ERROR; + if (!is_drive_through && RoadTypeIsTram(rt)) return CMD_ERROR; DiagDirection ddir; Axis axis; if (is_drive_through) { /* By definition axis is valid, due to there being 2 axes and reading 1 bit. */ - axis = Extract(p2); + axis = Extract(p2); ddir = AxisToDiagDir(axis); } else { /* By definition ddir is valid, due to there being 4 diagonal directions and reading 2 bits. */ - ddir = Extract(p2); + ddir = Extract(p2); axis = DiagDirToAxis(ddir); } @@ -1837,12 +1868,12 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin /* Total road stop cost. */ CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]); StationID est = INVALID_STATION; - ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rts); + ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rt); if (ret.Failed()) return ret; cost.AddCost(ret); - Station *st = NULL; - ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 5), roadstop_area, &st); + Station *st = nullptr; + ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 2), roadstop_area, &st); if (ret.Failed()) return ret; /* Check if this number of road stops can be allocated. */ @@ -1854,9 +1885,11 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { /* Check every tile in the area. */ TILE_AREA_LOOP(cur_tile, roadstop_area) { - RoadTypes cur_rts = GetRoadTypes(cur_tile); - Owner road_owner = HasBit(cur_rts, ROADTYPE_ROAD) ? GetRoadOwner(cur_tile, ROADTYPE_ROAD) : _current_company; - Owner tram_owner = HasBit(cur_rts, ROADTYPE_TRAM) ? GetRoadOwner(cur_tile, ROADTYPE_TRAM) : _current_company; + /* Get existing road types and owners before any tile clearing */ + RoadType road_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_ROAD) : INVALID_ROADTYPE; + RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE; + Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company; + Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company; if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) { RemoveRoadStop(cur_tile, flags); @@ -1880,23 +1913,27 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS; if (is_drive_through) { - /* Update company infrastructure counts. If the current tile is a normal - * road tile, count only the new road bits needed to get a full diagonal road. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, cur_rts | rts) { - Company *c = Company::GetIfValid(rt == ROADTYPE_ROAD ? road_owner : tram_owner); - if (c != NULL) { - c->infrastructure.road[rt] += 2 - (IsNormalRoadTile(cur_tile) && HasBit(cur_rts, rt) ? CountBits(GetRoadBits(cur_tile, rt)) : 0); - DirtyCompanyInfrastructureWindows(c->index); - } + /* Update company infrastructure counts. If the current tile is a normal road tile, remove the old + * bits first. */ + if (IsNormalRoadTile(cur_tile)) { + UpdateCompanyRoadInfrastructure(road_rt, road_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_ROAD))); + UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_TRAM))); } - MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts | cur_rts, axis); + if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt; + if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt; + + UpdateCompanyRoadInfrastructure(road_rt, road_owner, 2); + UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, 2); + + MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis); road_stop->MakeDriveThrough(); } else { + if (road_rt == INVALID_ROADTYPE && RoadTypeIsRoad(rt)) road_rt = rt; + if (tram_rt == INVALID_ROADTYPE && RoadTypeIsTram(rt)) tram_rt = rt; /* Non-drive-through stop never overbuild and always count as two road bits. */ - Company::Get(st->owner)->infrastructure.road[FIND_FIRST_BIT(rts)] += 2; - MakeRoadStop(cur_tile, st->owner, st->index, rs_type, rts, ddir); + Company::Get(st->owner)->infrastructure.road[rt] += 2; + MakeRoadStop(cur_tile, st->owner, st->index, rs_type, road_rt, tram_rt, ddir); } Company::Get(st->owner)->infrastructure.station++; @@ -1904,7 +1941,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin } } - if (st != NULL) { + if (st != nullptr) { st->AfterStationTileSetChange(true, type ? STATION_TRUCK: STATION_BUS); } return cost; @@ -1924,7 +1961,7 @@ static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *) if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK; } - return NULL; + return nullptr; } @@ -1955,12 +1992,12 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS); } - assert(cur_stop != NULL); + assert(cur_stop != nullptr); /* don't do the check for drive-through road stops when company bankrupts */ if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) { /* remove the 'going through road stop' status from all vehicles on that tile */ - if (flags & DC_EXEC) FindVehicleOnPos(tile, NULL, &ClearRoadStopStatusEnum); + if (flags & DC_EXEC) FindVehicleOnPos(tile, nullptr, &ClearRoadStopStatusEnum); } else { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; @@ -1971,7 +2008,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) /* removed the first stop in the list */ *primary_stop = cur_stop->next; /* removed the only stop? */ - if (*primary_stop == NULL) { + if (*primary_stop == nullptr) { st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP); } } else { @@ -1982,14 +2019,11 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) } /* Update company infrastructure counts. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - c->infrastructure.road[rt] -= 2; - DirtyCompanyInfrastructureWindows(c->index); - } + FOR_ALL_ROADTRAMTYPES(rtt) { + RoadType rt = GetRoadType(tile, rtt); + UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -2); } + Company::Get(st->owner)->infrastructure.station--; DirtyCompanyInfrastructureWindows(st->owner); @@ -2018,10 +2052,10 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) /* Update the tile area of the truck/bus stop */ if (is_truck) { st->truck_station.Clear(); - for (const RoadStop *rs = st->truck_stops; rs != NULL; rs = rs->next) st->truck_station.Add(rs->xy); + for (const RoadStop *rs = st->truck_stops; rs != nullptr; rs = rs->next) st->truck_station.Add(rs->xy); } else { st->bus_station.Clear(); - for (const RoadStop *rs = st->bus_stops; rs != NULL; rs = rs->next) st->bus_station.Add(rs->xy); + for (const RoadStop *rs = st->bus_stops; rs != nullptr; rs = rs->next) st->bus_station.Add(rs->xy); } } @@ -2063,16 +2097,16 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue; /* Save information on to-be-restored roads before the stop is removed. */ - RoadTypes rts = ROADTYPES_NONE; RoadBits road_bits = ROAD_NONE; + RoadType road_type[] = { INVALID_ROADTYPE, INVALID_ROADTYPE }; Owner road_owner[] = { OWNER_NONE, OWNER_NONE }; - assert_compile(lengthof(road_owner) == ROADTYPE_END); if (IsDriveThroughStopTile(cur_tile)) { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(cur_tile)) { - road_owner[rt] = GetRoadOwner(cur_tile, rt); + FOR_ALL_ROADTRAMTYPES(rtt) { + road_type[rtt] = GetRoadType(cur_tile, rtt); + if (road_type[rtt] == INVALID_ROADTYPE) continue; + road_owner[rtt] = GetRoadOwner(cur_tile, rtt); /* If we don't want to preserve our roads then restore only roads of others. */ - if (keep_drive_through_roads || road_owner[rt] != _current_company) SetBit(rts, rt); + if (!keep_drive_through_roads && road_owner[rtt] == _current_company) road_type[rtt] = INVALID_ROADTYPE; } road_bits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(cur_tile))); } @@ -2086,19 +2120,14 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui had_success = true; /* Restore roads. */ - if ((flags & DC_EXEC) && rts != ROADTYPES_NONE) { - MakeRoadNormal(cur_tile, road_bits, rts, ClosestTownFromTile(cur_tile, UINT_MAX)->index, - road_owner[ROADTYPE_ROAD], road_owner[ROADTYPE_TRAM]); + if ((flags & DC_EXEC) && (road_type[RTT_ROAD] != INVALID_ROADTYPE || road_type[RTT_TRAM] != INVALID_ROADTYPE)) { + MakeRoadNormal(cur_tile, road_bits, road_type[RTT_ROAD], road_type[RTT_TRAM], ClosestTownFromTile(cur_tile, UINT_MAX)->index, + road_owner[RTT_ROAD], road_owner[RTT_TRAM]); /* Update company infrastructure counts. */ - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, rts) { - Company *c = Company::GetIfValid(GetRoadOwner(cur_tile, rt)); - if (c != NULL) { - c->infrastructure.road[rt] += CountBits(road_bits); - DirtyCompanyInfrastructureWindows(c->index); - } - } + int count = CountBits(road_bits); + UpdateCompanyRoadInfrastructure(road_type[RTT_ROAD], road_owner[RTT_ROAD], count); + UpdateCompanyRoadInfrastructure(road_type[RTT_TRAM], road_owner[RTT_ROAD], count); } } @@ -2127,18 +2156,15 @@ static uint GetMinimalAirportDistanceToTile(TileIterator &it, TileIndex town_til * The further you get, the less noise you generate. * So all those folks at city council can now happily slee... work in their offices * @param as airport information - * @param it An iterator over all airport tiles. - * @param town_tile TileIndex of town's center, the one who will receive the airport's candidature + * @param distance minimum distance between town and airport * @return the noise that will be generated, according to distance */ -uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile) +uint8 GetAirportNoiseLevelForDistance(const AirportSpec *as, uint distance) { /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town. * So no need to go any further*/ if (as->noise_level < 2) return as->noise_level; - uint distance = GetMinimalAirportDistanceToTile(it, town_tile); - /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance. * Basically, it says that the less tolerant a town is, the bigger the distance before @@ -2159,13 +2185,14 @@ uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileI * If two towns have the same distance, town with lower index is returned. * @param as airport's description * @param it An iterator over all airport tiles + * @param[out] mindist Minimum distance to town * @return nearest town to airport */ -Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it) +Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it, uint &mindist) { - Town *t, *nearest = NULL; + Town *t, *nearest = nullptr; uint add = as->size_x + as->size_y - 2; // GetMinimalAirportDistanceToTile can differ from DistanceManhattan by this much - uint mindist = UINT_MAX - add; // prevent overflow + mindist = UINT_MAX - add; // prevent overflow FOR_ALL_TOWNS(t) { if (DistanceManhattan(t->xy, it) < mindist + add) { // avoid calling GetMinimalAirportDistanceToTile too often TileIterator *copy = it.Clone(); @@ -2194,8 +2221,9 @@ void UpdateAirportsNoise() if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) { const AirportSpec *as = st->airport.GetSpec(); AirportTileIterator it(st); - Town *nearest = AirportGetNearestTown(as, it); - nearest->noise_reached += GetAirportNoiseLevelForTown(as, it, nearest->xy); + uint dist; + Town *nearest = AirportGetNearestTown(as, it, dist); + nearest->noise_reached += GetAirportNoiseLevelForDistance(as, dist); } } } @@ -2232,6 +2260,7 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint /* Check if a valid, buildable airport was chosen for construction */ const AirportSpec *as = AirportSpec::Get(airport_type); if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR; + if (!as->IsWithinMapBounds(layout, tile)) return CMD_ERROR; Direction rotation = as->rotation[layout]; int w = as->size_x; @@ -2248,12 +2277,13 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint if (cost.Failed()) return cost; /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */ - Town *nearest = AirportGetNearestTown(as, iter); - uint newnoise_level = GetAirportNoiseLevelForTown(as, iter, nearest->xy); + uint dist; + Town *nearest = AirportGetNearestTown(as, iter, dist); + uint newnoise_level = GetAirportNoiseLevelForDistance(as, dist); /* Check if local auth would allow a new airport */ StringID authority_refuse_message = STR_NULL; - Town *authority_refuse_town = NULL; + Town *authority_refuse_town = nullptr; if (_settings_game.economy.station_noise_level) { /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */ @@ -2279,17 +2309,17 @@ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint return_cmd_error(authority_refuse_message); } - Station *st = NULL; + Station *st = nullptr; ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), airport_area, &st); if (ret.Failed()) return ret; /* Distant join */ - if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join); + if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join); ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT); if (ret.Failed()) return ret; - if (st != NULL && st->airport.tile != INVALID_TILE) { + if (st != nullptr && st->airport.tile != INVALID_TILE) { return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT); } @@ -2370,8 +2400,9 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) * And as for construction, always remove it, even if the setting is not set, in order to avoid the * need of recalculation */ AirportTileIterator it(st); - Town *nearest = AirportGetNearestTown(as, it); - nearest->noise_reached -= GetAirportNoiseLevelForTown(as, it, nearest->xy); + uint dist; + Town *nearest = AirportGetNearestTown(as, it, dist); + nearest->noise_reached -= GetAirportNoiseLevelForDistance(as, dist); } TILE_AREA_LOOP(tile_cur, st->airport) { @@ -2534,20 +2565,19 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 _dock_w_chk[direction], _dock_h_chk[direction]); /* middle */ - Station *st = NULL; + Station *st = nullptr; ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0), dock_area, &st); if (ret.Failed()) return ret; /* Distant join */ - if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join); + if (st == nullptr && distant_join) st = Station::GetIfValid(station_to_join); ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK); if (ret.Failed()) return ret; - if (st != NULL && st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK); - if (flags & DC_EXEC) { - st->dock_tile = tile; + st->ship_station.Add(tile); + st->ship_station.Add(tile + TileOffsByDiagDir(direction)); st->AddFacility(FACIL_DOCK, tile); st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY); @@ -2560,6 +2590,7 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Company::Get(st->owner)->infrastructure.station += 2; MakeDock(tile, st->owner, st->index, direction, wc); + UpdateStationDockingTiles(st); st->AfterStationTileSetChange(true, STATION_DOCK); } @@ -2567,6 +2598,86 @@ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]); } +void RemoveDockingTile(TileIndex t) +{ + for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) { + TileIndex tile = t + TileOffsByDiagDir(d); + if (!IsValidTile(tile)) continue; + + if (IsTileType(tile, MP_STATION)) { + UpdateStationDockingTiles(Station::GetByTile(tile)); + } else if (IsTileType(tile, MP_INDUSTRY)) { + Station *neutral = Industry::GetByTile(tile)->neutral_station; + if (neutral != nullptr) UpdateStationDockingTiles(neutral); + } + } +} + +/** + * Clear docking tile status from tiles around a removed dock, if the tile has + * no neighbours which would keep it as a docking tile. + * @param tile Ex-dock tile to check. + */ +void ClearDockingTilesCheckingNeighbours(TileIndex tile) +{ + assert(IsValidTile(tile)); + + /* Clear and maybe re-set docking tile */ + for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) { + TileIndex docking_tile = tile + TileOffsByDiagDir(d); + if (!IsValidTile(docking_tile)) continue; + + if (IsPossibleDockingTile(docking_tile)) { + SetDockingTile(docking_tile, false); + CheckForDockingTile(docking_tile); + } + } +} + +/** + * Check if a dock tile can be docked from the given direction. + * @param t Tile index of dock. + * @param d DiagDirection adjacent to dock being tested. + * @return True iff the dock can be docked from the given direction. + */ +bool IsValidDockingDirectionForDock(TileIndex t, DiagDirection d) +{ + assert(IsDockTile(t)); + + /** Bitmap of valid directions for each dock tile part. */ + static const uint8 _valid_docking_tile[] = { + 0, 0, 0, 0, // No docking against the slope part. + 1 << DIAGDIR_NE | 1 << DIAGDIR_SW, // Docking permitted at the end + 1 << DIAGDIR_NW | 1 << DIAGDIR_SE, // of the flat piers. + }; + + StationGfx gfx = GetStationGfx(t); + assert(gfx < lengthof(_valid_docking_tile)); + return HasBit(_valid_docking_tile[gfx], d); +} + +/** + * Find the part of a dock that is land-based + * @param t Dock tile to find land part of + * @return tile of land part of dock + */ +static TileIndex FindDockLandPart(TileIndex t) +{ + assert(IsDockTile(t)); + + StationGfx gfx = GetStationGfx(t); + if (gfx < GFX_DOCK_BASE_WATER_PART) return t; + + for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) { + TileIndex tile = t + TileOffsByDiagDir(d); + if (!IsValidTile(tile)) continue; + if (!IsDockTile(tile)) continue; + if (GetStationGfx(tile) < GFX_DOCK_BASE_WATER_PART && tile + TileOffsByDiagDir(GetDockDirection(tile)) == t) return tile; + } + + return INVALID_TILE; +} + /** * Remove a dock * @param tile TileIndex been queried @@ -2579,9 +2690,10 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; - TileIndex docking_location = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); + if (!IsDockTile(tile)) return CMD_ERROR; - TileIndex tile1 = st->dock_tile; + TileIndex tile1 = FindDockLandPart(tile); + if (tile1 == INVALID_TILE) return CMD_ERROR; TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1)); ret = EnsureNoVehicleOnGround(tile1); @@ -2596,26 +2708,34 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) st->rect.AfterRemoveTile(st, tile1); st->rect.AfterRemoveTile(st, tile2); - st->dock_tile = INVALID_TILE; - st->facilities &= ~FACIL_DOCK; + MakeShipStationAreaSmaller(st); + if (st->ship_station.tile == INVALID_TILE) { + st->ship_station.Clear(); + st->docking_station.Clear(); + st->facilities &= ~FACIL_DOCK; + } Company::Get(st->owner)->infrastructure.station -= 2; st->AfterStationTileSetChange(false, STATION_DOCK); + ClearDockingTilesCheckingNeighbours(tile1); + ClearDockingTilesCheckingNeighbours(tile2); + /* All ships that were going to our station, can't go to it anymore. * Just clear the order, then automatically the next appropriate order * will be selected and in case of no appropriate order it will just * wander around the world. */ - Ship *s; - FOR_ALL_SHIPS(s) { - if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) { - s->LeaveStation(); - } + if (!(st->facilities & FACIL_DOCK)) { + Ship *s; + FOR_ALL_SHIPS(s) { + if (s->current_order.IsType(OT_LOADING) && s->current_order.GetDestination() == st->index) { + s->LeaveStation(); + } - if (s->dest_tile == docking_location) { - s->SetDestTile(0); - s->current_order.Free(); + if (s->current_order.IsType(OT_GOTO_STATION) && s->current_order.GetDestination() == st->index) { + s->SetDestTile(s->GetOrderStationLocation(st->index)); + } } } } @@ -2634,7 +2754,7 @@ const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx) * Check whether a sprite is a track sprite, which can be replaced by a non-track ground sprite and a rail overlay. * If the ground sprite is suitable, \a ground is replaced with the new non-track ground sprite, and \a overlay_offset * is set to the overlay to draw. - * @param ti Positional info for the tile to decide snowyness etc. May be NULL. + * @param ti Positional info for the tile to decide snowyness etc. May be nullptr. * @param[in,out] ground Groundsprite to draw. * @param[out] overlay_offset Overlay to draw. * @return true if overlay can be drawn. @@ -2675,7 +2795,7 @@ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrack return false; } - if (ti != NULL) { + if (ti != nullptr) { /* Decide snow/desert from tile */ switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: @@ -2697,21 +2817,19 @@ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrack static void DrawTile_Station(TileInfo *ti) { - const NewGRFSpriteLayout *layout = NULL; + const NewGRFSpriteLayout *layout = nullptr; DrawTileSprites tmp_rail_layout; - const DrawTileSprites *t = NULL; - RoadTypes roadtypes; + const DrawTileSprites *t = nullptr; int32 total_offset; - const RailtypeInfo *rti = NULL; + const RailtypeInfo *rti = nullptr; uint32 relocation = 0; uint32 ground_relocation = 0; - BaseStation *st = NULL; - const StationSpec *statspec = NULL; + BaseStation *st = nullptr; + const StationSpec *statspec = nullptr; uint tile_layout = 0; if (HasStationRail(ti->tile)) { rti = GetRailTypeInfo(GetRailType(ti->tile)); - roadtypes = ROADTYPES_NONE; total_offset = rti->GetRailtypeSpriteOffset(); if (IsCustomStationSpecIndex(ti->tile)) { @@ -2719,7 +2837,7 @@ static void DrawTile_Station(TileInfo *ti) st = BaseStation::GetByTile(ti->tile); statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec; - if (statspec != NULL) { + if (statspec != nullptr) { tile_layout = GetStationGfx(ti->tile); if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) { @@ -2728,17 +2846,16 @@ static void DrawTile_Station(TileInfo *ti) } /* Ensure the chosen tile layout is valid for this custom station */ - if (statspec->renderdata != NULL) { + if (statspec->renderdata != nullptr) { layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)]; if (!layout->NeedsPreprocessing()) { t = layout; - layout = NULL; + layout = nullptr; } } } } } else { - roadtypes = IsRoadStop(ti->tile) ? GetRoadTypes(ti->tile) : ROADTYPES_NONE; total_offset = 0; } @@ -2747,7 +2864,7 @@ static void DrawTile_Station(TileInfo *ti) gfx = GetAirportGfx(ti->tile); if (gfx >= NEW_AIRPORTTILE_OFFSET) { const AirportTileSpec *ats = AirportTileSpec::Get(gfx); - if (ats->grf_prop.spritegroup[0] != NULL && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) { + if (ats->grf_prop.spritegroup[0] != nullptr && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) { return; } /* No sprite group (or no valid one) found, meaning no graphics associated. @@ -2784,11 +2901,11 @@ static void DrawTile_Station(TileInfo *ti) palette = PALETTE_TO_GREY; } - if (layout == NULL && (t == NULL || t->seq == NULL)) t = GetStationTileLayout(GetStationType(ti->tile), gfx); + if (layout == nullptr && (t == nullptr || t->seq == nullptr)) t = GetStationTileLayout(GetStationType(ti->tile), gfx); /* don't show foundation for docks */ if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) { - if (statspec != NULL && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) { + if (statspec != nullptr && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) { /* Station has custom foundations. * Check whether the foundation continues beyond the tile's upper sides. */ uint edge_info = 0; @@ -2867,7 +2984,7 @@ draw_default_foundation: } else { assert(IsDock(ti->tile)); TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile)); - WaterClass wc = GetWaterClass(water_tile); + WaterClass wc = HasTileWaterClass(water_tile) ? GetWaterClass(water_tile) : WATER_CLASS_INVALID; if (wc == WATER_CLASS_SEA) { DrawShoreTile(ti->tileh); } else { @@ -2875,7 +2992,7 @@ draw_default_foundation: } } } else { - if (layout != NULL) { + if (layout != nullptr) { /* Sprite layout which needs preprocessing */ bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND); uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground); @@ -2887,7 +3004,7 @@ draw_default_foundation: tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground); t = &tmp_rail_layout; total_offset = 0; - } else if (statspec != NULL) { + } else if (statspec != nullptr) { /* Simple sprite layout */ ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0); if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) { @@ -2899,7 +3016,7 @@ draw_default_foundation: SpriteID image = t->ground.sprite; PaletteID pal = t->ground.pal; RailTrackOffset overlay_offset; - if (rti != NULL && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) { + if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) { SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND); DrawGroundSprite(image, PAL_NONE); DrawGroundSprite(ground + overlay_offset, PAL_NONE); @@ -2923,10 +3040,30 @@ draw_default_foundation: if (HasStationRail(ti->tile) && HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti); - if (HasBit(roadtypes, ROADTYPE_TRAM)) { - Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; - DrawGroundSprite((HasBit(roadtypes, ROADTYPE_ROAD) ? SPR_TRAMWAY_OVERLAY : SPR_TRAMWAY_TRAM) + (axis ^ 1), PAL_NONE); - DrawRoadCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y); + if (IsRoadStop(ti->tile)) { + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo* tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + if (IsDriveThroughStopTile(ti->tile)) { + Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; + uint sprite_offset = axis == AXIS_X ? 1 : 0; + + DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset); + } else { + /* Non-drivethrough road stops are only valid for roads. */ + assert(road_rt != INVALID_ROADTYPE && tram_rt == INVALID_ROADTYPE); + + if (road_rti->UsesOverlay()) { + DiagDirection dir = GetRoadStopDir(ti->tile); + SpriteID ground = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_ROADSTOP); + DrawGroundSprite(ground + dir, PAL_NONE); + } + } + + /* Draw road, tram catenary */ + DrawRoadCatenary(ti); } if (IsRailWaypoint(ti->tile)) { @@ -2942,7 +3079,7 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro int32 total_offset = 0; PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company); const DrawTileSprites *t = GetStationTileLayout(st, image); - const RailtypeInfo *rti = NULL; + const RailtypeInfo *rti = nullptr; if (railtype != INVALID_RAILTYPE) { rti = GetRailTypeInfo(railtype); @@ -2951,7 +3088,7 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro SpriteID img = t->ground.sprite; RailTrackOffset overlay_offset; - if (rti != NULL && rti->UsesOverlay() && SplitGroundSpriteForOverlay(NULL, &img, &overlay_offset)) { + if (rti != nullptr && rti->UsesOverlay() && SplitGroundSpriteForOverlay(nullptr, &img, &overlay_offset)) { SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND); DrawSprite(img, PAL_NONE, x, y); DrawSprite(ground + overlay_offset, PAL_NONE, x, y); @@ -2959,8 +3096,29 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y); } - if (roadtype == ROADTYPE_TRAM) { - DrawSprite(SPR_TRAMWAY_TRAM + (t->ground.sprite == SPR_ROAD_PAVED_STRAIGHT_X ? 1 : 0), PAL_NONE, x, y); + if (roadtype != INVALID_ROADTYPE) { + const RoadTypeInfo* rti = GetRoadTypeInfo(roadtype); + if (image >= 4) { + /* Drive-through stop */ + uint sprite_offset = 5 - image; + + /* Road underlay takes precedence over tram */ + if (rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_GROUND); + DrawSprite(ground + sprite_offset, PAL_NONE, x, y); + + SpriteID overlay = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_OVERLAY); + if (overlay) DrawSprite(overlay + sprite_offset, PAL_NONE, x, y); + } else if (RoadTypeIsTram(roadtype)) { + DrawSprite(SPR_TRAMWAY_TRAM + sprite_offset, PAL_NONE, x, y); + } + } else { + /* Drive-in stop */ + if (RoadTypeIsRoad(roadtype) && rti->UsesOverlay()) { + SpriteID ground = GetCustomRoadSprite(rti, INVALID_TILE, ROTSG_ROADSTOP); + DrawSprite(ground + image, PAL_NONE, x, y); + } + } } /* Default waypoint has no railtype specific sprites */ @@ -2980,38 +3138,54 @@ static Foundation GetFoundation_Station(TileIndex tile, Slope tileh) static void GetTileDesc_Station(TileIndex tile, TileDesc *td) { td->owner[0] = GetTileOwner(tile); - if (IsDriveThroughStopTile(tile)) { + + if (IsRoadStopTile(tile)) { + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; - RoadTypes rts = GetRoadTypes(tile); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } - /* Is there a mix of owners? */ - if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || - (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { - uint i = 1; - if (road_owner != INVALID_OWNER) { - td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; - td->owner[i] = road_owner; - i++; - } - if (tram_owner != INVALID_OWNER) { - td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; - td->owner[i] = tram_owner; + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } + + if (IsDriveThroughStopTile(tile)) { + /* Is there a mix of owners? */ + if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || + (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { + uint i = 1; + if (road_owner != INVALID_OWNER) { + td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; + td->owner[i] = road_owner; + i++; + } + if (tram_owner != INVALID_OWNER) { + td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; + td->owner[i] = tram_owner; + } } } } + td->build_date = BaseStation::GetByTile(tile)->build_date; if (HasStationTileRail(tile)) { const StationSpec *spec = GetStationSpec(tile); - if (spec != NULL) { + if (spec != nullptr) { td->station_class = StationClass::Get(spec->cls_id)->name; td->station_name = spec->name; - if (spec->grf_prop.grffile != NULL) { + if (spec->grf_prop.grffile != nullptr) { const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid); td->grf = gc->GetName(); } @@ -3030,10 +3204,10 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td) const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); td->airport_tile_name = ats->name; - if (as->grf_prop.grffile != NULL) { + if (as->grf_prop.grffile != nullptr) { const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid); td->grf = gc->GetName(); - } else if (ats->grf_prop.grffile != NULL) { + } else if (ats->grf_prop.grffile != nullptr) { const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid); td->grf = gc->GetName(); } @@ -3048,7 +3222,14 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td) break; case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break; case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break; - case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break; + case STATION_OILRIG: { + const Industry *i = Station::GetByTile(tile)->industry; + const IndustrySpec *is = GetIndustrySpec(i->type); + td->owner[0] = i->owner; + str = is->name; + if (is->grf_prop.grffile != nullptr) td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName(); + break; + } case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break; case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break; case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break; @@ -3080,7 +3261,10 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode break; case TRANSPORT_ROAD: - if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) { + if (IsRoadStop(tile)) { + RoadTramType rtt = (RoadTramType)sub_mode; + if (!HasTileRoadType(tile, rtt)) break; + DiagDirection dir = GetRoadStopDir(tile); Axis axis = DiagDirToAxis(dir); @@ -3215,9 +3399,8 @@ void TriggerWatchedCargoCallbacks(Station *st) if (cargoes == 0) return; /* Loop over all houses in the catchment. */ - Rect r = st->GetCatchmentRect(); - TileArea ta(TileXY(r.left, r.top), TileXY(r.right, r.bottom)); - TILE_AREA_LOOP(tile, ta) { + BitmapTileIterator it(st->catchment_tiles); + for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { if (IsTileType(tile, MP_HOUSE)) { WatchedCargoCallback(tile, cargoes); } @@ -3272,7 +3455,7 @@ static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UIN ge->cargo.Truncate(amount, &waiting_per_source); for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) { Station *source_station = Station::GetIfValid(i->first); - if (source_station == NULL) continue; + if (source_station == nullptr) continue; GoodsEntry &source_ge = source_station->goods[cs->Index()]; source_ge.max_waiting_cargo = max(source_ge.max_waiting_cargo, i->second); @@ -3350,27 +3533,25 @@ static void UpdateStationRating(Station *st) byte waittime = ge->time_since_pickup; if (st->last_vehicle_type == VEH_SHIP) waittime >>= 2; - (waittime > 21) || - (rating += 25, waittime > 12) || - (rating += 25, waittime > 6) || - (rating += 45, waittime > 3) || - (rating += 35, true); + if (waittime <= 21) rating += 25; + if (waittime <= 12) rating += 25; + if (waittime <= 6) rating += 45; + if (waittime <= 3) rating += 35; - (rating -= 90, ge->max_waiting_cargo > 1500) || - (rating += 55, ge->max_waiting_cargo > 1000) || - (rating += 35, ge->max_waiting_cargo > 600) || - (rating += 10, ge->max_waiting_cargo > 300) || - (rating += 20, ge->max_waiting_cargo > 100) || - (rating += 10, true); + rating -= 90; + if (ge->max_waiting_cargo <= 1500) rating += 55; + if (ge->max_waiting_cargo <= 1000) rating += 35; + if (ge->max_waiting_cargo <= 600) rating += 10; + if (ge->max_waiting_cargo <= 300) rating += 20; + if (ge->max_waiting_cargo <= 100) rating += 10; } if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26; byte age = ge->last_age; - (age >= 3) || - (rating += 10, age >= 2) || - (rating += 10, age >= 1) || - (rating += 13, true); + if (age < 3) rating += 10; + if (age < 2) rating += 10; + if (age < 1) rating += 13; { int or_ = ge->rating; // old rating @@ -3453,7 +3634,7 @@ void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2) /* Reroute cargo staged to be transferred. */ for (std::list::iterator it(st->loading_vehicles.begin()); it != st->loading_vehicles.end(); ++it) { - for (Vehicle *v = *it; v != NULL; v = v->Next()) { + for (Vehicle *v = *it; v != nullptr; v = v->Next()) { if (v->cargo_type != c) continue; v->cargo.Reroute(UINT_MAX, &v->cargo, avoid, avoid2, &ge); } @@ -3474,7 +3655,7 @@ void DeleteStaleLinks(Station *from) const bool auto_distributed = (_settings_game.linkgraph.GetDistributionType(c) != DT_MANUAL); GoodsEntry &ge = from->goods[c]; LinkGraph *lg = LinkGraph::GetIfValid(ge.link_graph); - if (lg == NULL) continue; + if (lg == nullptr) continue; Node node = (*lg)[ge.node]; for (EdgeIterator it(node.Begin()); it != node.End();) { Edge edge = it->second; @@ -3490,11 +3671,11 @@ void DeleteStaleLinks(Station *from) /* Have all vehicles refresh their next hops before deciding to * remove the node. */ OrderList *l; - SmallVector vehicles; + std::vector vehicles; FOR_ALL_ORDER_LISTS(l) { bool found_from = false; bool found_to = false; - for (Order *order = l->GetFirstOrder(); order != NULL; order = order->next) { + for (Order *order = l->GetFirstOrder(); order != nullptr; order = order->next) { if (!order->IsType(OT_GOTO_STATION) && !order->IsType(OT_IMPLICIT)) continue; if (order->GetDestination() == from->index) { found_from = true; @@ -3505,11 +3686,11 @@ void DeleteStaleLinks(Station *from) } } if (!found_to || !found_from) continue; - *(vehicles.Append()) = l->GetFirstSharedVehicle(); + vehicles.push_back(l->GetFirstSharedVehicle()); } - Vehicle **iter = vehicles.Begin(); - while (iter != vehicles.End()) { + auto iter = vehicles.begin(); + while (iter != vehicles.end()) { Vehicle *v = *iter; LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted. @@ -3523,10 +3704,10 @@ void DeleteStaleLinks(Station *from) *iter = next_shared; ++iter; } else { - vehicles.Erase(iter); + iter = vehicles.erase(iter); } - if (iter == vehicles.End()) iter = vehicles.Begin(); + if (iter == vehicles.end()) iter = vehicles.begin(); } } @@ -3565,7 +3746,7 @@ void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint c GoodsEntry &ge1 = st->goods[cargo]; Station *st2 = Station::Get(next_station_id); GoodsEntry &ge2 = st2->goods[cargo]; - LinkGraph *lg = NULL; + LinkGraph *lg = nullptr; if (ge1.link_graph == INVALID_LINK_GRAPH) { if (ge2.link_graph == INVALID_LINK_GRAPH) { if (LinkGraph::CanAllocateItem()) { @@ -3601,7 +3782,7 @@ void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint c } } } - if (lg != NULL) { + if (lg != nullptr) { (*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode); } } @@ -3614,7 +3795,7 @@ void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint c */ void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id) { - for (const Vehicle *v = front; v != NULL; v = v->Next()) { + for (const Vehicle *v = front; v != nullptr; v = v->Next()) { if (v->refit_cap > 0) { /* The cargo count can indeed be higher than the refit_cap if * wagons have been auto-replaced and subsequently auto- @@ -3623,7 +3804,7 @@ void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id) * As usage is not such an important figure anyway we just * ignore the additional cargo then.*/ IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap, - min(v->refit_cap, v->cargo.StoredCount()), EUM_INCREASE); + min(v->refit_cap, v->cargo.StoredCount()), EUM_INCREASE); } } } @@ -3682,11 +3863,8 @@ void StationMonthlyLoop() void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius) { - Station *st; - - FOR_ALL_STATIONS(st) { - if (st->owner == owner && - DistanceManhattan(tile, st->xy) <= radius) { + ForAllStationsRadius(tile, radius, [&](Station *st) { + if (st->owner == owner) { for (CargoID i = 0; i < NUM_CARGO; i++) { GoodsEntry *ge = &st->goods[i]; @@ -3695,7 +3873,7 @@ void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint rad } } } - } + }); } static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id) @@ -3714,7 +3892,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT StationID next = ge.GetVia(st->index); ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next); - LinkGraph *lg = NULL; + LinkGraph *lg = nullptr; if (ge.link_graph == INVALID_LINK_GRAPH) { if (LinkGraph::CanAllocateItem()) { lg = new LinkGraph(type); @@ -3727,7 +3905,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT } else { lg = LinkGraph::Get(ge.link_graph); } - if (lg != NULL) (*lg)[ge.node].UpdateSupply(amount); + if (lg != nullptr) (*lg)[ge.node].UpdateSupply(amount); if (!ge.HasRating()) { InvalidateWindowData(WC_STATION_LIST, st->index); @@ -3748,7 +3926,7 @@ static bool IsUniqueStationName(const char *name) const Station *st; FOR_ALL_STATIONS(st) { - if (st->name != NULL && strcmp(st->name, name) == 0) return false; + if (st->name != nullptr && strcmp(st->name, name) == 0) return false; } return true; @@ -3766,7 +3944,7 @@ static bool IsUniqueStationName(const char *name) CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Station *st = Station::GetIfValid(p1); - if (st == NULL) return CMD_ERROR; + if (st == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; @@ -3780,7 +3958,7 @@ CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { free(st->name); - st->name = reset ? NULL : stredup(text); + st->name = reset ? nullptr : stredup(text); st->UpdateVirtCoord(); InvalidateWindowData(WC_STATION_LIST, st->owner, 1); @@ -3789,52 +3967,60 @@ CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uin return CommandCost(); } +static void AddNearbyStationsByCatchment(TileIndex tile, StationList *stations, StationList &nearby) +{ + for (Station *st : nearby) { + if (st->TileIsInCatchment(tile)) stations->insert(st); + } +} + /** * Find all stations around a rectangular producer (industry, house, headquarter, ...) * * @param location The location/area of the producer - * @param stations The list to store the stations in + * @param[out] stations The list to store the stations in + * @param use_nearby Use nearby station list of industry/town associated with location.tile */ -void FindStationsAroundTiles(const TileArea &location, StationList *stations) +void FindStationsAroundTiles(const TileArea &location, StationList * const stations, bool use_nearby) { - /* area to search = producer plus station catchment radius */ - uint max_rad = (_settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED); + if (use_nearby) { + /* Industries and towns maintain a list of nearby stations */ + if (IsTileType(location.tile, MP_INDUSTRY)) { + /* Industry nearby stations are already filtered by catchment. */ + *stations = Industry::GetByTile(location.tile)->stations_near; + return; + } else if (IsTileType(location.tile, MP_HOUSE)) { + /* Town nearby stations need to be filtered per tile. */ + assert(location.w == 1 && location.h == 1); + AddNearbyStationsByCatchment(location.tile, stations, Town::GetByTile(location.tile)->stations_near); + return; + } + } - uint x = TileX(location.tile); - uint y = TileY(location.tile); + /* Not using, or don't have a nearby stations list, so we need to scan. */ + std::set seen_stations; - uint min_x = (x > max_rad) ? x - max_rad : 0; - uint max_x = x + location.w + max_rad; - uint min_y = (y > max_rad) ? y - max_rad : 0; - uint max_y = y + location.h + max_rad; + /* Scan an area around the building covering the maximum possible station + * to find the possible nearby stations. */ + uint max_c = _settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED; + TileArea ta = TileArea(location).Expand(max_c); + TILE_AREA_LOOP(tile, ta) { + if (IsTileType(tile, MP_STATION)) seen_stations.insert(GetStationIndex(tile)); + } - if (min_x == 0 && _settings_game.construction.freeform_edges) min_x = 1; - if (min_y == 0 && _settings_game.construction.freeform_edges) min_y = 1; - if (max_x >= MapSizeX()) max_x = MapSizeX() - 1; - if (max_y >= MapSizeY()) max_y = MapSizeY() - 1; + for (StationID stationid : seen_stations) { + Station *st = Station::GetIfValid(stationid); + if (st == nullptr) continue; /* Waypoint */ - for (uint cy = min_y; cy < max_y; cy++) { - for (uint cx = min_x; cx < max_x; cx++) { - TileIndex cur_tile = TileXY(cx, cy); - if (!IsTileType(cur_tile, MP_STATION)) continue; + /* Check if station is attached to an industry */ + if (!_settings_game.station.serve_neutral_industries && st->industry != nullptr) continue; - Station *st = Station::GetByTile(cur_tile); - /* st can be NULL in case of waypoints */ - if (st == NULL) continue; - - if (_settings_game.station.modified_catchment) { - int rad = st->GetCatchmentRadius(); - int rad_x = cx - x; - int rad_y = cy - y; - - if (rad_x < -rad || rad_x >= rad + location.w) continue; - if (rad_y < -rad || rad_y >= rad + location.h) continue; + /* Test if the tile is within the station's catchment */ + TILE_AREA_LOOP(tile, location) { + if (st->TileIsInCatchment(tile)) { + stations->insert(st); + break; } - - /* Insert the station in the set. This will fail if it has - * already been added. - */ - stations->Include(st); } } } @@ -3857,14 +4043,12 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc /* Return if nothing to do. Also the rounding below fails for 0. */ if (amount == 0) return 0; - Station *st1 = NULL; // Station with best rating - Station *st2 = NULL; // Second best station + Station *st1 = nullptr; // Station with best rating + Station *st2 = nullptr; // Second best station uint best_rating1 = 0; // rating of st1 uint best_rating2 = 0; // rating of st2 - for (Station * const *st_iter = all_stations->Begin(); st_iter != all_stations->End(); ++st_iter) { - Station *st = *st_iter; - + for (Station *st : *all_stations) { /* Is the station reserved exclusively for somebody else? */ if (st->owner != OWNER_NONE && st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) continue; @@ -3879,28 +4063,28 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc } /* This station can be used, add it to st1/st2 */ - if (st1 == NULL || st->goods[type].rating >= best_rating1) { + if (st1 == nullptr || st->goods[type].rating >= best_rating1) { st2 = st1; best_rating2 = best_rating1; st1 = st; best_rating1 = st->goods[type].rating; - } else if (st2 == NULL || st->goods[type].rating >= best_rating2) { + } else if (st2 == nullptr || st->goods[type].rating >= best_rating2) { st2 = st; best_rating2 = st->goods[type].rating; } } /* no stations around at all? */ - if (st1 == NULL) return 0; + if (st1 == nullptr) return 0; /* From now we'll calculate with fractal cargo amounts. * First determine how much cargo we really have. */ amount *= best_rating1 + 1; - if (st2 == NULL) { + if (st2 == nullptr) { /* only one station around */ return UpdateStationWaiting(st1, type, amount, source_type, source_id); } /* several stations around, the best two (highest rating) are in st1 and st2 */ - assert(st1 != NULL); - assert(st2 != NULL); + assert(st1 != nullptr); + assert(st2 != nullptr); assert(best_rating1 != 0 || best_rating2 != 0); /* Then determine the amount the worst station gets. We do it this way as the @@ -3918,6 +4102,32 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id); } +void UpdateStationDockingTiles(Station *st) +{ + st->docking_station.Clear(); + + /* For neutral stations, start with the industry area instead of dock area */ + const TileArea *area = st->industry != nullptr ? &st->industry->location : &st->ship_station; + + if (area->tile == INVALID_TILE) return; + + int x = TileX(area->tile); + int y = TileY(area->tile); + + /* Expand the area by a tile on each side while + * making sure that we remain inside the map. */ + int x2 = min(x + area->w + 1, MapSizeX()); + int x1 = max(x - 1, 0); + + int y2 = min(y + area->h + 1, MapSizeY()); + int y1 = max(y - 1, 0); + + TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1)); + TILE_AREA_LOOP(tile, ta) { + if (IsValidTile(tile) && IsPossibleDockingTile(tile)) CheckForDockingTile(tile); + } +} + void BuildOilRig(TileIndex tile) { if (!Station::CanAllocateItem()) { @@ -3926,26 +4136,32 @@ void BuildOilRig(TileIndex tile) } Station *st = new Station(tile); + _station_kdtree.Insert(st->index); st->town = ClosestTownFromTile(tile, UINT_MAX); st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG); assert(IsTileType(tile, MP_INDUSTRY)); + /* Mark industry as associated both ways */ + st->industry = Industry::GetByTile(tile); + st->industry->neutral_station = st; DeleteAnimatedTile(tile); MakeOilrig(tile, st->index, GetWaterClass(tile)); st->owner = OWNER_NONE; st->airport.type = AT_OILRIG; st->airport.Add(tile); - st->dock_tile = tile; + st->ship_station.Add(tile); st->facilities = FACIL_AIRPORT | FACIL_DOCK; st->build_date = _date; + UpdateStationDockingTiles(st); st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE); st->UpdateVirtCoord(); + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeStation(st->index)); + st->RecomputeCatchment(); UpdateStationAcceptance(st, false); - st->RecomputeIndustriesNear(); } void DeleteOilRig(TileIndex tile) @@ -3954,30 +4170,24 @@ void DeleteOilRig(TileIndex tile) MakeWaterKeepingClass(tile, OWNER_NONE); - st->dock_tile = INVALID_TILE; - st->airport.Clear(); - st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK); - st->airport.flags = 0; - - st->rect.AfterRemoveTile(st, tile); - - st->UpdateVirtCoord(); - st->RecomputeIndustriesNear(); - if (!st->IsInUse()) delete st; + /* The oil rig station is not supposed to be shared with anything else */ + assert(st->facilities == (FACIL_AIRPORT | FACIL_DOCK) && st->airport.type == AT_OILRIG); + delete st; } static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner) { if (IsRoadStopTile(tile)) { - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* Update all roadtypes, no matter if they are present */ - if (GetRoadOwner(tile, rt) == old_owner) { - if (HasTileRoadType(tile, rt)) { + if (GetRoadOwner(tile, rtt) == old_owner) { + RoadType rt = GetRoadType(tile, rtt); + if (rt != INVALID_ROADTYPE) { /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ Company::Get(old_owner)->infrastructure.road[rt] -= 2; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2; } - SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } } @@ -4058,17 +4268,16 @@ static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags) /* Yeah... water can always remove stops, right? */ if (_current_company == OWNER_WATER) return true; - RoadTypes rts = GetRoadTypes(tile); - if (HasBit(rts, ROADTYPE_TRAM)) { - Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + if (GetRoadTypeTram(tile) != INVALID_ROADTYPE) { + Owner tram_owner = GetRoadOwner(tile, RTT_TRAM); if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false; } - if (HasBit(rts, ROADTYPE_ROAD)) { - Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); + if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) { + Owner road_owner = GetRoadOwner(tile, RTT_ROAD); if (road_owner != OWNER_TOWN) { if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false; } else { - if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, ROADTYPE_ROAD, flags).Failed()) return false; + if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, RTT_ROAD), OWNER_TOWN, RTT_ROAD, flags).Failed()) return false; } } @@ -4089,8 +4298,8 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags) case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD); case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST); - case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); - case STATION_BUS: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); + case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); + case STATION_BUS: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY); case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST); case STATION_OILRIG: @@ -4546,14 +4755,14 @@ extern const TileTypeProcs _tile_type_station_procs = { DrawTile_Station, // draw_tile_proc GetSlopePixelZ_Station, // get_slope_z_proc ClearTile_Station, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_Station, // get_tile_desc_proc GetTileTrackStatus_Station, // get_tile_track_status_proc ClickTile_Station, // click_tile_proc AnimateTile_Station, // animate_tile_proc TileLoop_Station, // tile_loop_proc ChangeTileOwner_Station, // change_tile_owner_proc - NULL, // add_produced_cargo_proc + nullptr, // add_produced_cargo_proc VehicleEnter_Station, // vehicle_enter_tile_proc GetFoundation_Station, // get_foundation_proc TerraformTile_Station, // terraform_tile_proc diff --git a/src/station_func.h b/src/station_func.h index 9748297f21..86aae1e56e 100644 --- a/src/station_func.h +++ b/src/station_func.h @@ -18,17 +18,19 @@ #include "vehicle_type.h" #include "economy_func.h" #include "rail.h" +#include "road.h" #include "linkgraph/linkgraph_type.h" +#include "industry_type.h" void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius); -void FindStationsAroundTiles(const TileArea &location, StationList *stations); +void FindStationsAroundTiles(const TileArea &location, StationList *stations, bool use_nearby = true); void ShowStationViewWindow(StationID station); void UpdateAllStationVirtCoords(); CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad); -CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted = NULL); +CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, CargoTypes *always_accepted = nullptr); void UpdateStationAcceptance(Station *st, bool show_msg); @@ -38,6 +40,10 @@ void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, Ro bool HasStationInUse(StationID station, bool include_company, CompanyID company); void DeleteOilRig(TileIndex t); +void UpdateStationDockingTiles(Station *st); +void RemoveDockingTile(TileIndex t); +void ClearDockingTilesCheckingNeighbours(TileIndex tile); +bool IsValidDockingDirectionForDock(TileIndex t, DiagDirection d); /* Check if a rail station tile is traversable. */ bool IsStationTileBlocked(TileIndex tile); diff --git a/src/station_gui.cpp b/src/station_gui.cpp index c149edd114..4101f822a4 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -80,6 +80,46 @@ int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageTyp return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO); } +/** + * Find stations adjacent to the current tile highlight area, so that existing coverage + * area can be drawn. + */ +static void FindStationsAroundSelection() +{ + /* With distant join we don't know which station will be selected, so don't show any */ + if (_ctrl_pressed) { + SetViewportCatchmentStation(nullptr, true); + return; + } + + /* Tile area for TileHighlightData */ + TileArea location(TileVirtXY(_thd.pos.x, _thd.pos.y), _thd.size.x / TILE_SIZE - 1, _thd.size.y / TILE_SIZE - 1); + + /* Extended area by one tile */ + uint x = TileX(location.tile); + uint y = TileY(location.tile); + + int max_c = 1; + TileArea ta(TileXY(max(0, x - max_c), max(0, y - max_c)), TileXY(min(MapMaxX(), x + location.w + max_c), min(MapMaxY(), y + location.h + max_c))); + + Station *adjacent = nullptr; + + /* Direct loop instead of FindStationsAroundTiles as we are not interested in catchment area */ + TILE_AREA_LOOP(tile, ta) { + if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) { + Station *st = Station::GetByTile(tile); + if (st == nullptr) continue; + if (adjacent != nullptr && st != adjacent) { + /* Multiple nearby, distant join is required. */ + adjacent = nullptr; + break; + } + adjacent = st; + } + } + SetViewportCatchmentStation(adjacent, true); +} + /** * Check whether we need to redraw the station coverage text. * If it is needed actually make the window for redrawing. @@ -87,9 +127,20 @@ int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageTyp */ void CheckRedrawStationCoverage(const Window *w) { + /* Test if ctrl state changed */ + static bool _last_ctrl_pressed; + if (_ctrl_pressed != _last_ctrl_pressed) { + _thd.dirty = 0xff; + _last_ctrl_pressed = _ctrl_pressed; + } + if (_thd.dirty & 1) { _thd.dirty &= ~1; w->SetDirty(); + + if (_settings_client.gui.station_show_coverage && _thd.drawstyle == HT_RECT) { + FindStationsAroundSelection(); + } } } @@ -178,7 +229,7 @@ protected: DEBUG(misc, 3, "Building station list for company %d", owner); - this->stations.Clear(); + this->stations.clear(); const Station *st; FOR_ALL_STATIONS(st) { @@ -189,105 +240,105 @@ protected: if (st->goods[j].HasRating()) { num_waiting_cargo++; // count number of waiting cargo if (HasBit(this->cargo_filter, j)) { - *this->stations.Append() = st; + this->stations.push_back(st); break; } } } /* stations without waiting cargo */ if (num_waiting_cargo == 0 && this->include_empty) { - *this->stations.Append() = st; + this->stations.push_back(st); } } } } - this->stations.Compact(); + this->stations.shrink_to_fit(); this->stations.RebuildDone(); - this->vscroll->SetCount(this->stations.Length()); // Update the scrollbar + this->vscroll->SetCount((uint)this->stations.size()); // Update the scrollbar } /** Sort stations by their name */ - static int CDECL StationNameSorter(const Station * const *a, const Station * const *b) + static bool StationNameSorter(const Station * const &a, const Station * const &b) { static char buf_cache[64]; char buf[64]; - SetDParam(0, (*a)->index); + SetDParam(0, a->index); GetString(buf, STR_STATION_NAME, lastof(buf)); - if (*b != last_station) { - last_station = *b; - SetDParam(0, (*b)->index); + if (b != last_station) { + last_station = b; + SetDParam(0, b->index); GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache)); } int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting). - if (r == 0) return (*a)->index - (*b)->index; - return r; + if (r == 0) return a->index < b->index; + return r < 0; } /** Sort stations by their type */ - static int CDECL StationTypeSorter(const Station * const *a, const Station * const *b) + static bool StationTypeSorter(const Station * const &a, const Station * const &b) { - return (*a)->facilities - (*b)->facilities; + return a->facilities < b->facilities; } /** Sort stations by their waiting cargo */ - static int CDECL StationWaitingTotalSorter(const Station * const *a, const Station * const *b) + static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b) { int diff = 0; CargoID j; FOR_EACH_SET_CARGO_ID(j, cargo_filter) { - diff += (*a)->goods[j].cargo.TotalCount() - (*b)->goods[j].cargo.TotalCount(); + diff += a->goods[j].cargo.TotalCount() - b->goods[j].cargo.TotalCount(); } - return diff; + return diff < 0; } /** Sort stations by their available waiting cargo */ - static int CDECL StationWaitingAvailableSorter(const Station * const *a, const Station * const *b) + static bool StationWaitingAvailableSorter(const Station * const &a, const Station * const &b) { int diff = 0; CargoID j; FOR_EACH_SET_CARGO_ID(j, cargo_filter) { - diff += (*a)->goods[j].cargo.AvailableCount() - (*b)->goods[j].cargo.AvailableCount(); + diff += a->goods[j].cargo.AvailableCount() - b->goods[j].cargo.AvailableCount(); } - return diff; + return diff < 0; } /** Sort stations by their rating */ - static int CDECL StationRatingMaxSorter(const Station * const *a, const Station * const *b) + static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b) { byte maxr1 = 0; byte maxr2 = 0; CargoID j; FOR_EACH_SET_CARGO_ID(j, cargo_filter) { - if ((*a)->goods[j].HasRating()) maxr1 = max(maxr1, (*a)->goods[j].rating); - if ((*b)->goods[j].HasRating()) maxr2 = max(maxr2, (*b)->goods[j].rating); + if (a->goods[j].HasRating()) maxr1 = max(maxr1, a->goods[j].rating); + if (b->goods[j].HasRating()) maxr2 = max(maxr2, b->goods[j].rating); } - return maxr1 - maxr2; + return maxr1 < maxr2; } /** Sort stations by their rating */ - static int CDECL StationRatingMinSorter(const Station * const *a, const Station * const *b) + static bool StationRatingMinSorter(const Station * const &a, const Station * const &b) { byte minr1 = 255; byte minr2 = 255; for (CargoID j = 0; j < NUM_CARGO; j++) { if (!HasBit(cargo_filter, j)) continue; - if ((*a)->goods[j].HasRating()) minr1 = min(minr1, (*a)->goods[j].rating); - if ((*b)->goods[j].HasRating()) minr2 = min(minr2, (*b)->goods[j].rating); + if (a->goods[j].HasRating()) minr1 = min(minr1, a->goods[j].rating); + if (b->goods[j].HasRating()) minr2 = min(minr2, b->goods[j].rating); } - return -(minr1 - minr2); + return minr1 > minr2; } /** Sort the stations list */ @@ -296,7 +347,7 @@ protected: if (!this->stations.Sort()) return; /* Reset name sorter sort cache */ - this->last_station = NULL; + this->last_station = nullptr; /* Set the modified widget dirty */ this->SetWidgetDirty(WID_STL_LIST); @@ -337,7 +388,7 @@ public: this->last_sorting = this->stations.GetListing(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_STL_SORTBY: { @@ -393,7 +444,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { this->BuildStationsList((Owner)this->window_number); this->SortStationsList(); @@ -401,7 +452,7 @@ public: this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_STL_SORTBY: @@ -411,7 +462,7 @@ public: case WID_STL_LIST: { bool rtl = _current_text_dir == TD_RTL; - int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); + int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->stations.size()); int y = r.top + WD_FRAMERECT_TOP; for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner const Station *st = this->stations[i]; @@ -485,7 +536,7 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_STL_CAPTION) { SetDParam(0, this->window_number); @@ -493,12 +544,12 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_STL_LIST: { uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL); - if (id_v >= this->stations.Length()) return; // click out of list bound + if (id_v >= this->stations.size()) return; // click out of list bound const Station *st = this->stations[id_v]; /* do not check HasStationInUse - it is slow and may be invalid */ @@ -609,7 +660,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (this->stations.SortType() != index) { this->stations.SetSortType(index); @@ -621,7 +672,7 @@ public: } } - virtual void OnGameTick() + void OnGameTick() override { if (this->stations.NeedResort()) { DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number); @@ -629,7 +680,7 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_STL_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } @@ -639,7 +690,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ @@ -655,7 +706,7 @@ byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_ bool CompanyStationsWindow::include_empty = true; const CargoTypes CompanyStationsWindow::cargo_filter_max = ALL_CARGOTYPES; CargoTypes CompanyStationsWindow::cargo_filter = ALL_CARGOTYPES; -const Station *CompanyStationsWindow::last_station = NULL; +const Station *CompanyStationsWindow::last_station = nullptr; /* Available station sorting functions */ GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = { @@ -785,6 +836,7 @@ static const NWidgetPart _nested_station_view_widgets[] = { EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CATCHMENT), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP), @@ -903,9 +955,9 @@ public: } /** - * Retrieve a child for the given station. Return NULL if it doesn't exist. + * Retrieve a child for the given station. Return nullptr if it doesn't exist. * @param station ID of the station the child we're looking for is associated with. - * @return a child entry for the given station or NULL. + * @return a child entry for the given station or nullptr. */ CargoDataEntry *Retrieve(StationID station) const { @@ -914,9 +966,9 @@ public: } /** - * Retrieve a child for the given cargo. Return NULL if it doesn't exist. + * Retrieve a child for the given cargo. Return nullptr if it doesn't exist. * @param cargo ID of the cargo the child we're looking for is associated with. - * @return a child entry for the given cargo or NULL. + * @return a child entry for the given cargo or nullptr. */ CargoDataEntry *Retrieve(CargoID cargo) const { @@ -1001,7 +1053,7 @@ private: }; CargoDataEntry::CargoDataEntry() : - parent(NULL), + parent(nullptr), station(INVALID_STATION), num_children(0), count(0), @@ -1025,19 +1077,19 @@ CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *pa {} CargoDataEntry::CargoDataEntry(StationID station) : - parent(NULL), + parent(nullptr), station(station), num_children(0), count(0), - children(NULL) + children(nullptr) {} CargoDataEntry::CargoDataEntry(CargoID cargo) : - parent(NULL), + parent(nullptr), cargo(cargo), num_children(0), count(0), - children(NULL) + children(nullptr) {} CargoDataEntry::~CargoDataEntry() @@ -1051,14 +1103,14 @@ CargoDataEntry::~CargoDataEntry() */ void CargoDataEntry::Clear() { - if (this->children != NULL) { + if (this->children != nullptr) { for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) { assert(*i != this); delete *i; } this->children->clear(); } - if (this->parent != NULL) this->parent->count -= this->count; + if (this->parent != nullptr) this->parent->count -= this->count; this->count = 0; this->num_children = 0; } @@ -1107,7 +1159,7 @@ CargoDataEntry *CargoDataEntry::InsertOrRetrieve(Tid child_id) void CargoDataEntry::Update(uint count) { this->count += count; - if (this->parent != NULL) this->parent->Update(count); + if (this->parent != nullptr) this->parent->Update(count); } /** @@ -1116,7 +1168,7 @@ void CargoDataEntry::Update(uint count) void CargoDataEntry::IncrementSize() { ++this->num_children; - if (this->parent != NULL) this->parent->IncrementSize(); + if (this->parent != nullptr) this->parent->IncrementSize(); } void CargoDataEntry::Resort(CargoSortType type, SortOrder order) @@ -1129,7 +1181,7 @@ void CargoDataEntry::Resort(CargoSortType type, SortOrder order) CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const { if (i == this->children->end()) { - return NULL; + return nullptr; } else { assert(this->children->value_comp().GetSortType() != ST_COUNT); return *i; @@ -1314,6 +1366,8 @@ struct StationViewWindow : public Window { DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false); DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false); DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false); + + SetViewportCatchmentStation(Station::Get(this->window_number), false); } /** @@ -1331,7 +1385,7 @@ struct StationViewWindow : public Window { if (count == 0) return; bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; const CargoDataEntry *expand = &this->expanded_rows; - for (int i = 0; i < NUM_COLUMNS && expand != NULL; ++i) { + for (int i = 0; i < NUM_COLUMNS && expand != nullptr; ++i) { switch (groupings[i]) { case GR_CARGO: assert(i == 0); @@ -1362,7 +1416,7 @@ struct StationViewWindow : public Window { data->Update(count); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_SV_WAITING: @@ -1386,7 +1440,7 @@ struct StationViewWindow : public Window { } } - virtual void OnPaint() + void OnPaint() override { const Station *st = Station::Get(this->window_number); CargoDataEntry cargo; @@ -1403,6 +1457,10 @@ struct StationViewWindow : public Window { this->SetWidgetDisabledState(WID_SV_CLOSE_AIRPORT, !(st->facilities & FACIL_AIRPORT) || st->owner != _local_company || st->owner == OWNER_NONE); // Also consider SE, where _local_company == OWNER_NONE this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0); + extern const Station *_viewport_highlight_station; + this->SetWidgetDisabledState(WID_SV_CATCHMENT, st->facilities == FACIL_NONE); + this->SetWidgetLoweredState(WID_SV_CATCHMENT, _viewport_highlight_station == st); + this->DrawWidgets(); if (!this->IsShaded()) { @@ -1442,7 +1500,7 @@ struct StationViewWindow : public Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { const Station *st = Station::Get(this->window_number); SetDParam(0, st->index); @@ -1572,13 +1630,13 @@ struct StationViewWindow : public Window { StationID next = it.GetKey(); const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation()); - if (source_entry == NULL) { + if (source_entry == nullptr) { this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); continue; } const CargoDataEntry *via_entry = source_entry->Retrieve(next); - if (via_entry == NULL) { + if (via_entry == nullptr) { this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); continue; } @@ -1601,7 +1659,7 @@ struct StationViewWindow : public Window { { for (CargoID i = 0; i < NUM_CARGO; i++) { - if (this->cached_destinations.Retrieve(i) == NULL) { + if (this->cached_destinations.Retrieve(i) == nullptr) { this->RecalcDestinations(i); } @@ -1621,13 +1679,13 @@ struct StationViewWindow : public Window { { std::list stations; const CargoDataEntry *parent = data->GetParent(); - if (parent->GetParent() == NULL) { + if (parent->GetParent() == nullptr) { this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo())); return; } StationID next = data->GetStation(); - while (parent->GetParent()->GetParent() != NULL) { + while (parent->GetParent()->GetParent() != nullptr) { stations.push_back(parent->GetStation()); parent = parent->GetParent(); } @@ -1765,7 +1823,7 @@ struct StationViewWindow : public Window { DrawString(text_left, text_right, y, str); if (column < NUM_COLUMNS - 1) { - const char *sym = NULL; + const char *sym = nullptr; if (cd->GetNumChildren() > 0) { sym = "-"; } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) { @@ -1834,7 +1892,7 @@ struct StationViewWindow : public Window { const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph); SetDParam(0, cs->name); - SetDParam(1, lg != NULL ? lg->Monthly((*lg)[ge->node].Supply()) : 0); + SetDParam(1, lg != nullptr ? lg->Monthly((*lg)[ge->node].Supply()) : 0); SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5)); SetDParam(3, ToPercent8(ge->rating)); DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING); @@ -1851,7 +1909,7 @@ struct StationViewWindow : public Window { template void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next) { - if (filter->Retrieve(next) != NULL) { + if (filter->Retrieve(next) != nullptr) { filter->Remove(next); } else { filter->InsertOrRetrieve(next); @@ -1878,13 +1936,17 @@ struct StationViewWindow : public Window { this->SetWidgetDirty(WID_SV_WAITING); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SV_WAITING: this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition()); break; + case WID_SV_CATCHMENT: + SetViewportCatchmentStation(Station::Get(this->window_number), !this->IsWidgetLowered(WID_SV_CATCHMENT)); + break; + case WID_SV_LOCATION: if (_ctrl_pressed) { ShowExtraViewPortWindow(Station::Get(this->window_number)->xy); @@ -2039,7 +2101,7 @@ struct StationViewWindow : public Window { this->SetDirty(); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (widget == WID_SV_SORT_BY) { this->SelectSortBy(index); @@ -2048,14 +2110,14 @@ struct StationViewWindow : public Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; - DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), NULL, str); + DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), nullptr, str); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } @@ -2087,7 +2149,7 @@ struct StationViewWindow : public Window { * @param data Information about the changed data. If it's a valid cargo ID, invalidate the cargo 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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (gui_scope) { if (data >= 0 && data < NUM_CARGO) { @@ -2140,8 +2202,8 @@ struct TileAndStation { StationID station; ///< StationID }; -static SmallVector _deleted_stations_nearby; -static SmallVector _stations_nearby_list; +static std::vector _deleted_stations_nearby; +static std::vector _stations_nearby_list; /** * Add station on this tile to _stations_nearby_list if it's fully within the @@ -2156,11 +2218,11 @@ static bool AddNearbyStation(TileIndex tile, void *user_data) TileArea *ctx = (TileArea *)user_data; /* First check if there were deleted stations here */ - for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) { - TileAndStation *ts = _deleted_stations_nearby.Get(i); + for (uint i = 0; i < _deleted_stations_nearby.size(); i++) { + auto ts = _deleted_stations_nearby.begin() + i; if (ts->tile == tile) { - *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station; - _deleted_stations_nearby.Erase(ts); + _stations_nearby_list.push_back(_deleted_stations_nearby[i].station); + _deleted_stations_nearby.erase(ts); i--; } } @@ -2174,10 +2236,10 @@ static bool AddNearbyStation(TileIndex tile, void *user_data) if (!T::IsValidID(sid)) return false; T *st = T::Get(sid); - if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false; + if (st->owner != _local_company || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false; if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) { - *_stations_nearby_list.Append() = sid; + _stations_nearby_list.push_back(sid); } return false; // We want to include *all* nearby stations @@ -2197,8 +2259,8 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) { TileArea ctx = ta; - _stations_nearby_list.Clear(); - _deleted_stations_nearby.Clear(); + _stations_nearby_list.clear(); + _deleted_stations_nearby.clear(); /* Check the inside, to return, if we sit on another station */ TILE_AREA_LOOP(t, ta) { @@ -2211,9 +2273,7 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { /* Include only within station spread (yes, it is strictly less than) */ if (max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { - TileAndStation *ts = _deleted_stations_nearby.Append(); - ts->tile = st->xy; - ts->station = st->index; + _deleted_stations_nearby.push_back({st->xy, st->index}); /* Add the station when it's within where we're going to build */ if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) && @@ -2227,13 +2287,13 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) /* Only search tiles where we have a chance to stay within the station spread. * The complete check needs to be done in the callback as we don't know the * extent of the found station, yet. */ - if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL; + if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return nullptr; uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1; TileIndex tile = TileAddByDir(ctx.tile, DIR_N); CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); - return NULL; + return nullptr; } static const NWidgetPart _nested_select_station_widgets[] = { @@ -2272,15 +2332,24 @@ struct SelectStationWindow : WindowPopup { this->GetWidget(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION; this->FinishInitNested(0); this->OnInvalidateData(0); + + _thd.freeze = true; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + ~SelectStationWindow() + { + if (_settings_client.gui.station_show_coverage) SetViewportCatchmentStation(nullptr, true); + + _thd.freeze = false; + } + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_JS_PANEL) return; /* Determine the widest string */ Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); - for (uint i = 0; i < _stations_nearby_list.Length(); i++) { + for (uint i = 0; i < _stations_nearby_list.size(); i++) { const T *st = T::Get(_stations_nearby_list[i]); SetDParam(0, st->index); SetDParam(1, st->facilities); @@ -2294,7 +2363,7 @@ struct SelectStationWindow : WindowPopup { *size = d; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_JS_PANEL) return; @@ -2304,7 +2373,7 @@ struct SelectStationWindow : WindowPopup { y += this->resize.step_height; } - for (uint i = max(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.Length(); ++i, y += this->resize.step_height) { + for (uint i = max(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.size(); ++i, y += this->resize.step_height) { /* Don't draw anything if it extends past the end of the window. */ if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break; @@ -2315,7 +2384,7 @@ struct SelectStationWindow : WindowPopup { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget != WID_JS_PANEL) return; @@ -2323,7 +2392,7 @@ struct SelectStationWindow : WindowPopup { bool distant_join = (st_index > 0); if (distant_join) st_index--; - if (distant_join && st_index >= _stations_nearby_list.Length()) return; + if (distant_join && st_index >= _stations_nearby_list.size()) return; /* Insert station to be joined into stored command */ SB(this->select_station_cmd.p2, 16, 16, @@ -2336,7 +2405,7 @@ struct SelectStationWindow : WindowPopup { DeleteWindowById(WC_SELECT_STATION, 0); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (_thd.dirty & 2) { _thd.dirty &= ~2; @@ -2344,7 +2413,7 @@ struct SelectStationWindow : WindowPopup { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } @@ -2354,13 +2423,30 @@ struct SelectStationWindow : WindowPopup { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; FindStationsNearby(this->area, true); - this->vscroll->SetCount(_stations_nearby_list.Length() + 1); + this->vscroll->SetCount((uint)_stations_nearby_list.size() + 1); this->SetDirty(); } + + void OnMouseOver(Point pt, int widget) override + { + if (widget != WID_JS_PANEL || T::EXPECTED_FACIL == FACIL_WAYPOINT) { + SetViewportCatchmentStation(nullptr, true); + return; + } + + /* Show coverage area of station under cursor */ + uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP); + if (st_index == 0 || st_index > _stations_nearby_list.size()) { + SetViewportCatchmentStation(nullptr, true); + } else { + st_index--; + SetViewportCatchmentStation(Station::Get(_stations_nearby_list[st_index]), true); + } + } }; static WindowDesc _select_station_desc( @@ -2387,7 +2473,7 @@ static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta) /* If a window is already opened and we didn't ctrl-click, * return true (i.e. just flash the old window) */ Window *selection_window = FindWindowById(WC_SELECT_STATION, 0); - if (selection_window != NULL) { + if (selection_window != nullptr) { /* Abort current distant-join and start new one */ delete selection_window; UpdateTileSelection(); @@ -2403,7 +2489,7 @@ static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta) * If adjacent-stations is disabled and we are building next to a station, do not show the selection window. * but join the other station immediately. */ const T *st = FindStationsNearby(ta, false); - return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0); + return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0); } /** diff --git a/src/station_kdtree.h b/src/station_kdtree.h new file mode 100644 index 0000000000..321bbacc6f --- /dev/null +++ b/src/station_kdtree.h @@ -0,0 +1,42 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 station_kdtree.h Declarations for accessing the k-d tree of stations */ + +#ifndef STATION_KDTREE_H +#define STATION_KDTREE_H + +#include "core/kdtree.hpp" +#include "core/math_func.hpp" +#include "station_base.h" +#include "map_func.h" + +inline uint16 Kdtree_StationXYFunc(StationID stid, int dim) { return (dim == 0) ? TileX(BaseStation::Get(stid)->xy) : TileY(BaseStation::Get(stid)->xy); } +typedef Kdtree StationKdtree; +extern StationKdtree _station_kdtree; + +/** + * Call a function on all stations whose sign is within a radius of a center tile. + * @param center Central tile to search around. + * @param radius Distance in both X and Y to search within. + * @param func The function to call, must take a single parameter which is Station*. + */ +template +void ForAllStationsRadius(TileIndex center, uint radius, Func func) +{ + uint16 x1, y1, x2, y2; + x1 = (uint16)max(0, TileX(center) - radius); + x2 = (uint16)min(TileX(center) + radius + 1, MapSizeX()); + y1 = (uint16)max(0, TileY(center) - radius); + y2 = (uint16)min(TileY(center) + radius + 1, MapSizeY()); + + _station_kdtree.FindContained(x1, y1, x2, y2, [&](StationID id) { + func(Station::Get(id)); + }); +} + +#endif diff --git a/src/station_map.h b/src/station_map.h index e591787e3b..98f8f288bc 100644 --- a/src/station_map.h +++ b/src/station_map.h @@ -17,6 +17,7 @@ #include "water_map.h" #include "station_func.h" #include "rail.h" +#include "road.h" typedef byte StationGfx; ///< Index of station graphics. @see _station_display_datas @@ -535,6 +536,7 @@ static inline void MakeStation(TileIndex t, Owner o, StationID sid, StationType SetTileType(t, MP_STATION); SetTileOwner(t, o); SetWaterClass(t, wc); + SetDockingTile(t, false); _m[t].m2 = sid; _m[t].m3 = 0; _m[t].m4 = 0; @@ -583,15 +585,16 @@ static inline void MakeRailWaypoint(TileIndex t, Owner o, StationID sid, Axis a, * @param o the owner of the roadstop * @param sid the station to which this tile belongs * @param rst the type of roadstop to make this tile - * @param rt the roadtypes on this tile + * @param road_rt the road roadtype on this tile + * @param tram_rt the tram roadtype on this tile * @param d the direction of the roadstop */ -static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopType rst, RoadTypes rt, DiagDirection d) +static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, DiagDirection d) { MakeStation(t, o, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), d); - SetRoadTypes(t, rt); - SetRoadOwner(t, ROADTYPE_ROAD, o); - SetRoadOwner(t, ROADTYPE_TRAM, o); + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_ROAD, o); + SetRoadOwner(t, RTT_TRAM, o); } /** @@ -602,15 +605,16 @@ static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopTyp * @param tram the owner of the tram * @param sid the station to which this tile belongs * @param rst the type of roadstop to make this tile - * @param rt the roadtypes on this tile + * @param road_rt the road roadtype on this tile + * @param tram_rt the tram roadtype on this tile * @param a the direction of the roadstop */ -static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadTypes rt, Axis a) +static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, Axis a) { MakeStation(t, station, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + a); - SetRoadTypes(t, rt); - SetRoadOwner(t, ROADTYPE_ROAD, road); - SetRoadOwner(t, ROADTYPE_TRAM, tram); + SetRoadTypes(t, road_rt, tram_rt); + SetRoadOwner(t, RTT_ROAD, road); + SetRoadOwner(t, RTT_TRAM, tram); } /** diff --git a/src/station_type.h b/src/station_type.h index 495e95a082..9afbc22056 100644 --- a/src/station_type.h +++ b/src/station_type.h @@ -12,9 +12,9 @@ #ifndef STATION_TYPE_H #define STATION_TYPE_H -#include "core/smallvec_type.hpp" #include "core/smallstack_type.hpp" #include "tilearea_type.h" +#include typedef uint16 StationID; typedef uint16 RoadStopID; @@ -49,7 +49,7 @@ enum RoadStopType { }; /** The facilities a station might be having */ -enum StationFacility { +enum StationFacility : byte { FACIL_NONE = 0, ///< The station has no facilities at all FACIL_TRAIN = 1 << 0, ///< Station with train station FACIL_TRUCK_STOP = 1 << 1, ///< Station with truck stops @@ -59,10 +59,9 @@ enum StationFacility { FACIL_WAYPOINT = 1 << 7, ///< Station is a waypoint }; DECLARE_ENUM_AS_BIT_SET(StationFacility) -typedef SimpleTinyEnumT StationFacilityByte; /** The vehicles that may have visited a station */ -enum StationHadVehicleOfType { +enum StationHadVehicleOfType : byte { HVOT_NONE = 0, ///< Station has seen no vehicles HVOT_TRAIN = 1 << 1, ///< Station has seen a train HVOT_BUS = 1 << 2, ///< Station has seen a bus @@ -73,7 +72,6 @@ enum StationHadVehicleOfType { HVOT_WAYPOINT = 1 << 6, ///< Station is a waypoint (NewGRF only!) }; DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType) -typedef SimpleTinyEnumT StationHadVehicleOfTypeByte; /** The different catchment areas used */ enum CatchmentArea { @@ -90,8 +88,12 @@ enum CatchmentArea { static const uint MAX_LENGTH_STATION_NAME_CHARS = 32; ///< The maximum length of a station name in characters including '\0' +struct StationCompare { + bool operator() (const Station *lhs, const Station *rhs) const; +}; + /** List of stations */ -typedef SmallVector StationList; +typedef std::set StationList; /** * Structure contains cached list of stations nearby. The list diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index 557551f3f0..82939e8961 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -100,18 +100,18 @@ struct StatusBarWindow : Window { PositionStatusbar(this); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt = { 0, _screen.height - sm_height }; return pt; } - virtual void FindWindowPlacementAndResize(int def_width, int def_height) + void FindWindowPlacementAndResize(int def_width, int def_height) override { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { Dimension d; switch (widget) { @@ -138,7 +138,7 @@ struct StatusBarWindow : Window { *size = maxdim(d, *size); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_S_LEFT: @@ -150,7 +150,7 @@ struct StatusBarWindow : Window { case WID_S_RIGHT: { /* Draw company money, if any */ const Company *c = Company::GetIfValid(_local_company); - if (c != NULL) { + if (c != nullptr) { SetDParam(0, c->money); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_COMPANY_MONEY, TC_FROMSTRING, SA_HOR_CENTER); } @@ -165,7 +165,7 @@ struct StatusBarWindow : Window { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_AUTOSAVE, TC_FROMSTRING, SA_HOR_CENTER); } else if (_pause_mode != PM_UNPAUSED) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_PAUSED, TC_FROMSTRING, SA_HOR_CENTER); - } else if (this->ticker_scroll < TICKER_STOP && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item != NULL && _statusbar_news_item->string_id != 0) { + } else if (this->ticker_scroll < TICKER_STOP && _statusbar_news_item != nullptr && _statusbar_news_item->string_id != 0) { /* Draw the scrolling news text */ if (!DrawScrollingStatusText(_statusbar_news_item, ScaleGUITrad(this->ticker_scroll), r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom)) { InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); @@ -196,7 +196,7 @@ struct StatusBarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; switch (data) { @@ -212,7 +212,7 @@ struct StatusBarWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_S_MIDDLE: ShowLastNewsMessage(); break; @@ -221,7 +221,7 @@ struct StatusBarWindow : Window { } } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (_pause_mode != PM_UNPAUSED) return; @@ -249,7 +249,7 @@ static const NWidgetPart _nested_main_status_widgets[] = { }; static WindowDesc _main_status_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_STATUS_BAR, WC_NONE, WDF_NO_FOCUS, _nested_main_status_widgets, lengthof(_nested_main_status_widgets) @@ -261,7 +261,7 @@ static WindowDesc _main_status_desc( bool IsNewsTickerShown() { const StatusBarWindow *w = dynamic_cast(FindWindowById(WC_STATUS_BAR, 0)); - return w != NULL && w->ticker_scroll < StatusBarWindow::TICKER_STOP; + return w != nullptr && w->ticker_scroll < StatusBarWindow::TICKER_STOP; } /** diff --git a/src/stdafx.h b/src/stdafx.h index cb92d97faa..7f7f9cc6e7 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -16,22 +16,22 @@ #include "os/macosx/osx_stdafx.h" #endif /* __APPLE__ */ -#if defined(__BEOS__) || defined(__HAIKU__) +#if defined(__HAIKU__) #include #include #define _GNU_SOURCE #define TROUBLED_INTS - #include -#elif defined(__NDS__) - #include - #define TROUBLED_INTS +#endif + +#if defined(__HAIKU__) || defined(__CYGWIN__) +# include /* strncasecmp */ #endif /* It seems that we need to include stdint.h before anything else * We need INT64_MAX, which for most systems comes from stdint.h. However, MSVC - * does not have stdint.h and apparently neither does MorphOS. + * does not have stdint.h. * For OSX the inclusion is already done in osx_stdafx.h. */ -#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER >= 1600) && !defined(__MORPHOS__) +#if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER >= 1600) #if defined(SUNOS) /* SunOS/Solaris does not have stdint.h, but inttypes.h defines everything * stdint.h defines and we need. */ @@ -86,6 +86,7 @@ #include #include #include +#include #ifndef SIZE_MAX #define SIZE_MAX ((size_t)-1) @@ -100,34 +101,10 @@ #define strcasecmp stricmp #endif -#if defined(SUNOS) || defined(HPUX) +#if defined(SUNOS) || defined(HPUX) || defined(__CYGWIN__) #include #endif -#if defined(__MORPHOS__) - /* MorphOS defines certain Amiga defines per default, we undefine them - * here to make the rest of source less messy and more clear what is - * required for morphos and what for AmigaOS */ - #if defined(amigaos) - #undef amigaos - #endif - #if defined(__amigaos__) - #undef __amigaos__ - # endif - #if defined(__AMIGA__) - #undef __AMIGA__ - #endif - #if defined(AMIGA) - #undef AMIGA - #endif - #if defined(amiga) - #undef amiga - #endif - /* Act like we already included this file, as it somehow gives linkage problems - * (mismatch linkage of C++ and C between this include and unistd.h). */ - #define CLIB_USERGROUP_PROTOS_H -#endif /* __MORPHOS__ */ - /* Stuff for GCC */ #if defined(__GNUC__) #define NORETURN __attribute__ ((noreturn)) @@ -163,7 +140,7 @@ #include #endif /* __WATCOMC__ */ -#if defined(__MINGW32__) || defined(__CYGWIN__) +#if defined(__MINGW32__) #include // alloca() #endif @@ -260,7 +237,7 @@ # endif /* liblzma from vcpkg (before 5.2.4-2) used to patch lzma.h to define LZMA_API_STATIC for static builds */ -# if defined(WITH_LZMA) +# if defined(WITH_LIBLZMA) # if !defined(LZMA_API_STATIC) # define LZMA_API_STATIC # endif @@ -276,15 +253,6 @@ #endif /* defined(_MSC_VER) */ -#if defined(DOS) - /* The DOS port does not have all signals/signal functions. */ - #define strsignal(sig) "" - /* Use 'no floating point' for bus errors; SIGBUS does not exist - * for DOS, SIGNOFP for other platforms. So it's fairly safe - * to interchange those. */ - #define SIGBUS SIGNOFP -#endif - /* NOTE: the string returned by these functions is only valid until the next * call to the same function and is not thread- or reentrancy-safe */ #if !defined(STRGEN) && !defined(SETTINGSGEN) @@ -340,17 +308,23 @@ typedef unsigned char byte; /* This is already defined in unix, but not in QNX Neutrino (6.x)*/ -#if (!defined(UNIX) && !defined(__CYGWIN__) && !defined(__BEOS__) && !defined(__HAIKU__) && !defined(__MORPHOS__)) || defined(__QNXNTO__) +#if (!defined(UNIX) && !defined(__HAIKU__)) || defined(__QNXNTO__) typedef unsigned int uint; #endif #if defined(TROUBLED_INTS) - /* NDS'/BeOS'/Haiku's types for uint32/int32 are based on longs, which causes - * trouble all over the place in OpenTTD. */ - #define uint32 uint32_ugly_hack - #define int32 int32_ugly_hack + /* Haiku's types for uint32/int32/uint64/int64 are different than what + * they are on other platforms; not in length, but how to print them. + * So make them more like the other platforms, to make printf() etc a + * little bit easier. */ +# define uint32 uint32_ugly_hack +# define int32 int32_ugly_hack +# define uint64 uint64_ugly_hack +# define int64 int64_ugly_hack typedef unsigned int uint32_ugly_hack; typedef signed int int32_ugly_hack; + typedef unsigned __int64 uint64_ugly_hack; + typedef signed __int64 int64_ugly_hack; #else typedef unsigned char uint8; typedef signed char int8; @@ -466,10 +440,7 @@ void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); #define OTTD_ASSERT #endif -#if defined(MORPHOS) || defined(__NDS__) || defined(__DJGPP__) - /* MorphOS and NDS don't have C++ conformant _stricmp... */ - #define _stricmp stricmp -#elif defined(OPENBSD) +#if defined(OPENBSD) /* OpenBSD uses strcasecmp(3) */ #define _stricmp strcasecmp #endif diff --git a/src/story.cpp b/src/story.cpp index a6da0b7a3a..5227eaa1d5 100644 --- a/src/story.cpp +++ b/src/story.cpp @@ -45,7 +45,7 @@ INSTANTIATE_POOL_METHODS(StoryPage) * @param tile The tile parameter of the DoCommand proc * @param reference The reference parameter of the DoCommand proc (p2) * @param text The text parameter of the DoCommand proc - * @return true, if and only if the given parameters are valid for the given page elment type and page id. + * @return true, if and only if the given parameters are valid for the given page element type and page id. */ static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32 reference, const char *text) { @@ -124,7 +124,7 @@ CommandCost CmdCreateStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, u s->date = _date; s->company = company; if (StrEmpty(text)) { - s->title = NULL; + s->title = nullptr; } else { s->title = stredup(text); } @@ -241,7 +241,7 @@ CommandCost CmdSetStoryPageTitle(TileIndex tile, DoCommandFlag flags, uint32 p1, StoryPage *p = StoryPage::Get(page_id); free(p->title); if (StrEmpty(text)) { - p->title = NULL; + p->title = nullptr; } else { p->title = stredup(text); } diff --git a/src/story_base.h b/src/story_base.h index 3db1ba4a86..4cc857b8d3 100644 --- a/src/story_base.h +++ b/src/story_base.h @@ -27,7 +27,7 @@ extern uint32 _story_page_next_sort_value; /* * Each story page element is one of these types. */ -enum StoryPageElementType { +enum StoryPageElementType : byte { SPET_TEXT = 0, ///< A text element. SPET_LOCATION, ///< An element that references a tile along with a one-line text. SPET_GOAL, ///< An element that references a goal. @@ -37,7 +37,6 @@ enum StoryPageElementType { /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT StoryPageElementTypeByte; ///< typedefing-enumification of Direction /** * Struct about story page elements. @@ -47,7 +46,7 @@ typedef TinyEnumT StoryPageElementTypeByte; ///< typedefin struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_pool> { uint32 sort_value; ///< A number that increases for every created story page element. Used for sorting. The id of a story page element is the pool index. StoryPageID page; ///< Id of the page which the page element belongs to - StoryPageElementTypeByte type; ///< Type of page element + StoryPageElementType type; ///< Type of page element uint32 referenced_id; ///< Id of referenced object (location, goal etc.) char *text; ///< Static content text of page element @@ -58,7 +57,7 @@ struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_po inline StoryPageElement() { } /** - * (Empty) destructor has to be defined else operator delete might be called with NULL parameter + * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter */ inline ~StoryPageElement() { free(this->text); } }; @@ -70,7 +69,7 @@ struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_po struct StoryPage : StoryPagePool::PoolItem<&_story_page_pool> { uint32 sort_value; ///< A number that increases for every created story page. Used for sorting. The id of a story page is the pool index. Date date; ///< Date when the page was created. - CompanyByte company; ///< StoryPage is for a specific company; INVALID_COMPANY if it is global + CompanyID company; ///< StoryPage is for a specific company; INVALID_COMPANY if it is global char *title; ///< Title of story page @@ -80,7 +79,7 @@ struct StoryPage : StoryPagePool::PoolItem<&_story_page_pool> { inline StoryPage() { } /** - * (Empty) destructor has to be defined else operator delete might be called with NULL parameter + * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter */ inline ~StoryPage() { diff --git a/src/story_gui.cpp b/src/story_gui.cpp index 003843310e..316e79ebb9 100644 --- a/src/story_gui.cpp +++ b/src/story_gui.cpp @@ -52,16 +52,16 @@ protected: void BuildStoryPageList() { if (this->story_pages.NeedRebuild()) { - this->story_pages.Clear(); + this->story_pages.clear(); const StoryPage *p; FOR_ALL_STORY_PAGES(p) { if (this->IsPageAvailable(p)) { - *this->story_pages.Append() = p; + this->story_pages.push_back(p); } } - this->story_pages.Compact(); + this->story_pages.shrink_to_fit(); this->story_pages.RebuildDone(); } @@ -69,28 +69,28 @@ protected: } /** Sort story pages by order value. */ - static int CDECL PageOrderSorter(const StoryPage * const *a, const StoryPage * const *b) + static bool PageOrderSorter(const StoryPage * const &a, const StoryPage * const &b) { - return (*a)->sort_value - (*b)->sort_value; + return a->sort_value < b->sort_value; } /** (Re)Build story page element list. */ void BuildStoryPageElementList() { if (this->story_page_elements.NeedRebuild()) { - this->story_page_elements.Clear(); + this->story_page_elements.clear(); const StoryPage *p = GetSelPage(); - if (p != NULL) { + if (p != nullptr) { const StoryPageElement *pe; FOR_ALL_STORY_PAGE_ELEMENTS(pe) { if (pe->page == p->index) { - *this->story_page_elements.Append() = pe; + this->story_page_elements.push_back(pe); } } } - this->story_page_elements.Compact(); + this->story_page_elements.shrink_to_fit(); this->story_page_elements.RebuildDone(); } @@ -98,9 +98,9 @@ protected: } /** Sort story page elements by order value. */ - static int CDECL PageElementOrderSorter(const StoryPageElement * const *a, const StoryPageElement * const *b) + static bool PageElementOrderSorter(const StoryPageElement * const &a, const StoryPageElement * const &b) { - return (*a)->sort_value - (*b)->sort_value; + return a->sort_value < b->sort_value; } /* @@ -115,11 +115,11 @@ protected: /** * Get instance of selected page. - * @return Instance of selected page or NULL if no page is selected. + * @return Instance of selected page or nullptr if no page is selected. */ StoryPage *GetSelPage() const { - if (!_story_page_pool.IsValidID(selected_page_id)) return NULL; + if (!_story_page_pool.IsValidID(selected_page_id)) return nullptr; return _story_page_pool.Get(selected_page_id); } @@ -130,8 +130,7 @@ protected: int GetSelPageNum() const { int page_number = 0; - for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { - const StoryPage *p = *iter; + for (const StoryPage *p : this->story_pages) { if (p->index == this->selected_page_id) { return page_number; } @@ -148,7 +147,7 @@ protected: /* Verify that the selected page exist. */ if (!_story_page_pool.IsValidID(this->selected_page_id)) return false; - return (*this->story_pages.Begin())->index == this->selected_page_id; + return this->story_pages.front()->index == this->selected_page_id; } /** @@ -159,8 +158,8 @@ protected: /* Verify that the selected page exist. */ if (!_story_page_pool.IsValidID(this->selected_page_id)) return false; - if (this->story_pages.Length() <= 1) return true; - const StoryPage *last = *(this->story_pages.End() - 1); + if (this->story_pages.size() <= 1) return true; + const StoryPage *last = this->story_pages.back(); return last->index == this->selected_page_id; } @@ -171,7 +170,7 @@ protected: { /* Generate generic title if selected page have no custom title. */ StoryPage *page = this->GetSelPage(); - if (page != NULL && page->title == NULL) { + if (page != nullptr && page->title == nullptr) { SetDParam(0, GetSelPageNum() + 1); GetString(selected_generic_title, STR_STORY_BOOK_GENERIC_PAGE_ITEM, lastof(selected_generic_title)); } @@ -194,11 +193,10 @@ protected: /* Find the last available page which is previous to the current selected page. */ const StoryPage *last_available; - last_available = NULL; - for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { - const StoryPage *p = *iter; + last_available = nullptr; + for (const StoryPage *p : this->story_pages) { if (p->index == this->selected_page_id) { - if (last_available == NULL) return; // No previous page available. + if (last_available == nullptr) return; // No previous page available. this->SetSelectedPage(last_available->index); return; } @@ -214,12 +212,12 @@ protected: if (!_story_page_pool.IsValidID(this->selected_page_id)) return; /* Find selected page. */ - for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { + for (auto iter = this->story_pages.begin(); iter != this->story_pages.end(); iter++) { const StoryPage *p = *iter; if (p->index == this->selected_page_id) { /* Select the page after selected page. */ iter++; - if (iter != this->story_pages.End()) { + if (iter != this->story_pages.end()) { this->SetSelectedPage((*iter)->index); } return; @@ -230,15 +228,14 @@ protected: /** * Builds the page selector drop down list. */ - DropDownList *BuildDropDownList() const + DropDownList BuildDropDownList() const { - DropDownList *list = new DropDownList(); + DropDownList list; uint16 page_num = 1; - for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { - const StoryPage *p = *iter; + for (const StoryPage *p : this->story_pages) { bool current_page = p->index == this->selected_page_id; - DropDownListStringItem *item = NULL; - if (p->title != NULL) { + DropDownListStringItem *item = nullptr; + if (p->title != nullptr) { item = new DropDownListCharStringItem(p->title, p->index, current_page); } else { /* No custom title => use a generic page title with page number. */ @@ -248,16 +245,10 @@ protected: item = str_item; } - *list->Append() = item; + list.emplace_back(item); page_num++; } - /* Check if list is empty. */ - if (list->Length() == 0) { - delete list; - list = NULL; - } - return list; } @@ -272,19 +263,19 @@ protected: /** * Counts how many pixels of height that are used by Date and Title * (excluding marginal after Title, as each body element has - * an empty row before the elment). + * an empty row before the element). * @param max_width Available width to display content. * @return the height in pixels. */ uint GetHeadHeight(int max_width) const { StoryPage *page = this->GetSelPage(); - if (page == NULL) return 0; + if (page == nullptr) return 0; int height = 0; /* Title lines */ height += FONT_HEIGHT_NORMAL; // Date always use exactly one line. - SetDParamStr(0, page->title != NULL ? page->title : this->selected_generic_title); + SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title); height += GetStringHeight(STR_STORY_BOOK_TITLE, max_width); return height; @@ -301,7 +292,7 @@ protected: switch (pe.type) { case SPET_GOAL: { Goal *g = Goal::Get((GoalID) pe.referenced_id); - if (g == NULL) return SPR_IMG_GOAL_BROKEN_REF; + if (g == nullptr) return SPR_IMG_GOAL_BROKEN_REF; return g->completed ? SPR_IMG_GOAL_COMPLETED : SPR_IMG_GOAL; } case SPET_LOCATION: @@ -345,7 +336,7 @@ protected: uint GetContentHeight() { StoryPage *page = this->GetSelPage(); - if (page == NULL) return 0; + if (page == nullptr) return 0; int max_width = GetAvailablePageContentWidth(); uint element_vertical_dist = FONT_HEIGHT_NORMAL; @@ -353,8 +344,7 @@ protected: uint height = GetHeadHeight(max_width); /* Body */ - for (const StoryPageElement **iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { - const StoryPageElement *pe = *iter; + for (const StoryPageElement *pe : this->story_page_elements) { height += element_vertical_dist; height += GetPageElementHeight(*pe, max_width); } @@ -422,7 +412,7 @@ public: this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR); this->vscroll->SetStepSize(FONT_HEIGHT_NORMAL); - /* Initalize page sort. */ + /* Initialize page sort. */ this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs); this->story_pages.ForceRebuild(); this->BuildStoryPageList(); @@ -444,8 +434,8 @@ public: */ void UpdatePrevNextDisabledState() { - this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.Length() == 0 || this->IsFirstPageSelected()); - this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.Length() == 0 || this->IsLastPageSelected()); + this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.size() == 0 || this->IsFirstPageSelected()); + this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.size() == 0 || this->IsLastPageSelected()); this->SetWidgetDirty(WID_SB_PREV_PAGE); this->SetWidgetDirty(WID_SB_NEXT_PAGE); } @@ -463,12 +453,12 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_SB_SEL_PAGE: { StoryPage *page = this->GetSelPage(); - SetDParamStr(0, page != NULL && page->title != NULL ? page->title : this->selected_generic_title); + SetDParamStr(0, page != nullptr && page->title != nullptr ? page->title : this->selected_generic_title); break; } case WID_SB_CAPTION: @@ -482,7 +472,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { /* Detect if content has changed height. This can happen if a * multi-line text contains eg. {COMPANY} and that company is @@ -497,12 +487,12 @@ public: this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_SB_PAGE_PANEL) return; StoryPage *page = this->GetSelPage(); - if (page == NULL) return; + if (page == nullptr) return; const int x = r.left + WD_FRAMETEXT_LEFT; const int y = r.top + WD_FRAMETEXT_TOP; @@ -528,12 +518,11 @@ public: y_offset += line_height; /* Title */ - SetDParamStr(0, page->title != NULL ? page->title : this->selected_generic_title); + SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title); y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER); /* Page elements */ - for (const StoryPageElement *const*iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { - const StoryPageElement *const pe = *iter; + for (const StoryPageElement *const pe : this->story_page_elements) { y_offset += line_height; // margin to previous element switch (pe->type) { @@ -544,8 +533,8 @@ public: case SPET_GOAL: { Goal *g = Goal::Get((GoalID) pe->referenced_id); - StringID string_id = g == NULL ? STR_STORY_BOOK_INVALID_GOAL_REF : STR_JUST_RAW_STRING; - if (g != NULL) SetDParamStr(0, g->text); + StringID string_id = g == nullptr ? STR_STORY_BOOK_INVALID_GOAL_REF : STR_JUST_RAW_STRING; + if (g != nullptr) SetDParamStr(0, g->text); DrawActionElement(y_offset, right - x, line_height, GetPageElementSprite(*pe), string_id); break; } @@ -563,7 +552,7 @@ public: _cur_dpi = old_dpi; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return; @@ -575,10 +564,10 @@ public: case WID_SB_SEL_PAGE: { /* Get max title width. */ - for (uint16 i = 0; i < this->story_pages.Length(); i++) { + for (uint16 i = 0; i < this->story_pages.size(); i++) { const StoryPage *s = this->story_pages[i]; - if (s->title != NULL) { + if (s->title != nullptr) { SetDParamStr(0, s->title); } else { SetDParamStr(0, this->selected_generic_title); @@ -606,27 +595,27 @@ public: } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SB_PAGE_PANEL, WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM); this->vscroll->SetCount(this->GetContentHeight()); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_SB_SEL_PAGE: { - DropDownList *list = this->BuildDropDownList(); - if (list != NULL) { + DropDownList list = this->BuildDropDownList(); + if (!list.empty()) { /* Get the index of selected page. */ int selected = 0; - for (uint16 i = 0; i < this->story_pages.Length(); i++) { + for (uint16 i = 0; i < this->story_pages.size(); i++) { const StoryPage *p = this->story_pages[i]; if (p->index == this->selected_page_id) break; selected++; } - ShowDropDownList(this, list, selected, widget); + ShowDropDownList(this, std::move(list), selected, widget); } break; } @@ -650,8 +639,7 @@ public: /* Detect if a page element was clicked. */ uint y = head_height; uint element_vertical_dist = FONT_HEIGHT_NORMAL; - for (const StoryPageElement *const*iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { - const StoryPageElement *const pe = *iter; + for (const StoryPageElement *const pe : this->story_page_elements) { y += element_vertical_dist; // margin row @@ -667,7 +655,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (widget != WID_SB_SEL_PAGE) return; @@ -682,7 +670,7 @@ public: * >= 0 Id of the page that needs to be refreshed. If it is not the current page, nothing happens. * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; @@ -694,7 +682,7 @@ public: this->BuildStoryPageList(); /* Was the last page removed? */ - if (this->story_pages.Length() == 0) { + if (this->story_pages.size() == 0) { this->selected_generic_title[0] = '\0'; } @@ -702,14 +690,14 @@ public: if (!_story_page_pool.IsValidID(this->selected_page_id)) { this->selected_page_id = INVALID_STORY_PAGE; } - if (this->selected_page_id == INVALID_STORY_PAGE && this->story_pages.Length() > 0) { + if (this->selected_page_id == INVALID_STORY_PAGE && this->story_pages.size() > 0) { /* No page is selected, but there exist at least one available. * => Select first page. */ this->SetSelectedPage(this->story_pages[0]->index); } - this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.Length() == 0); + this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.size() == 0); this->SetWidgetDirty(WID_SB_SEL_PAGE); this->UpdatePrevNextDisabledState(); } else if (data >= 0 && this->selected_page_id == data) { diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index 98e11e2eb6..c33e884af0 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -30,13 +30,6 @@ #include #endif /* _WIN32 || __WATCOMC__ */ -#ifdef __MORPHOS__ -#ifdef stderr -#undef stderr -#endif -#define stderr stdout -#endif /* __MORPHOS__ */ - #include "../table/strgen_tables.h" #include "../safeguards.h" @@ -113,7 +106,7 @@ struct FileStringReader : StringReader { StringReader(data, file, master, translation) { this->fh = fopen(file, "rb"); - if (this->fh == NULL) error("Could not open %s", file); + if (this->fh == nullptr) error("Could not open %s", file); } /** Free/close the file. */ @@ -122,14 +115,14 @@ struct FileStringReader : StringReader { fclose(this->fh); } - /* virtual */ char *ReadLine(char *buffer, const char *last) + char *ReadLine(char *buffer, const char *last) override { return fgets(buffer, ClampToU16(last - buffer + 1), this->fh); } - /* virtual */ void HandlePragma(char *str); + void HandlePragma(char *str) override; - /* virtual */ void ParseFile() + void ParseFile() override { this->StringReader::ParseFile(); @@ -142,7 +135,7 @@ struct FileStringReader : StringReader { void FileStringReader::HandlePragma(char *str) { if (!memcmp(str, "id ", 3)) { - this->data.next_string_id = strtoul(str + 3, NULL, 0); + this->data.next_string_id = strtoul(str + 3, nullptr, 0); } else if (!memcmp(str, "name ", 5)) { strecpy(_lang.name, str + 5, lastof(_lang.name)); } else if (!memcmp(str, "ownname ", 8)) { @@ -168,14 +161,14 @@ void FileStringReader::HandlePragma(char *str) strecpy(_lang.digit_decimal_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str, lastof(_lang.digit_decimal_separator)); } else if (!memcmp(str, "winlangid ", 10)) { const char *buf = str + 10; - long langid = strtol(buf, NULL, 16); + long langid = strtol(buf, nullptr, 16); if (langid > (long)UINT16_MAX || langid < 0) { error("Invalid winlangid %s", buf); } _lang.winlangid = (uint16)langid; } else if (!memcmp(str, "grflangid ", 10)) { const char *buf = str + 10; - long langid = strtol(buf, NULL, 16); + long langid = strtol(buf, nullptr, 16); if (langid >= 0x7F || langid < 0) { error("Invalid grflangid %s", buf); } @@ -187,7 +180,7 @@ void FileStringReader::HandlePragma(char *str) for (;;) { const char *s = ParseWord(&buf); - if (s == NULL) break; + if (s == nullptr) break; if (_lang.num_genders >= MAX_NUM_GENDERS) error("Too many genders, max %d", MAX_NUM_GENDERS); strecpy(_lang.genders[_lang.num_genders], s, lastof(_lang.genders[_lang.num_genders])); _lang.num_genders++; @@ -199,7 +192,7 @@ void FileStringReader::HandlePragma(char *str) for (;;) { const char *s = ParseWord(&buf); - if (s == NULL) break; + if (s == nullptr) break; if (_lang.num_cases >= MAX_NUM_CASES) error("Too many cases, max %d", MAX_NUM_CASES); strecpy(_lang.cases[_lang.num_cases], s, lastof(_lang.cases[_lang.num_cases])); _lang.num_cases++; @@ -212,10 +205,10 @@ void FileStringReader::HandlePragma(char *str) bool CompareFiles(const char *n1, const char *n2) { FILE *f2 = fopen(n2, "rb"); - if (f2 == NULL) return false; + if (f2 == nullptr) return false; FILE *f1 = fopen(n1, "rb"); - if (f1 == NULL) { + if (f1 == nullptr) { fclose(f2); error("can't open %s", n1); } @@ -253,7 +246,7 @@ struct FileWriter { this->filename = stredup(filename); this->fh = fopen(this->filename, "wb"); - if (this->fh == NULL) { + if (this->fh == nullptr) { error("Could not open %s", this->filename); } } @@ -262,14 +255,14 @@ struct FileWriter { void Finalise() { fclose(this->fh); - this->fh = NULL; + this->fh = nullptr; } /** Make sure the file is closed. */ virtual ~FileWriter() { /* If we weren't closed an exception was thrown, so remove the temporary file. */ - if (fh != NULL) { + if (fh != nullptr) { fclose(this->fh); unlink(this->filename); } @@ -399,11 +392,13 @@ static inline char *mkpath(char *buf, const char *last, const char *path, const return buf; } -#if defined(__MINGW32__) +#if defined(_WIN32) /** * On MingW, it is common that both / as \ are accepted in the * params. To go with those flow, we rewrite all incoming / - * simply to \, so internally we can safely assume \. + * simply to \, so internally we can safely assume \, and do + * this for all Windows machines to keep identical behaviour, + * no matter what your compiler was. */ static inline char *replace_pathsep(char *s) { @@ -423,7 +418,7 @@ static const OptionData _opts[] = { GETOPT_NOVAL( 't', "--todo"), GETOPT_NOVAL( 'w', "--warning"), GETOPT_NOVAL( 'h', "--help"), - GETOPT_GENERAL('h', '?', NULL, ODF_NO_VALUE), + GETOPT_GENERAL('h', '?', nullptr, ODF_NO_VALUE), GETOPT_VALUE( 's', "--source_dir"), GETOPT_VALUE( 'd', "--dest_dir"), GETOPT_END(), @@ -433,7 +428,7 @@ int CDECL main(int argc, char *argv[]) { char pathbuf[MAX_PATH]; const char *src_dir = "."; - const char *dest_dir = NULL; + const char *dest_dir = nullptr; GetOptData mgo(argc - 1, argv + 1, _opts); for (;;) { @@ -517,7 +512,7 @@ int CDECL main(int argc, char *argv[]) } } - if (dest_dir == NULL) dest_dir = src_dir; // if dest_dir is not specified, it equals src_dir + if (dest_dir == nullptr) dest_dir = src_dir; // if dest_dir is not specified, it equals src_dir try { /* strgen has two modes of operation. If no (free) arguments are passed @@ -556,17 +551,17 @@ int CDECL main(int argc, char *argv[]) const char *translation = replace_pathsep(mgo.argv[i]); const char *file = strrchr(translation, PATHSEPCHAR); - FileStringReader translation_reader(data, translation, false, file == NULL || strcmp(file + 1, "english.txt") != 0); + FileStringReader translation_reader(data, translation, false, file == nullptr || strcmp(file + 1, "english.txt") != 0); translation_reader.ParseFile(); // target file if (_errors != 0) return 1; /* get the targetfile, strip any directories and append to destination path */ r = strrchr(mgo.argv[i], PATHSEPCHAR); - mkpath(pathbuf, lastof(pathbuf), dest_dir, (r != NULL) ? &r[1] : mgo.argv[i]); + mkpath(pathbuf, lastof(pathbuf), dest_dir, (r != nullptr) ? &r[1] : mgo.argv[i]); /* rename the .txt (input-extension) to .lng */ r = strrchr(pathbuf, '.'); - if (r == NULL || strcmp(r, ".txt") != 0) r = strchr(pathbuf, '\0'); + if (r == nullptr || strcmp(r, ".txt") != 0) r = strchr(pathbuf, '\0'); strecpy(r, ".lng", lastof(pathbuf)); LanguageFileWriter writer(pathbuf); diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index a4a3aed709..69b8732f17 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -73,7 +73,7 @@ struct StringReader { * Read a single line from the source of strings. * @param buffer The buffer to read the data in to. * @param last The last element in the buffer. - * @return The buffer, or NULL if at the end of the file. + * @return The buffer, or nullptr if at the end of the file. */ virtual char *ReadLine(char *buffer, const char *last) = 0; diff --git a/src/strgen/strgen_base.cpp b/src/strgen/strgen_base.cpp index 8bfe442815..84fc3537be 100644 --- a/src/strgen/strgen_base.cpp +++ b/src/strgen/strgen_base.cpp @@ -59,8 +59,8 @@ Case::~Case() * @param line The line this string was found on. */ LangString::LangString(const char *name, const char *english, size_t index, int line) : - name(stredup(name)), english(stredup(english)), translated(NULL), - hash_next(0), index(index), line(line), translated_case(NULL) + name(stredup(name)), english(stredup(english)), translated(nullptr), + hash_next(0), index(index), line(line), translated_case(nullptr) { } @@ -77,10 +77,10 @@ LangString::~LangString() void LangString::FreeTranslation() { free(this->translated); - this->translated = NULL; + this->translated = nullptr; delete this->translated_case; - this->translated_case = NULL; + this->translated_case = nullptr; } /** @@ -107,7 +107,7 @@ void StringData::FreeTranslation() { for (size_t i = 0; i < this->max_strings; i++) { LangString *ls = this->strings[i]; - if (ls != NULL) ls->FreeTranslation(); + if (ls != nullptr) ls->FreeTranslation(); } } @@ -140,7 +140,7 @@ void StringData::Add(const char *s, LangString *ls) /** * Find a LangString based on the string name. * @param s The string name to search on. - * @return The LangString or NULL if it is not known. + * @return The LangString or nullptr if it is not known. */ LangString *StringData::Find(const char *s) { @@ -152,7 +152,7 @@ LangString *StringData::Find(const char *s) if (strcmp(ls->name, s) == 0) return ls; idx = ls->hash_next; } - return NULL; + return nullptr; } /** @@ -181,7 +181,7 @@ uint StringData::Version() const for (size_t i = 0; i < this->max_strings; i++) { const LangString *ls = this->strings[i]; - if (ls != NULL) { + if (ls != nullptr) { const CmdStruct *cs; const char *s; char buf[MAX_COMMAND_PARAM_SIZE]; @@ -194,7 +194,7 @@ uint StringData::Version() const hash = this->VersionHashStr(hash, s + 1); s = ls->english; - while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != NULL) { + while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != nullptr) { if (cs->flags & C_DONTCOUNT) continue; hash ^= (cs - _cmd_structs) * 0x1234567; @@ -213,7 +213,7 @@ uint StringData::Version() const uint StringData::CountInUse(uint tab) const { int i; - for (i = TAB_SIZE; --i >= 0;) if (this->strings[(tab * TAB_SIZE) + i] != NULL) break; + for (i = TAB_SIZE; --i >= 0;) if (this->strings[(tab * TAB_SIZE) + i] != nullptr) break; return i + 1; } @@ -235,14 +235,14 @@ static ParsedCommandStruct _cur_pcs; static int _cur_argidx; /** The buffer for writing a single string. */ -struct Buffer : SmallVector { +struct Buffer : std::vector { /** * Convenience method for adding a byte. * @param value The value to add. */ void AppendByte(byte value) { - *this->Append() = value; + this->push_back(value); } /** @@ -252,19 +252,19 @@ struct Buffer : SmallVector { void AppendUtf8(uint32 value) { if (value < 0x80) { - *this->Append() = value; + this->push_back(value); } else if (value < 0x800) { - *this->Append() = 0xC0 + GB(value, 6, 5); - *this->Append() = 0x80 + GB(value, 0, 6); + this->push_back(0xC0 + GB(value, 6, 5)); + this->push_back(0x80 + GB(value, 0, 6)); } else if (value < 0x10000) { - *this->Append() = 0xE0 + GB(value, 12, 4); - *this->Append() = 0x80 + GB(value, 6, 6); - *this->Append() = 0x80 + GB(value, 0, 6); + this->push_back(0xE0 + GB(value, 12, 4)); + this->push_back(0x80 + GB(value, 6, 6)); + this->push_back(0x80 + GB(value, 0, 6)); } else if (value < 0x110000) { - *this->Append() = 0xF0 + GB(value, 18, 3); - *this->Append() = 0x80 + GB(value, 12, 6); - *this->Append() = 0x80 + GB(value, 6, 6); - *this->Append() = 0x80 + GB(value, 0, 6); + this->push_back(0xF0 + GB(value, 18, 3)); + this->push_back(0x80 + GB(value, 12, 6)); + this->push_back(0x80 + GB(value, 6, 6)); + this->push_back(0x80 + GB(value, 0, 6)); } else { strgen_warning("Invalid unicode value U+0x%X", value); } @@ -327,7 +327,7 @@ bool ParseRelNum(char **buf, int *value, int *offset) } else { *value = v; } - if (offset != NULL && *end == ':') { + if (offset != nullptr && *end == ':') { /* Take the Nth within */ s = end + 1; *offset = strtol(s, &end, 0); @@ -337,13 +337,13 @@ bool ParseRelNum(char **buf, int *value, int *offset) return true; } -/* Parse out the next word, or NULL */ +/* Parse out the next word, or nullptr */ char *ParseWord(char **buf) { char *s = *buf, *r; while (*s == ' ' || *s == '\t') s++; - if (*s == '\0') return NULL; + if (*s == '\0') return nullptr; if (*s == '"') { r = ++s; @@ -399,8 +399,8 @@ void EmitPlural(Buffer *buffer, char *buf, int value) const CmdStruct *cmd = _cur_pcs.cmd[argidx]; if (offset == -1) { /* Use default offset */ - if (cmd == NULL || cmd->default_plural_offset < 0) { - strgen_fatal("Command '%s' has no (default) plural position", cmd == NULL ? "" : cmd->cmd); + if (cmd == nullptr || cmd->default_plural_offset < 0) { + strgen_fatal("Command '%s' has no (default) plural position", cmd == nullptr ? "" : cmd->cmd); } offset = cmd->default_plural_offset; } @@ -408,7 +408,7 @@ void EmitPlural(Buffer *buffer, char *buf, int value) /* Parse each string */ for (nw = 0; nw < MAX_PLURALS; nw++) { words[nw] = ParseWord(&buf); - if (words[nw] == NULL) break; + if (words[nw] == nullptr) break; } if (nw == 0) { @@ -462,13 +462,13 @@ void EmitGender(Buffer *buffer, char *buf, int value) if (!ParseRelNum(&buf, &argidx, &offset)) {} const CmdStruct *cmd = _cur_pcs.cmd[argidx]; - if (cmd == NULL || (cmd->flags & C_GENDER) == 0) { - strgen_fatal("Command '%s' can't have a gender", cmd == NULL ? "" : cmd->cmd); + if (cmd == nullptr || (cmd->flags & C_GENDER) == 0) { + strgen_fatal("Command '%s' can't have a gender", cmd == nullptr ? "" : cmd->cmd); } for (nw = 0; nw < MAX_NUM_GENDERS; nw++) { words[nw] = ParseWord(&buf); - if (words[nw] == NULL) break; + if (words[nw] == nullptr) break; } if (nw != _lang.num_genders) strgen_fatal("Bad # of arguments for gender command"); @@ -484,7 +484,7 @@ static const CmdStruct *FindCmd(const char *s, int len) for (const CmdStruct *cs = _cmd_structs; cs != endof(_cmd_structs); cs++) { if (strncmp(cs->cmd, s, len) == 0 && cs->cmd[len] == '\0') return cs; } - return NULL; + return nullptr; } static uint ResolveCaseName(const char *str, size_t len) @@ -501,7 +501,7 @@ static uint ResolveCaseName(const char *str, size_t len) } -/* returns NULL on eof +/* returns nullptr on eof * else returns command struct */ static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei) { @@ -513,7 +513,7 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a /* Scan to the next command, exit if there's no next command. */ for (; *s != '{'; s++) { - if (*s == '\0') return NULL; + if (*s == '\0') return nullptr; } s++; // Skip past the { @@ -532,9 +532,9 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); const CmdStruct *cmd = FindCmd(start, s - start - 1); - if (cmd == NULL) { + if (cmd == nullptr) { strgen_error("Undefined command '%.*s'", (int)(s - start - 1), start); - return NULL; + return nullptr; } if (c == '.') { @@ -552,7 +552,7 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a if (c == '\0') { strgen_error("Missing } from command '%s'", start); - return NULL; + return nullptr; } @@ -565,7 +565,7 @@ static const CmdStruct *ParseCommandString(const char **str, char *param, int *a if (c == '}') break; if (c == '\0') { strgen_error("Missing } from command '%s'", start); - return NULL; + return nullptr; } if (s - start == MAX_COMMAND_PARAM_SIZE) error("param command too long"); *param++ = c; @@ -609,7 +609,7 @@ static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool war /* read until next command from a. */ const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei); - if (ar == NULL) break; + if (ar == nullptr) break; /* Sanity checking */ if (argno != -1 && ar->consumes == 0) strgen_fatal("Non consumer param can't have a paramindex"); @@ -617,7 +617,7 @@ static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool war if (ar->consumes) { if (argno != -1) argidx = argno; if (argidx < 0 || (uint)argidx >= lengthof(p->cmd)) strgen_fatal("invalid param idx %d", argidx); - if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) strgen_fatal("duplicate param idx %d", argidx); + if (p->cmd[argidx] != nullptr && p->cmd[argidx] != ar) strgen_fatal("duplicate param idx %d", argidx); p->cmd[argidx++] = ar; } else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them @@ -632,7 +632,7 @@ static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool war static const CmdStruct *TranslateCmdForCompare(const CmdStruct *a) { - if (a == NULL) return NULL; + if (a == nullptr) return nullptr; if (strcmp(a->cmd, "STRING1") == 0 || strcmp(a->cmd, "STRING2") == 0 || @@ -677,7 +677,7 @@ static bool CheckCommandsMatch(char *a, char *b, const char *name) if (templ.pairs[i].a == lang.pairs[j].a && strcmp(templ.pairs[i].v, lang.pairs[j].v) == 0) { /* it was found in both. zero it out from lang so we don't find it again */ - lang.pairs[j].a = NULL; + lang.pairs[j].a = nullptr; found = true; break; } @@ -694,8 +694,8 @@ static bool CheckCommandsMatch(char *a, char *b, const char *name) for (uint i = 0; i < lengthof(templ.cmd); i++) { if (TranslateCmdForCompare(templ.cmd[i]) != lang.cmd[i]) { strgen_warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i, - lang.cmd[i] == NULL ? "" : TranslateCmdForCompare(lang.cmd[i])->cmd, - templ.cmd[i] == NULL ? "" : templ.cmd[i]->cmd); + lang.cmd[i] == nullptr ? "" : TranslateCmdForCompare(lang.cmd[i])->cmd, + templ.cmd[i] == nullptr ? "" : templ.cmd[i]->cmd); result = false; } } @@ -714,7 +714,7 @@ void StringReader::HandleString(char *str) if (*str == ';' || *str == ' ' || *str == '\0') return; char *s = strchr(str, ':'); - if (s == NULL) { + if (s == nullptr) { strgen_error("Line has no ':' delimiter"); return; } @@ -747,23 +747,23 @@ void StringReader::HandleString(char *str) /* Check if the string has a case.. * The syntax for cases is IDENTNAME.case */ char *casep = strchr(str, '.'); - if (casep != NULL) *casep++ = '\0'; + if (casep != nullptr) *casep++ = '\0'; /* Check if this string already exists.. */ LangString *ent = this->data.Find(str); if (this->master) { - if (casep != NULL) { + if (casep != nullptr) { strgen_error("Cases in the base translation are not supported."); return; } - if (ent != NULL) { + if (ent != nullptr) { strgen_error("String name '%s' is used multiple times", str); return; } - if (this->data.strings[this->data.next_string_id] != NULL) { + if (this->data.strings[this->data.next_string_id] != nullptr) { strgen_error("String ID 0x" PRINTF_SIZEX " for '%s' already in use by '%s'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name); return; } @@ -771,12 +771,12 @@ void StringReader::HandleString(char *str) /* Allocate a new LangString */ this->data.Add(str, new LangString(str, s, this->data.next_string_id++, _cur_line)); } else { - if (ent == NULL) { + if (ent == nullptr) { strgen_warning("String name '%s' does not exist in master file", str); return; } - if (ent->translated && casep == NULL) { + if (ent->translated && casep == nullptr) { strgen_error("String name '%s' is used multiple times", str); return; } @@ -784,7 +784,7 @@ void StringReader::HandleString(char *str) /* make sure that the commands match */ if (!CheckCommandsMatch(s, ent->english, str)) return; - if (casep != NULL) { + if (casep != nullptr) { ent->translated_case = new Case(ResolveCaseName(casep, strlen(casep)), s, ent->translated_case); } else { ent->translated = stredup(s); @@ -830,7 +830,7 @@ void StringReader::ParseFile() strecpy(_lang.digit_decimal_separator, ".", lastof(_lang.digit_decimal_separator)); _cur_line = 1; - while (this->data.next_string_id < this->data.max_strings && this->ReadLine(buf, lastof(buf)) != NULL) { + while (this->data.next_string_id < this->data.max_strings && this->ReadLine(buf, lastof(buf)) != nullptr) { rstrip(buf); this->HandleString(buf); _cur_line++; @@ -849,7 +849,7 @@ void HeaderWriter::WriteHeader(const StringData &data) { int last = 0; for (size_t i = 0; i < data.max_strings; i++) { - if (data.strings[i] != NULL) { + if (data.strings[i] != nullptr) { this->WriteStringID(data.strings[i]->name, (int)i); last = (int)i; } @@ -866,18 +866,18 @@ static int TranslateArgumentIdx(int argidx, int offset) strgen_fatal("invalid argidx %d", argidx); } const CmdStruct *cs = _cur_pcs.cmd[argidx]; - if (cs != NULL && cs->consumes <= offset) { + if (cs != nullptr && cs->consumes <= offset) { strgen_fatal("invalid argidx offset %d:%d", argidx, offset); } - if (_cur_pcs.cmd[argidx] == NULL) { + if (_cur_pcs.cmd[argidx] == nullptr) { strgen_fatal("no command for this argidx %d", argidx); } for (int i = sum = 0; i < argidx; i++) { const CmdStruct *cs = _cur_pcs.cmd[i]; - sum += (cs != NULL) ? cs->consumes : 1; + sum += (cs != nullptr) ? cs->consumes : 1; } return sum + offset; @@ -905,7 +905,7 @@ static void PutCommandString(Buffer *buffer, const char *str) int argno; int casei; const CmdStruct *cs = ParseCommandString(&str, param, &argno, &casei); - if (cs == NULL) break; + if (cs == nullptr) break; if (casei != -1) { buffer->AppendUtf8(SCC_SET_CASE); // {SET_CASE} @@ -922,7 +922,7 @@ static void PutCommandString(Buffer *buffer, const char *str) /* Output the one from the master string... it's always accurate. */ cs = _cur_pcs.cmd[_cur_argidx++]; - if (cs == NULL) { + if (cs == nullptr) { strgen_fatal("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1); } } @@ -965,7 +965,7 @@ void LanguageWriter::WriteLang(const StringData &data) for (uint j = 0; j != in_use[tab]; j++) { const LangString *ls = data.strings[(tab * TAB_SIZE) + j]; - if (ls != NULL && ls->translated == NULL) _lang.missing++; + if (ls != nullptr && ls->translated == nullptr) _lang.missing++; } } @@ -984,7 +984,7 @@ void LanguageWriter::WriteLang(const StringData &data) const char *cmdp; /* For undefined strings, just set that it's an empty string */ - if (ls == NULL) { + if (ls == nullptr) { this->WriteLength(0); continue; } @@ -993,7 +993,7 @@ void LanguageWriter::WriteLang(const StringData &data) _cur_line = ls->line; /* Produce a message if a string doesn't have a translation. */ - if (_show_todo > 0 && ls->translated == NULL) { + if (_show_todo > 0 && ls->translated == nullptr) { if ((_show_todo & 2) != 0) { strgen_warning("'%s' is untranslated", ls->name); } @@ -1006,17 +1006,17 @@ void LanguageWriter::WriteLang(const StringData &data) /* Extract the strings and stuff from the english command string */ ExtractCommandString(&_cur_pcs, ls->english, false); - if (ls->translated_case != NULL || ls->translated != NULL) { + if (ls->translated_case != nullptr || ls->translated != nullptr) { casep = ls->translated_case; cmdp = ls->translated; } else { - casep = NULL; + casep = nullptr; cmdp = ls->english; } _translated = cmdp != ls->english; - if (casep != NULL) { + if (casep != nullptr) { const Case *c; uint num; @@ -1030,27 +1030,27 @@ void LanguageWriter::WriteLang(const StringData &data) buffer.AppendByte(num); /* Write each case */ - for (c = casep; c != NULL; c = c->next) { + for (c = casep; c != nullptr; c = c->next) { buffer.AppendByte(c->caseidx); /* Make some space for the 16-bit length */ - uint pos = buffer.Length(); + uint pos = (uint)buffer.size(); buffer.AppendByte(0); buffer.AppendByte(0); /* Write string */ PutCommandString(&buffer, c->string); buffer.AppendByte(0); // terminate with a zero /* Fill in the length */ - uint size = buffer.Length() - (pos + 2); + uint size = (uint)buffer.size() - (pos + 2); buffer[pos + 0] = GB(size, 8, 8); buffer[pos + 1] = GB(size, 0, 8); } } - if (cmdp != NULL) PutCommandString(&buffer, cmdp); + if (cmdp != nullptr) PutCommandString(&buffer, cmdp); - this->WriteLength(buffer.Length()); - this->Write(buffer.Begin(), buffer.Length()); - buffer.Clear(); + this->WriteLength((uint)buffer.size()); + this->Write(buffer.data(), buffer.size()); + buffer.clear(); } } } diff --git a/src/string.cpp b/src/string.cpp index ae1b556aff..ed3f7cc66b 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -37,12 +37,12 @@ #include "os/macosx/string_osx.h" #endif -#ifdef WITH_ICU_SORT +#ifdef WITH_ICU_I18N /* Required by strnatcmp. */ #include #include "language.h" #include "gfx_func.h" -#endif /* WITH_ICU_SORT */ +#endif /* WITH_ICU_I18N */ /* The function vsnprintf is used internally to perform the required formatting * tasks. As such this one must be allowed, and makes sure it's terminated. */ @@ -71,7 +71,7 @@ int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) * * Appends the source string to the destination string with respect of the * terminating null-character and and the last pointer to the last element - * in the destination buffer. If the last pointer is set to NULL no + * in the destination buffer. If the last pointer is set to nullptr no * boundary check is performed. * * @note usage: strecat(dst, src, lastof(dst)); @@ -99,7 +99,7 @@ char *strecat(char *dst, const char *src, const char *last) * * Copies the source string to the destination buffer with respect of the * terminating null-character and the last pointer to the last element in - * the destination buffer. If the last pointer is set to NULL no boundary + * the destination buffer. If the last pointer is set to nullptr no boundary * check is performed. * * @note usage: strecpy(dst, src, lastof(dst)); @@ -131,13 +131,13 @@ char *strecpy(char *dst, const char *src, const char *last) /** * Create a duplicate of the given string. * @param s The string to duplicate. - * @param last The last character that is safe to duplicate. If NULL, the whole string is duplicated. + * @param last The last character that is safe to duplicate. If nullptr, the whole string is duplicated. * @note The maximum length of the resulting string might therefore be last - s + 1. * @return The duplicate of the string. */ char *stredup(const char *s, const char *last) { - size_t len = last == NULL ? strlen(s) : ttd_strnlen(s, last - s + 1); + size_t len = last == nullptr ? strlen(s) : ttd_strnlen(s, last - s + 1); char *tmp = CallocT(len + 1); memcpy(tmp, s, len); return tmp; @@ -447,7 +447,7 @@ char *md5sumToString(char *buf, const char *last, const uint8 md5sum[16]) */ size_t Utf8Decode(WChar *c, const char *s) { - assert(c != NULL); + assert(c != nullptr); if (!HasBit(s[0], 7)) { /* Single byte character: 0xxxxxxx */ @@ -551,7 +551,7 @@ char *strcasestr(const char *haystack, const char *needle) hay_len--; } - return NULL; + return nullptr; } #endif /* DEFINE_STRCASESTR */ @@ -584,13 +584,13 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front) s2 = SkipGarbage(s2); } -#ifdef WITH_ICU_SORT - if (_current_collator != NULL) { +#ifdef WITH_ICU_I18N + if (_current_collator != nullptr) { UErrorCode status = U_ZERO_ERROR; int result = _current_collator->compareUTF8(s1, s2, status); if (U_SUCCESS(status)) return result; } -#endif /* WITH_ICU_SORT */ +#endif /* WITH_ICU_I18N */ #if defined(_WIN32) && !defined(STRGEN) && !defined(SETTINGSGEN) int res = OTTDStringCompare(s1, s2); @@ -613,7 +613,7 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front) return new UniscribeStringIterator(); } -#elif defined(WITH_ICU_SORT) +#elif defined(WITH_ICU_I18N) #include #include @@ -624,27 +624,27 @@ class IcuStringIterator : public StringIterator icu::BreakIterator *char_itr; ///< ICU iterator for characters. icu::BreakIterator *word_itr; ///< ICU iterator for words. - SmallVector utf16_str; ///< UTF-16 copy of the string. - SmallVector utf16_to_utf8; ///< Mapping from UTF-16 code point position to index in the UTF-8 source string. + std::vector utf16_str; ///< UTF-16 copy of the string. + std::vector utf16_to_utf8; ///< Mapping from UTF-16 code point position to index in the UTF-8 source string. public: - IcuStringIterator() : char_itr(NULL), word_itr(NULL) + IcuStringIterator() : char_itr(nullptr), word_itr(nullptr) { UErrorCode status = U_ZERO_ERROR; - this->char_itr = icu::BreakIterator::createCharacterInstance(icu::Locale(_current_language != NULL ? _current_language->isocode : "en"), status); - this->word_itr = icu::BreakIterator::createWordInstance(icu::Locale(_current_language != NULL ? _current_language->isocode : "en"), status); + this->char_itr = icu::BreakIterator::createCharacterInstance(icu::Locale(_current_language != nullptr ? _current_language->isocode : "en"), status); + this->word_itr = icu::BreakIterator::createWordInstance(icu::Locale(_current_language != nullptr ? _current_language->isocode : "en"), status); - *this->utf16_str.Append() = '\0'; - *this->utf16_to_utf8.Append() = 0; + this->utf16_str.push_back('\0'); + this->utf16_to_utf8.push_back(0); } - virtual ~IcuStringIterator() + ~IcuStringIterator() override { delete this->char_itr; delete this->word_itr; } - virtual void SetString(const char *s) + void SetString(const char *s) override { const char *string_base = s; @@ -652,40 +652,40 @@ public: * for word break iterators (especially for CJK languages) in combination * with UTF-8 input. As a work around we have to convert the input to * UTF-16 and create a mapping back to UTF-8 character indices. */ - this->utf16_str.Clear(); - this->utf16_to_utf8.Clear(); + this->utf16_str.clear(); + this->utf16_to_utf8.clear(); while (*s != '\0') { size_t idx = s - string_base; WChar c = Utf8Consume(&s); if (c < 0x10000) { - *this->utf16_str.Append() = (UChar)c; + this->utf16_str.push_back((UChar)c); } else { /* Make a surrogate pair. */ - *this->utf16_str.Append() = (UChar)(0xD800 + ((c - 0x10000) >> 10)); - *this->utf16_str.Append() = (UChar)(0xDC00 + ((c - 0x10000) & 0x3FF)); - *this->utf16_to_utf8.Append() = idx; + this->utf16_str.push_back((UChar)(0xD800 + ((c - 0x10000) >> 10))); + this->utf16_str.push_back((UChar)(0xDC00 + ((c - 0x10000) & 0x3FF))); + this->utf16_to_utf8.push_back(idx); } - *this->utf16_to_utf8.Append() = idx; + this->utf16_to_utf8.push_back(idx); } - *this->utf16_str.Append() = '\0'; - *this->utf16_to_utf8.Append() = s - string_base; + this->utf16_str.push_back('\0'); + this->utf16_to_utf8.push_back(s - string_base); UText text = UTEXT_INITIALIZER; UErrorCode status = U_ZERO_ERROR; - utext_openUChars(&text, this->utf16_str.Begin(), this->utf16_str.Length() - 1, &status); + utext_openUChars(&text, this->utf16_str.data(), this->utf16_str.size() - 1, &status); this->char_itr->setText(&text, status); this->word_itr->setText(&text, status); this->char_itr->first(); this->word_itr->first(); } - virtual size_t SetCurPosition(size_t pos) + size_t SetCurPosition(size_t pos) override { /* Convert incoming position to an UTF-16 string index. */ uint utf16_pos = 0; - for (uint i = 0; i < this->utf16_to_utf8.Length(); i++) { + for (uint i = 0; i < this->utf16_to_utf8.size(); i++) { if (this->utf16_to_utf8[i] == pos) { utf16_pos = i; break; @@ -699,7 +699,7 @@ public: return this->utf16_to_utf8[this->char_itr->current()]; } - virtual size_t Next(IterType what) + size_t Next(IterType what) override { int32_t pos; switch (what) { @@ -731,7 +731,7 @@ public: return pos == icu::BreakIterator::DONE ? END : this->utf16_to_utf8[pos]; } - virtual size_t Prev(IterType what) + size_t Prev(IterType what) override { int32_t pos; switch (what) { @@ -779,7 +779,7 @@ class DefaultStringIterator : public StringIterator size_t cur_pos; ///< Current iteration position. public: - DefaultStringIterator() : string(NULL), len(0), cur_pos(0) + DefaultStringIterator() : string(nullptr), len(0), cur_pos(0) { } @@ -792,7 +792,7 @@ public: virtual size_t SetCurPosition(size_t pos) { - assert(this->string != NULL && pos <= this->len); + assert(this->string != nullptr && pos <= this->len); /* Sanitize in case we get a position inside an UTF-8 sequence. */ while (pos > 0 && IsUtf8Part(this->string[pos])) pos--; return this->cur_pos = pos; @@ -800,7 +800,7 @@ public: virtual size_t Next(IterType what) { - assert(this->string != NULL); + assert(this->string != nullptr); /* Already at the end? */ if (this->cur_pos >= this->len) return END; @@ -838,7 +838,7 @@ public: virtual size_t Prev(IterType what) { - assert(this->string != NULL); + assert(this->string != nullptr); /* Already at the beginning? */ if (this->cur_pos == 0) return END; @@ -878,7 +878,7 @@ public: /* static */ StringIterator *StringIterator::Create() { StringIterator *i = OSXStringIterator::Create(); - if (i != NULL) return i; + if (i != nullptr) return i; return new DefaultStringIterator(); } diff --git a/src/string_func.h b/src/string_func.h index ff12f3747a..1f622870e1 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -33,7 +33,7 @@ char *strecat(char *dst, const char *src, const char *last); char *strecpy(char *dst, const char *src, const char *last); -char *stredup(const char *src, const char *last = NULL); +char *stredup(const char *src, const char *last = nullptr); int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4); int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap); @@ -54,11 +54,11 @@ bool StrValid(const char *str, const char *last); * * @param s The pointer to the first element of the buffer * @return true if the buffer starts with the terminating null-character or - * if the given pointer points to NULL else return false + * if the given pointer points to nullptr else return false */ static inline bool StrEmpty(const char *s) { - return s == NULL || s[0] == '\0'; + return s == nullptr || s[0] == '\0'; } /** diff --git a/src/string_type.h b/src/string_type.h index 94d4304dfe..b4e8237c41 100644 --- a/src/string_type.h +++ b/src/string_type.h @@ -13,6 +13,8 @@ #define STRING_TYPE_H #include "core/enum_type.hpp" +#include +#include /** A non-breaking space. */ #define NBSP "\xC2\xA0" @@ -53,4 +55,8 @@ enum StringValidationSettings { }; DECLARE_ENUM_AS_BIT_SET(StringValidationSettings) + +/** Type for a list of strings. */ +typedef std::vector StringList; + #endif /* STRING_TYPE_H */ diff --git a/src/stringfilter.cpp b/src/stringfilter.cpp index 6045c19ef4..d0bffb2706 100644 --- a/src/stringfilter.cpp +++ b/src/stringfilter.cpp @@ -28,18 +28,19 @@ static const WChar STATE_QUOTE2 = '"'; */ void StringFilter::SetFilterTerm(const char *str) { - this->word_index.Reset(); + this->word_index.clear(); + this->word_index.shrink_to_fit(); this->word_matches = 0; free(this->filter_buffer); - assert(str != NULL); + assert(str != nullptr); char *dest = MallocT(strlen(str) + 1); this->filter_buffer = dest; WChar state = STATE_WHITESPACE; const char *pos = str; - WordState *word = NULL; + WordState *word = nullptr; size_t len; for (;; pos += len) { WChar c; @@ -47,9 +48,9 @@ void StringFilter::SetFilterTerm(const char *str) if (c == 0 || (state == STATE_WORD && IsWhitespace(c))) { /* Finish word */ - if (word != NULL) { + if (word != nullptr) { *(dest++) = '\0'; - word = NULL; + word = nullptr; } state = STATE_WHITESPACE; if (c != 0) continue; else break; @@ -74,10 +75,9 @@ void StringFilter::SetFilterTerm(const char *str) } /* Add to word */ - if (word == NULL) { - word = this->word_index.Append(); - word->start = dest; - word->match = false; + if (word == nullptr) { + /*C++17: word = &*/ this->word_index.push_back({dest, false}); + word = &this->word_index.back(); } memcpy(dest, pos, len); @@ -91,9 +91,8 @@ void StringFilter::SetFilterTerm(const char *str) void StringFilter::ResetState() { this->word_matches = 0; - const WordState *end = this->word_index.End(); - for (WordState *it = this->word_index.Begin(); it != end; ++it) { - it->match = false; + for (WordState &ws : this->word_index) { + ws.match = false; } } @@ -107,14 +106,13 @@ void StringFilter::ResetState() */ void StringFilter::AddLine(const char *str) { - if (str == NULL) return; + if (str == nullptr) return; - bool match_case = this->case_sensitive != NULL && *this->case_sensitive; - const WordState *end = this->word_index.End(); - for (WordState *it = this->word_index.Begin(); it != end; ++it) { - if (!it->match) { - if ((match_case ? strstr(str, it->start) : strcasestr(str, it->start)) != NULL) { - it->match = true; + bool match_case = this->case_sensitive != nullptr && *this->case_sensitive; + for (WordState &ws : this->word_index) { + if (!ws.match) { + if ((match_case ? strstr(str, ws.start) : strcasestr(str, ws.start)) != nullptr) { + ws.match = true; this->word_matches++; } } diff --git a/src/stringfilter_type.h b/src/stringfilter_type.h index f78b133cb4..c2acffc35e 100644 --- a/src/stringfilter_type.h +++ b/src/stringfilter_type.h @@ -39,7 +39,7 @@ private: }; const char *filter_buffer; ///< Parsed filter string. Words separated by 0. - SmallVector word_index; ///< Word index and filter state. + std::vector word_index; ///< Word index and filter state. uint word_matches; ///< Summary of filter state: Number of words matched. const bool *case_sensitive; ///< Match case-sensitively (usually a static variable). @@ -47,9 +47,9 @@ private: public: /** * Constructor for filter. - * @param case_sensitive Pointer to a (usually static) variable controlling the case-sensitivity. NULL means always case-insensitive. + * @param case_sensitive Pointer to a (usually static) variable controlling the case-sensitivity. nullptr means always case-insensitive. */ - StringFilter(const bool *case_sensitive = NULL) : filter_buffer(NULL), word_matches(0), case_sensitive(case_sensitive) {} + StringFilter(const bool *case_sensitive = nullptr) : filter_buffer(nullptr), word_matches(0), case_sensitive(case_sensitive) {} ~StringFilter() { free(this->filter_buffer); } void SetFilterTerm(const char *str); @@ -58,7 +58,7 @@ public: * Check whether any filter words were entered. * @return true if no words were entered. */ - bool IsEmpty() const { return this->word_index.Length() == 0; } + bool IsEmpty() const { return this->word_index.size() == 0; } void ResetState(); void AddLine(const char *str); @@ -68,7 +68,7 @@ public: * Get the matching state of the current item. * @return true if matched. */ - bool GetState() const { return this->word_matches == this->word_index.Length(); } + bool GetState() const { return this->word_matches == this->word_index.size(); } }; #endif /* STRINGFILTER_TYPE_H */ diff --git a/src/strings.cpp b/src/strings.cpp index 6ffa688f1d..5593f6ba05 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -35,9 +35,7 @@ #include "window_func.h" #include "debug.h" #include "game/game_text.hpp" -#ifdef ENABLE_NETWORK -# include "network/network_content_gui.h" -#endif /* ENABLE_NETWORK */ +#include "network/network_content_gui.h" #include #include "table/strings.h" @@ -47,13 +45,13 @@ char _config_language_file[MAX_PATH]; ///< The file (name) stored in the configuration. LanguageList _languages; ///< The actual list of language meta data. -const LanguageMetadata *_current_language = NULL; ///< The currently loaded language. +const LanguageMetadata *_current_language = nullptr; ///< The currently loaded language. TextDirection _current_text_dir; ///< Text direction of the currently selected language. -#ifdef WITH_ICU_SORT -icu::Collator *_current_collator = NULL; ///< Collator for the language currently in use. -#endif /* WITH_ICU_SORT */ +#ifdef WITH_ICU_I18N +icu::Collator *_current_collator = nullptr; ///< Collator for the language currently in use. +#endif /* WITH_ICU_I18N */ static uint64 _global_string_params_data[20]; ///< Global array of string parameters. To access, use #SetDParam. static WChar _global_string_params_type[20]; ///< Type of parameters stored in #_global_string_params @@ -62,7 +60,7 @@ StringParameters _global_string_params(_global_string_params_data, 20, _global_s /** Reset the type array. */ void StringParameters::ClearTypeInformation() { - assert(this->type != NULL); + assert(this->type != nullptr); MemSetT(this->type, 0, this->num_param); } @@ -77,7 +75,7 @@ int64 StringParameters::GetInt64(WChar type) DEBUG(misc, 0, "Trying to read invalid string parameter"); return 0; } - if (this->type != NULL) { + if (this->type != nullptr) { if (this->type[this->offset] != 0 && this->type[this->offset] != type) { DEBUG(misc, 0, "Trying to read string parameter with wrong type"); return 0; @@ -123,7 +121,8 @@ void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size) */ void SetDParamMaxDigits(uint n, uint count, FontSize size) { - uint front, next; + uint front = 0; + uint next = 0; GetBroadestDigit(&front, &next, size); uint64 val = count > 1 ? front : next; for (; count > 1; count--) { @@ -173,7 +172,7 @@ void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num) strings[i] = stredup((const char *)(size_t)_global_string_params.GetParam(i)); dst[i] = (size_t)strings[i]; } else { - strings[i] = NULL; + strings[i] = nullptr; } } } @@ -321,7 +320,7 @@ static char *FormatNumber(char *buff, int64 number, const char *last, const char for (int i = 0; i < max_digits; i++) { if (i == max_digits - fractional_digits) { const char *decimal_separator = _settings_game.locale.digit_decimal_separator; - if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator; + if (decimal_separator == nullptr) decimal_separator = _langpack->digit_decimal_separator; buff += seprintf(buff, last, "%s", decimal_separator); } @@ -346,7 +345,7 @@ static char *FormatNumber(char *buff, int64 number, const char *last, const char static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0) { const char *separator = _settings_game.locale.digit_group_separator; - if (separator == NULL) separator = _langpack->digit_group_separator; + if (separator == nullptr) separator = _langpack->digit_group_separator; return FormatNumber(buff, number, last, separator, 1, fractional_digits); } @@ -385,7 +384,7 @@ static char *FormatBytes(char *buff, int64 number, const char *last) } const char *decimal_separator = _settings_game.locale.digit_decimal_separator; - if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator; + if (decimal_separator == nullptr) decimal_separator = _langpack->digit_decimal_separator; if (number < 1024) { id = 0; @@ -479,8 +478,8 @@ static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money n } const char *separator = _settings_game.locale.digit_group_separator_currency; - if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator; - if (separator == NULL) separator = _langpack->digit_group_separator_currency; + if (separator == nullptr && !StrEmpty(_currency->separator)) separator = _currency->separator; + if (separator == nullptr) separator = _langpack->digit_group_separator_currency; buff = FormatNumber(buff, number, last, separator); buff = strecpy(buff, multiplier, last); @@ -938,7 +937,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg char buf[256]; bool old_sgd = _scan_for_gender_data; _scan_for_gender_data = true; - StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL); + StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, nullptr); p = FormatString(buf, input, &tmp_params, lastof(buf)); _scan_for_gender_data = old_sgd; *p = '\0'; @@ -1017,8 +1016,8 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg if (game_script && GetStringTab(str) != TEXT_TAB_GAMESCRIPT_START) break; /* WARNING. It's prohibited for the included string to consume any arguments. * For included strings that consume argument, you should use STRING1, STRING2 etc. - * To debug stuff you can set argv to NULL and it will tell you */ - StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), NULL); + * To debug stuff you can set argv to nullptr and it will tell you */ + StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), nullptr); buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script); next_substr_case_index = 0; break; @@ -1271,9 +1270,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_COMPANY_NAME: { // {COMPANY} const Company *c = Company::GetIfValid(args->GetInt32()); - if (c == NULL) break; + if (c == nullptr) break; - if (c->name != NULL) { + if (c->name != nullptr) { int64 args_array[] = {(int64)(size_t)c->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1308,7 +1307,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg } const Depot *d = Depot::Get(args->GetInt32()); - if (d->name != NULL) { + if (d->name != nullptr) { int64 args_array[] = {(int64)(size_t)d->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1322,14 +1321,14 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_ENGINE_NAME: { // {ENGINE} const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME)); - if (e == NULL) break; + if (e == nullptr) break; - if (e->name != NULL && e->IsEnabled()) { + if (e->name != nullptr && e->IsEnabled()) { int64 args_array[] = {(int64)(size_t)e->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { - StringParameters tmp_params(NULL, 0, NULL); + StringParameters tmp_params(nullptr, 0, nullptr); buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last); } break; @@ -1337,9 +1336,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_GROUP_NAME: { // {GROUP} const Group *g = Group::GetIfValid(args->GetInt32()); - if (g == NULL) break; + if (g == nullptr) break; - if (g->name != NULL) { + if (g->name != nullptr) { int64 args_array[] = {(int64)(size_t)g->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1354,12 +1353,12 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_INDUSTRY_NAME: { // {INDUSTRY} const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME)); - if (i == NULL) break; + if (i == nullptr) break; if (_scan_for_gender_data) { /* Gender is defined by the industry type. * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */ - StringParameters tmp_params(NULL, 0, NULL); + StringParameters tmp_params(nullptr, 0, nullptr); buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index); } else { /* First print the town name and the industry type name. */ @@ -1374,9 +1373,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME} const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME)); - if (c == NULL) break; + if (c == nullptr) break; - if (c->president_name != NULL) { + if (c->president_name != nullptr) { int64 args_array[] = {(int64)(size_t)c->president_name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1392,16 +1391,16 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg StationID sid = args->GetInt32(SCC_STATION_NAME); const Station *st = Station::GetIfValid(sid); - if (st == NULL) { + if (st == nullptr) { /* The station doesn't exist anymore. The only place where we might * be "drawing" an invalid station is in the case of cargo that is * in transit. */ - StringParameters tmp_params(NULL, 0, NULL); + StringParameters tmp_params(nullptr, 0, nullptr); buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last); break; } - if (st->name != NULL) { + if (st->name != nullptr) { int64 args_array[] = {(int64)(size_t)st->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1429,9 +1428,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_TOWN_NAME: { // {TOWN} const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME)); - if (t == NULL) break; + if (t == nullptr) break; - if (t->name != NULL) { + if (t->name != nullptr) { int64 args_array[] = {(int64)(size_t)t->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1443,9 +1442,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_WAYPOINT_NAME: { // {WAYPOINT} Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME)); - if (wp == NULL) break; + if (wp == nullptr) break; - if (wp->name != NULL) { + if (wp->name != nullptr) { int64 args_array[] = {(int64)(size_t)wp->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1461,9 +1460,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_VEHICLE_NAME: { // {VEHICLE} const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME)); - if (v == NULL) break; + if (v == nullptr) break; - if (v->name != NULL) { + if (v->name != nullptr) { int64 args_array[] = {(int64)(size_t)v->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); @@ -1487,14 +1486,14 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg case SCC_SIGN_NAME: { // {SIGN} const Sign *si = Sign::GetIfValid(args->GetInt32()); - if (si == NULL) break; + if (si == nullptr) break; - if (si->name != NULL) { + if (si->name != nullptr) { int64 args_array[] = {(int64)(size_t)si->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { - StringParameters tmp_params(NULL, 0, NULL); + StringParameters tmp_params(nullptr, 0, nullptr); buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last); } break; @@ -1674,7 +1673,7 @@ static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, c } /* resolution size? */ - if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) { + if (IsInsideBS(ind, (SPECSTR_RESOLUTION_START - 0x70E4), _resolutions.size())) { int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4); buff += seprintf( buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height @@ -1685,11 +1684,7 @@ static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, c NOT_REACHED(); } -#ifdef ENABLE_NETWORK extern void SortNetworkLanguages(); -#else /* ENABLE_NETWORK */ -static inline void SortNetworkLanguages() {} -#endif /* ENABLE_NETWORK */ /** * Check whether the header is a valid header for OpenTTD. @@ -1722,7 +1717,7 @@ bool ReadLanguagePack(const LanguageMetadata *lang) /* Current language pack */ size_t len; LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20); - if (lang_pack == NULL) return false; + if (lang_pack == nullptr) return false; /* End of read data (+ terminating zero added in ReadFileToMem()) */ const char *end = (char *)lang_pack + len + 1; @@ -1800,24 +1795,24 @@ bool ReadLanguagePack(const LanguageMetadata *lang) MacOSSetCurrentLocaleName(_current_language->isocode); #endif -#ifdef WITH_ICU_SORT +#ifdef WITH_ICU_I18N /* Delete previous collator. */ - if (_current_collator != NULL) { + if (_current_collator != nullptr) { delete _current_collator; - _current_collator = NULL; + _current_collator = nullptr; } /* Create a collator instance for our current locale. */ UErrorCode status = U_ZERO_ERROR; _current_collator = icu::Collator::createInstance(icu::Locale(_current_language->isocode), status); /* Sort number substrings by their numerical value. */ - if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status); + if (_current_collator != nullptr) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status); /* Avoid using the collator if it is not correctly set. */ if (U_FAILURE(status)) { delete _current_collator; - _current_collator = NULL; + _current_collator = nullptr; } -#endif /* WITH_ICU_SORT */ +#endif /* WITH_ICU_I18N */ /* Some lists need to be sorted again after a language change. */ ReconsiderGameScriptLanguage(); @@ -1825,9 +1820,7 @@ bool ReadLanguagePack(const LanguageMetadata *lang) SortIndustryTypes(); BuildIndustriesLegend(); SortNetworkLanguages(); -#ifdef ENABLE_NETWORK BuildContentTypeStringList(); -#endif /* ENABLE_NETWORK */ InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window. InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window. InvalidateWindowClassesData(WC_ROADVEH_LIST); // Road vehicle group window. @@ -1847,22 +1840,22 @@ bool ReadLanguagePack(const LanguageMetadata *lang) * First check some default values, after this one we passed ourselves * and if none exist return the value for $LANG * @param param environment variable to check conditionally if default ones are not - * set. Pass NULL if you don't want additional checks. - * @return return string containing current charset, or NULL if not-determinable + * set. Pass nullptr if you don't want additional checks. + * @return return string containing current charset, or nullptr if not-determinable */ const char *GetCurrentLocale(const char *param) { const char *env; env = getenv("LANGUAGE"); - if (env != NULL) return env; + if (env != nullptr) return env; env = getenv("LC_ALL"); - if (env != NULL) return env; + if (env != nullptr) return env; - if (param != NULL) { + if (param != nullptr) { env = getenv(param); - if (env != NULL) return env; + if (env != nullptr) return env; } return getenv("LANG"); @@ -1871,28 +1864,28 @@ const char *GetCurrentLocale(const char *param) const char *GetCurrentLocale(const char *param); #endif /* !(defined(_WIN32) || defined(__APPLE__)) */ -int CDECL StringIDSorter(const StringID *a, const StringID *b) +bool StringIDSorter(const StringID &a, const StringID &b) { char stra[512]; char strb[512]; - GetString(stra, *a, lastof(stra)); - GetString(strb, *b, lastof(strb)); + GetString(stra, a, lastof(stra)); + GetString(strb, b, lastof(strb)); - return strnatcmp(stra, strb); + return strnatcmp(stra, strb) < 0; } /** * Get the language with the given NewGRF language ID. * @param newgrflangid NewGRF languages ID to check. - * @return The language's metadata, or NULL if it is not known. + * @return The language's metadata, or nullptr if it is not known. */ const LanguageMetadata *GetLanguage(byte newgrflangid) { - for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) { - if (newgrflangid == lang->newgrflangid) return lang; + for (const LanguageMetadata &lang : _languages) { + if (newgrflangid == lang.newgrflangid) return ⟨ } - return NULL; + return nullptr; } /** @@ -1904,7 +1897,7 @@ const LanguageMetadata *GetLanguage(byte newgrflangid) static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr) { FILE *f = fopen(file, "rb"); - if (f == NULL) return false; + if (f == nullptr) return false; size_t read = fread(hdr, sizeof(*hdr), 1, f); fclose(f); @@ -1926,14 +1919,14 @@ static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr) static void GetLanguageList(const char *path) { DIR *dir = ttd_opendir(path); - if (dir != NULL) { + if (dir != nullptr) { struct dirent *dirent; - while ((dirent = readdir(dir)) != NULL) { + while ((dirent = readdir(dir)) != nullptr) { const char *d_name = FS2OTTD(dirent->d_name); const char *extension = strrchr(d_name, '.'); /* Not a language file */ - if (extension == NULL || strcmp(extension, ".lng") != 0) continue; + if (extension == nullptr || strcmp(extension, ".lng") != 0) continue; LanguageMetadata lmd; seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name); @@ -1941,10 +1934,10 @@ static void GetLanguageList(const char *path) /* Check whether the file is of the correct version */ if (!GetLanguageFileHeader(lmd.file, &lmd)) { DEBUG(misc, 3, "%s is not a valid language file", lmd.file); - } else if (GetLanguage(lmd.newgrflangid) != NULL) { + } else if (GetLanguage(lmd.newgrflangid) != nullptr) { DEBUG(misc, 3, "%s's language ID is already known", lmd.file); } else { - *_languages.Append() = lmd; + _languages.push_back(lmd); } } closedir(dir); @@ -1964,36 +1957,36 @@ void InitializeLanguagePacks() FioAppendDirectory(path, lastof(path), sp, LANG_DIR); GetLanguageList(path); } - if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)"); + if (_languages.size() == 0) usererror("No available language packs (invalid versions?)"); /* Acquire the locale of the current system */ const char *lang = GetCurrentLocale("LC_MESSAGES"); - if (lang == NULL) lang = "en_GB"; + if (lang == nullptr) lang = "en_GB"; - const LanguageMetadata *chosen_language = NULL; ///< Matching the language in the configuration file or the current locale - const LanguageMetadata *language_fallback = NULL; ///< Using pt_PT for pt_BR locale when pt_BR is not available - const LanguageMetadata *en_GB_fallback = _languages.Begin(); ///< Fallback when no locale-matching language has been found + const LanguageMetadata *chosen_language = nullptr; ///< Matching the language in the configuration file or the current locale + const LanguageMetadata *language_fallback = nullptr; ///< Using pt_PT for pt_BR locale when pt_BR is not available + const LanguageMetadata *en_GB_fallback = _languages.data(); ///< Fallback when no locale-matching language has been found /* Find a proper language. */ - for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) { + for (const LanguageMetadata &lng : _languages) { /* We are trying to find a default language. The priority is by * configuration file, local environment and last, if nothing found, * English. */ - const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1; + const char *lang_file = strrchr(lng.file, PATHSEPCHAR) + 1; if (strcmp(lang_file, _config_language_file) == 0) { - chosen_language = lng; + chosen_language = &lng; break; } - if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback = lng; - if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng; - if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng; + if (strcmp (lng.isocode, "en_GB") == 0) en_GB_fallback = &lng; + if (strncmp(lng.isocode, lang, 5) == 0) chosen_language = &lng; + if (strncmp(lng.isocode, lang, 2) == 0) language_fallback = &lng; } /* We haven't found the language in the config nor the one in the locale. * Now we set it to one of the fallback languages */ - if (chosen_language == NULL) { - chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback; + if (chosen_language == nullptr) { + chosen_language = (language_fallback != nullptr) ? language_fallback : en_GB_fallback; } if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file); @@ -2012,7 +2005,7 @@ const char *GetCurrentLanguageIsoCode() * Check whether there are glyphs missing in the current language. * @param[out] str Pointer to an address for storing the text pointer. * @return If glyphs are missing, return \c true, else return \c false. - * @post If \c true is returned and str is not NULL, *str points to a string that is found to contain at least one missing glyph. + * @post If \c true is returned and str is not nullptr, *str points to a string that is found to contain at least one missing glyph. */ bool MissingGlyphSearcher::FindMissingGlyphs(const char **str) { @@ -2024,9 +2017,9 @@ bool MissingGlyphSearcher::FindMissingGlyphs(const char **str) } this->Reset(); - for (const char *text = this->NextString(); text != NULL; text = this->NextString()) { + for (const char *text = this->NextString(); text != nullptr; text = this->NextString()) { FontSize size = this->DefaultSize(); - if (str != NULL) *str = text; + if (str != nullptr) *str = text; for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) { if (c >= SCC_FIRST_FONT && c <= SCC_LAST_FONT) { size = (FontSize)(c - SCC_FIRST_FONT); @@ -2044,20 +2037,20 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher { uint i; ///< Iterator for the primary language tables. uint j; ///< Iterator for the secondary language tables. - /* virtual */ void Reset() + void Reset() override { this->i = 0; this->j = 0; } - /* virtual */ FontSize DefaultSize() + FontSize DefaultSize() override { return FS_NORMAL; } - /* virtual */ const char *NextString() + const char *NextString() override { - if (this->i >= TEXT_TAB_END) return NULL; + if (this->i >= TEXT_TAB_END) return nullptr; const char *ret = _langpack_offs[_langtab_start[this->i] + this->j]; @@ -2070,18 +2063,23 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher { return ret; } - /* virtual */ bool Monospace() + bool Monospace() override { return false; } - /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name) + void SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data) override { -#ifdef WITH_FREETYPE +#if defined(WITH_FREETYPE) || defined(_WIN32) strecpy(settings->small.font, font_name, lastof(settings->small.font)); strecpy(settings->medium.font, font_name, lastof(settings->medium.font)); strecpy(settings->large.font, font_name, lastof(settings->large.font)); -#endif /* WITH_FREETYPE */ + + free(settings->medium.os_handle); // Only free one, they are all the same pointer. + settings->small.os_handle = os_data; + settings->medium.os_handle = os_data; + settings->large.os_handle = os_data; +#endif } }; @@ -2096,22 +2094,28 @@ class LanguagePackGlyphSearcher : public MissingGlyphSearcher { * been added. * @param base_font Whether to look at the base font as well. * @param searcher The methods to use to search for strings to check. - * If NULL the loaded language pack searcher is used. + * If nullptr the loaded language pack searcher is used. */ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher) { static LanguagePackGlyphSearcher pack_searcher; - if (searcher == NULL) searcher = &pack_searcher; - bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL); -#ifdef WITH_FREETYPE + if (searcher == nullptr) searcher = &pack_searcher; + bool bad_font = !base_font || searcher->FindMissingGlyphs(nullptr); +#if defined(WITH_FREETYPE) || defined(_WIN32) if (bad_font) { /* We found an unprintable character... lets try whether we can find * a fallback font that can print the characters in the current language. */ FreeTypeSettings backup; memcpy(&backup, &_freetype, sizeof(backup)); + _freetype.mono.os_handle = nullptr; + _freetype.medium.os_handle = nullptr; + bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher); + free(_freetype.mono.os_handle); + free(_freetype.medium.os_handle); + memcpy(&_freetype, &backup, sizeof(backup)); if (bad_font && base_font) { @@ -2142,7 +2146,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher) /* Update the font with cache */ LoadStringWidthTable(searcher->Monospace()); -#if !defined(WITH_ICU_LAYOUT) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA) +#if !defined(WITH_ICU_LX) && !defined(WITH_UNISCRIBE) && !defined(WITH_COCOA) /* * For right-to-left languages we need the ICU library. If * we do not have support for that library we warn the user @@ -2162,5 +2166,5 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher) SetDParamStr(0, err_str); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } -#endif /* !WITH_ICU_LAYOUT */ +#endif /* !WITH_ICU_LX */ } diff --git a/src/strings_func.h b/src/strings_func.h index 0da711bc4d..26ca56fbd5 100644 --- a/src/strings_func.h +++ b/src/strings_func.h @@ -60,9 +60,9 @@ static inline StringID MakeStringID(StringTab tab, uint index) } class StringParameters { - StringParameters *parent; ///< If not NULL, this instance references data from this parent instance. + StringParameters *parent; ///< If not nullptr, this instance references data from this parent instance. uint64 *data; ///< Array with the actual data. - WChar *type; ///< Array with type information about the data. Can be NULL when no type information is needed. See #StringControlCode. + WChar *type; ///< Array with type information about the data. Can be nullptr when no type information is needed. See #StringControlCode. public: uint offset; ///< Current offset in the data/type arrays. @@ -70,7 +70,7 @@ public: /** Create a new StringParameters instance. */ StringParameters(uint64 *data, uint num_param, WChar *type) : - parent(NULL), + parent(nullptr), data(data), type(type), offset(0), @@ -80,9 +80,9 @@ public: /** Create a new StringParameters instance. */ template StringParameters(int64 (&data)[Tnum_param]) : - parent(NULL), + parent(nullptr), data((uint64 *)data), - type(NULL), + type(nullptr), offset(0), num_param(Tnum_param) { @@ -100,8 +100,8 @@ public: num_param(size) { assert(size <= parent.GetDataLeft()); - if (parent.type == NULL) { - this->type = NULL; + if (parent.type == nullptr) { + this->type = nullptr; } else { this->type = parent.type + parent.offset; } @@ -109,7 +109,7 @@ public: ~StringParameters() { - if (this->parent != NULL) { + if (this->parent != nullptr) { this->parent->offset += this->num_param; } } @@ -148,7 +148,7 @@ public: /** Does this instance store information about the type of the parameters. */ bool HasTypeInformation() const { - return this->type != NULL; + return this->type != nullptr; } /** Get the type of a specific element. */ @@ -238,7 +238,7 @@ extern TextDirection _current_text_dir; ///< Text direction of the currently sel void InitializeLanguagePacks(); const char *GetCurrentLanguageIsoCode(); -int CDECL StringIDSorter(const StringID *a, const StringID *b); +bool StringIDSorter(const StringID &a, const StringID &b); /** * A searcher for missing glyphs. @@ -250,7 +250,7 @@ public: /** * Get the next string to search through. - * @return The next string or NULL if there is none. + * @return The next string or nullptr if there is none. */ virtual const char *NextString() = 0; @@ -275,12 +275,13 @@ public: * Set the right font names. * @param settings The settings to modify. * @param font_name The new font name. + * @param os_data Opaque pointer to OS-specific data. */ - virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name) = 0; + virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name, const void *os_data = nullptr) = 0; bool FindMissingGlyphs(const char **str); }; -void CheckForMissingGlyphs(bool base_font = true, MissingGlyphSearcher *search = NULL); +void CheckForMissingGlyphs(bool base_font = true, MissingGlyphSearcher *search = nullptr); #endif /* STRINGS_FUNC_H */ diff --git a/src/strings_type.h b/src/strings_type.h index aa3ed788c3..11eeef1532 100644 --- a/src/strings_type.h +++ b/src/strings_type.h @@ -93,9 +93,8 @@ enum SpecialStrings { SPECSTR_LANGUAGE_START = 0x7100, SPECSTR_LANGUAGE_END = SPECSTR_LANGUAGE_START + MAX_LANG - 1, - /* reserve 32 strings for various screen resolutions */ + /* reserve strings for various screen resolutions MUST BE THE LAST VALUE IN THIS ENUM */ SPECSTR_RESOLUTION_START = SPECSTR_LANGUAGE_END + 1, - SPECSTR_RESOLUTION_END = SPECSTR_RESOLUTION_START + 0x1F, }; #endif /* STRINGS_TYPE_H */ diff --git a/src/subsidy.cpp b/src/subsidy.cpp index 4e819fb4a7..711b918109 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -377,7 +377,7 @@ bool FindSubsidyIndustryCargoRoute() /* Select a random industry. */ const Industry *src_ind = Industry::GetRandom(); - if (src_ind == NULL) return false; + if (src_ind == nullptr) return false; uint trans, total; @@ -442,7 +442,7 @@ bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src) case ST_INDUSTRY: { /* Select a random industry. */ const Industry *dst_ind = Industry::GetRandom(); - if (dst_ind == NULL) return false; + if (dst_ind == nullptr) return false; /* The industry must accept the cargo */ bool valid = std::find(dst_ind->accepts_cargo, endof(dst_ind->accepts_cargo), cid) != endof(dst_ind->accepts_cargo); @@ -565,7 +565,7 @@ bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, /* Remember all towns near this station (at least one house in its catchment radius) * which are destination of subsidised path. Do that only if needed */ - SmallVector towns_near; + std::vector towns_near; if (!st->rect.IsEmpty()) { Subsidy *s; FOR_ALL_SUBSIDIES(s) { @@ -574,15 +574,11 @@ bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, if (s->cargo_type != cargo_type || s->src_type != src_type || s->src != src) continue; if (s->IsAwarded() && s->awarded != company) continue; - Rect rect = st->GetCatchmentRect(); - - for (int y = rect.top; y <= rect.bottom; y++) { - for (int x = rect.left; x <= rect.right; x++) { - TileIndex tile = TileXY(x, y); - if (!IsTileType(tile, MP_HOUSE)) continue; - const Town *t = Town::GetByTile(tile); - if (t->cache.part_of_subsidy & POS_DST) towns_near.Include(t); - } + BitmapTileIterator it(st->catchment_tiles); + for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { + if (!IsTileType(tile, MP_HOUSE)) continue; + const Town *t = Town::GetByTile(tile); + if (t->cache.part_of_subsidy & POS_DST) include(towns_near, t); } break; } @@ -597,18 +593,18 @@ bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, if (s->cargo_type == cargo_type && s->src_type == src_type && s->src == src && (!s->IsAwarded() || s->awarded == company)) { switch (s->dst_type) { case ST_INDUSTRY: - for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) { - if (s->dst == (*ip)->index) { - assert((*ip)->part_of_subsidy & POS_DST); + for (Industry *ind : st->industries_near) { + if (s->dst == ind->index) { + assert(ind->part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); } } break; case ST_TOWN: - for (const Town * const *tp = towns_near.Begin(); tp != towns_near.End(); tp++) { - if (s->dst == (*tp)->index) { - assert((*tp)->cache.part_of_subsidy & POS_DST); + for (const Town *tp : towns_near) { + if (s->dst == tp->index) { + assert(tp->cache.part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); } diff --git a/src/subsidy_base.h b/src/subsidy_base.h index f12fbc4b9b..a7f6f4f3ee 100644 --- a/src/subsidy_base.h +++ b/src/subsidy_base.h @@ -22,13 +22,13 @@ extern SubsidyPool _subsidy_pool; /** Struct about subsidies, offered and awarded */ struct Subsidy : SubsidyPool::PoolItem<&_subsidy_pool> { - CargoID cargo_type; ///< Cargo type involved in this subsidy, CT_INVALID for invalid subsidy - byte remaining; ///< Remaining months when this subsidy is valid - CompanyByte awarded; ///< Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone - SourceTypeByte src_type; ///< Source of subsidised path (ST_INDUSTRY or ST_TOWN) - SourceTypeByte dst_type; ///< Destination of subsidised path (ST_INDUSTRY or ST_TOWN) - SourceID src; ///< Index of source. Either TownID or IndustryID - SourceID dst; ///< Index of destination. Either TownID or IndustryID + CargoID cargo_type; ///< Cargo type involved in this subsidy, CT_INVALID for invalid subsidy + byte remaining; ///< Remaining months when this subsidy is valid + CompanyID awarded; ///< Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone + SourceType src_type; ///< Source of subsidised path (ST_INDUSTRY or ST_TOWN) + SourceType dst_type; ///< Destination of subsidised path (ST_INDUSTRY or ST_TOWN) + SourceID src; ///< Index of source. Either TownID or IndustryID + SourceID dst; ///< Index of destination. Either TownID or IndustryID /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) @@ -36,7 +36,7 @@ struct Subsidy : SubsidyPool::PoolItem<&_subsidy_pool> { inline Subsidy() { } /** - * (Empty) destructor has to be defined else operator delete might be called with NULL parameter + * (Empty) destructor has to be defined else operator delete might be called with nullptr parameter */ inline ~Subsidy() { } diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp index 04e5ae262b..e71b62f94f 100644 --- a/src/subsidy_gui.cpp +++ b/src/subsidy_gui.cpp @@ -38,7 +38,7 @@ struct SubsidyListWindow : Window { this->OnInvalidateData(0); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget != WID_SUL_PANEL) return; @@ -129,7 +129,7 @@ struct SubsidyListWindow : Window { return 3 + num_awarded + num_not_awarded; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_SUL_PANEL) return; Dimension d = maxdim(GetStringBoundingBox(STR_SUBSIDIES_OFFERED_TITLE), GetStringBoundingBox(STR_SUBSIDIES_SUBSIDISED_TITLE)); @@ -142,7 +142,7 @@ struct SubsidyListWindow : Window { *size = maxdim(*size, d); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_SUL_PANEL) return; @@ -207,7 +207,7 @@ struct SubsidyListWindow : Window { } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_SUL_PANEL); } @@ -217,7 +217,7 @@ struct SubsidyListWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->vscroll->SetCount(this->CountLines()); diff --git a/src/subsidy_type.h b/src/subsidy_type.h index 83c33a00a9..968351ffb3 100644 --- a/src/subsidy_type.h +++ b/src/subsidy_type.h @@ -15,14 +15,11 @@ #include "core/enum_type.hpp" /** What part of a subsidy is something? */ -enum PartOfSubsidy { +enum PartOfSubsidy : byte { POS_NONE = 0, ///< nothing POS_SRC = 1 << 0, ///< bit 0 set -> town/industry is source of subsidised path POS_DST = 1 << 1, ///< bit 1 set -> town/industry is destination of subsidised path }; -/** Helper to store the PartOfSubsidy data in a single byte. */ -typedef SimpleTinyEnumT PartOfSubsidyByte; - DECLARE_ENUM_AS_BIT_SET(PartOfSubsidy) typedef uint16 SubsidyID; ///< ID of a subsidy diff --git a/src/table/airport_defaults.h b/src/table/airport_defaults.h index 593e157ac3..89989ee988 100644 --- a/src/table/airport_defaults.h +++ b/src/table/airport_defaults.h @@ -386,7 +386,7 @@ static const Direction _default_airports_rotation[] = { /** AirportSpec definition for airports without any depot. */ #define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \ - AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), NULL, 0, \ + AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), nullptr, 0, \ size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true) /** AirportSpec definition for airports with at least one depot. */ @@ -405,12 +405,12 @@ extern const AirportSpec _origin_airport_specs[] = { AS(helidepot, 2, 2, 1976, MAX_YEAR, 4, 2, 7, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELIDEPOT, SPR_AIRPORT_PREVIEW_HELIDEPOT), AS(intercontinental, 9, 11, 2002, MAX_YEAR, 10, 25, 72, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERCONTINENTAL, SPR_AIRPORT_PREVIEW_INTERCONTINENTAL), AS(helistation, 4, 2, 1980, MAX_YEAR, 4, 3, 14, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELISTATION, SPR_AIRPORT_PREVIEW_HELISTATION), - AS_GENERIC(&_airportfta_oilrig, NULL, _default_airports_rotation, 0, NULL, 0, 1, 1, 0, 4, 0, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false), + AS_GENERIC(&_airportfta_oilrig, nullptr, _default_airports_rotation, 0, nullptr, 0, 1, 1, 0, 4, 0, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false), }; assert_compile(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs)); -const AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, NULL, _default_airports_rotation, 0, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false); +const AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, nullptr, _default_airports_rotation, 0, nullptr, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false); #undef AS #undef AS_ND diff --git a/src/table/airport_movement.h b/src/table/airport_movement.h index d9030f652c..010ceef38a 100644 --- a/src/table/airport_movement.h +++ b/src/table/airport_movement.h @@ -34,7 +34,7 @@ struct AirportFTAbuildup { * @param flags Movement flags. * @param dir Direction. */ -#define AMD(x, y, flags, dir) { x, y, flags, {dir} } +#define AMD(x, y, flags, dir) { x, y, flags, dir } /** Dummy airport. */ static const AirportMovingData _airport_moving_data_dummy[] = { @@ -71,10 +71,10 @@ static const AirportMovingData _airport_moving_data_country[22] = { }; /** Commuter Airfield (small) 5x4. */ -static const AirportMovingData _airport_moving_data_commuter[37] = { +static const AirportMovingData _airport_moving_data_commuter[38] = { AMD( 69, 3, AMED_EXACTPOS, DIR_SE), // 00 In Hangar AMD( 72, 22, 0, DIR_N ), // 01 Taxi to right outside depot - AMD( 8, 22, AMED_EXACTPOS, DIR_SW), // 01 Taxi to right outside depot + AMD( 8, 22, AMED_EXACTPOS, DIR_SW), // 02 Taxi to right outside depot AMD( 24, 36, AMED_EXACTPOS, DIR_SE), // 03 Terminal 1 AMD( 40, 36, AMED_EXACTPOS, DIR_SE), // 04 Terminal 2 AMD( 56, 36, AMED_EXACTPOS, DIR_SE), // 05 Terminal 3 @@ -108,8 +108,9 @@ static const AirportMovingData _airport_moving_data_commuter[37] = { AMD( 48, 8, AMED_HELI_RAISE, DIR_N ), // 32 Takeoff Helipad2 AMD( 64, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 33 Go to position for Hangarentrance in air AMD( 64, 22, AMED_HELI_LOWER, DIR_N ), // 34 Land in front of hangar - AMD( 40, 8, AMED_EXACTPOS, DIR_N ), // pre-helitakeoff helipad 1 - AMD( 56, 8, AMED_EXACTPOS, DIR_N ), // pre-helitakeoff helipad 2 + AMD( 40, 8, AMED_EXACTPOS, DIR_N ), // 35 pre-helitakeoff helipad 1 + AMD( 56, 8, AMED_EXACTPOS, DIR_N ), // 36 pre-helitakeoff helipad 2 + AMD( 64, 25, AMED_HELI_RAISE, DIR_N ), // 37 Take off in front of hangar }; /** City Airport (large) 6x6. */ @@ -179,11 +180,11 @@ static const AirportMovingData _airport_moving_data_metropolitan[28] = { }; /** International Airport (international) - 2 runways, 6 terminals, dedicated helipad. */ -static const AirportMovingData _airport_moving_data_international[51] = { +static const AirportMovingData _airport_moving_data_international[53] = { AMD( 7, 55, AMED_EXACTPOS, DIR_SE), // 00 In Hangar 1 AMD( 100, 21, AMED_EXACTPOS, DIR_SE), // 01 In Hangar 2 - AMD( 7, 70, 0, DIR_N ), // 02 Taxi to right outside depot - AMD( 100, 36, 0, DIR_N ), // 03 Taxi to right outside depot + AMD( 7, 70, 0, DIR_N ), // 02 Taxi to right outside depot (Hangar 1) + AMD( 100, 36, 0, DIR_N ), // 03 Taxi to right outside depot (Hangar 2) AMD( 38, 70, AMED_EXACTPOS, DIR_SW), // 04 Terminal 1 AMD( 38, 54, AMED_EXACTPOS, DIR_SW), // 05 Terminal 2 AMD( 38, 38, AMED_EXACTPOS, DIR_SW), // 06 Terminal 3 @@ -232,6 +233,8 @@ static const AirportMovingData _airport_moving_data_international[51] = { AMD( 104, 55, AMED_HELI_RAISE, DIR_N ), // 48 Takeoff Helipad2 AMD( 104, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 49 Go to position for Hangarentrance in air AMD( 104, 32, AMED_HELI_LOWER, DIR_N ), // 50 Land in HANGAR2_AREA to go to hangar + AMD( 7, 70, AMED_HELI_RAISE, DIR_N ), // 51 Takeoff from HANGAR1_AREA + AMD( 100, 36, AMED_HELI_RAISE, DIR_N ), // 52 Takeoff from HANGAR2_AREA }; /** Intercontinental Airport - 4 runways, 8 terminals, 2 dedicated helipads. */ @@ -408,11 +411,11 @@ static const AirportMovingData _airport_moving_data_oilrig[9] = { /////**********Movement Machine on Airports*********************/////// static const byte _airport_entries_dummy[] = {0, 1, 2, 3}; static const AirportFTAbuildup _airport_fta_dummy[] = { - { 0, 0, 0, 3}, - { 1, 0, 0, 0}, - { 2, 0, 0, 1}, - { 3, 0, 0, 2}, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 0, TO_ALL, 0, 3}, + { 1, TO_ALL, 0, 0}, + { 2, TO_ALL, 0, 1}, + { 3, TO_ALL, 0, 2}, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; /* First element of terminals array tells us how many depots there are (to know size of array) @@ -422,11 +425,11 @@ static const byte _airport_terminal_country[] = {1, 2}; static const byte _airport_entries_country[] = {16, 15, 18, 17}; static const AirportFTAbuildup _airport_fta_country[] = { { 0, HANGAR, NOTHING_block, 1 }, - { 1, 255, AIRPORT_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM1, TERM1_block, 2 }, { 1, TERM2, 0, 4 }, { 1, HELITAKEOFF, 0, 19 }, { 1, 0, 0, 6 }, + { 1, TERMGROUP, AIRPORT_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM1, TERM1_block, 2 }, { 1, TERM2, 0, 4 }, { 1, HELITAKEOFF, 0, 19 }, { 1, TO_ALL, 0, 6 }, { 2, TERM1, TERM1_block, 1 }, { 3, TERM2, TERM2_block, 5 }, - { 4, 255, AIRPORT_BUSY_block, 0 }, { 4, TERM2, 0, 5 }, { 4, HANGAR, 0, 1 }, { 4, TAKEOFF, 0, 6 }, { 4, HELITAKEOFF, 0, 1 }, - { 5, 255, AIRPORT_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, 0, 0, 4 }, + { 4, TERMGROUP, AIRPORT_BUSY_block, 0 }, { 4, TERM2, 0, 5 }, { 4, HANGAR, 0, 1 }, { 4, TAKEOFF, 0, 6 }, { 4, HELITAKEOFF, 0, 1 }, + { 5, TERMGROUP, AIRPORT_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TO_ALL, 0, 4 }, { 6, 0, AIRPORT_BUSY_block, 7 }, /* takeoff */ { 7, TAKEOFF, AIRPORT_BUSY_block, 8 }, @@ -435,82 +438,83 @@ static const AirportFTAbuildup _airport_fta_country[] = { /* landing */ { 10, FLYING, NOTHING_block, 15 }, { 10, LANDING, 0, 11 }, { 10, HELILANDING, 0, 20 }, { 11, LANDING, AIRPORT_BUSY_block, 12 }, - { 12, 0, AIRPORT_BUSY_block, 13 }, - { 13, ENDLANDING, AIRPORT_BUSY_block, 14 }, { 13, TERM2, 0, 5 }, { 13, 0, 0, 14 }, - { 14, 0, AIRPORT_BUSY_block, 1 }, + { 12, TO_ALL, AIRPORT_BUSY_block, 13 }, + { 13, ENDLANDING, AIRPORT_BUSY_block, 14 }, { 13, TERM2, 0, 5 }, { 13, TO_ALL, 0, 14 }, + { 14, TO_ALL, AIRPORT_BUSY_block, 1 }, /* In air */ - { 15, 0, NOTHING_block, 16 }, - { 16, 0, NOTHING_block, 17 }, - { 17, 0, NOTHING_block, 18 }, - { 18, 0, NOTHING_block, 10 }, + { 15, TO_ALL, NOTHING_block, 16 }, + { 16, TO_ALL, NOTHING_block, 17 }, + { 17, TO_ALL, NOTHING_block, 18 }, + { 18, TO_ALL, NOTHING_block, 10 }, { 19, HELITAKEOFF, NOTHING_block, 0 }, { 20, HELILANDING, AIRPORT_BUSY_block, 21 }, { 21, HELIENDLANDING, AIRPORT_BUSY_block, 1 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_commuter[] = { {{4, 0}, DIR_SE, 0} }; static const byte _airport_terminal_commuter[] = { 1, 3 }; static const byte _airport_entries_commuter[] = {22, 21, 24, 23}; static const AirportFTAbuildup _airport_fta_commuter[] = { - { 0, HANGAR, NOTHING_block, 1 }, { 0, HELITAKEOFF, HELIPAD2_block, 1 }, { 0, 0, 0, 1 }, - { 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TAKEOFF, 0, 11 }, { 1, TERM1, TAXIWAY_BUSY_block, 10 }, { 1, TERM2, TAXIWAY_BUSY_block, 10 }, { 1, TERM3, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD1, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD2, TAXIWAY_BUSY_block, 10 }, { 1, HELITAKEOFF, TAXIWAY_BUSY_block, 10 }, { 1, 0, 0, 0 }, - { 2, 255, AIRPORT_ENTRANCE_block, 2 }, { 2, HANGAR, 0, 8 }, { 2, TERM1, 0, 8 }, { 2, TERM2, 0, 8 }, { 2, TERM3, 0, 8 }, { 2, HELIPAD1, 0, 8 }, { 2, HELIPAD2, 0, 8 }, { 2, HELITAKEOFF, 0, 8 }, { 2, 0, 0, 2 }, - { 3, TERM1, TERM1_block, 8 }, { 3, HANGAR, 0, 8 }, { 3, TAKEOFF, 0, 8 }, { 3, 0, 0, 3 }, - { 4, TERM2, TERM2_block, 9 }, { 4, HANGAR, 0, 9 }, { 4, TAKEOFF, 0, 9 }, { 4, 0, 0, 4 }, - { 5, TERM3, TERM3_block, 10 }, { 5, HANGAR, 0, 10 }, { 5, TAKEOFF, 0, 10 }, { 5, 0, 0, 5 }, + { 0, HANGAR, NOTHING_block, 1 }, { 0, HELITAKEOFF, TAXIWAY_BUSY_block, 1 }, { 0, TO_ALL, 0, 1 }, + { 1, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TAKEOFF, 0, 11 }, { 1, TERM1, TAXIWAY_BUSY_block, 10 }, { 1, TERM2, TAXIWAY_BUSY_block, 10 }, { 1, TERM3, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD1, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD2, TAXIWAY_BUSY_block, 10 }, { 1, HELITAKEOFF, TAXIWAY_BUSY_block, 37 }, { 1, TO_ALL, 0, 0 }, + { 2, TERMGROUP, AIRPORT_ENTRANCE_block, 2 }, { 2, HANGAR, 0, 8 }, { 2, TERM1, 0, 8 }, { 2, TERM2, 0, 8 }, { 2, TERM3, 0, 8 }, { 2, HELIPAD1, 0, 8 }, { 2, HELIPAD2, 0, 8 }, { 2, HELITAKEOFF, 0, 8 }, { 2, TO_ALL, 0, 2 }, + { 3, TERM1, TERM1_block, 8 }, { 3, HANGAR, 0, 8 }, { 3, TAKEOFF, 0, 8 }, { 3, TO_ALL, 0, 3 }, + { 4, TERM2, TERM2_block, 9 }, { 4, HANGAR, 0, 9 }, { 4, TAKEOFF, 0, 9 }, { 4, TO_ALL, 0, 4 }, + { 5, TERM3, TERM3_block, 10 }, { 5, HANGAR, 0, 10 }, { 5, TAKEOFF, 0, 10 }, { 5, TO_ALL, 0, 5 }, { 6, HELIPAD1, HELIPAD1_block, 6 }, { 6, HANGAR, TAXIWAY_BUSY_block, 9 }, { 6, HELITAKEOFF, 0, 35 }, { 7, HELIPAD2, HELIPAD2_block, 7 }, { 7, HANGAR, TAXIWAY_BUSY_block, 10 }, { 7, HELITAKEOFF, 0, 36 }, - { 8, 255, TAXIWAY_BUSY_block, 8 }, { 8, TAKEOFF, TAXIWAY_BUSY_block, 9 }, { 8, HANGAR, TAXIWAY_BUSY_block, 9 }, { 8, TERM1, TERM1_block, 3 }, { 8, 0, TAXIWAY_BUSY_block, 9 }, - { 9, 255, TAXIWAY_BUSY_block, 9 }, { 9, TAKEOFF, TAXIWAY_BUSY_block, 10 }, { 9, HANGAR, TAXIWAY_BUSY_block, 10 }, { 9, TERM2, TERM2_block, 4 }, { 9, HELIPAD1, HELIPAD1_block, 6 }, { 9, HELITAKEOFF, HELIPAD1_block, 6 }, { 9, TERM1, TAXIWAY_BUSY_block, 8 }, { 9, 0, TAXIWAY_BUSY_block, 10 }, - { 10, 255, TAXIWAY_BUSY_block, 10 }, { 10, TERM3, TERM3_block, 5 }, { 10, HELIPAD1, 0, 9 }, { 10, HELIPAD2, HELIPAD2_block, 7 }, { 10, HELITAKEOFF, HELIPAD2_block, 7 }, { 10, TAKEOFF, TAXIWAY_BUSY_block, 1 }, { 10, HANGAR, TAXIWAY_BUSY_block, 1 }, { 10, 0, TAXIWAY_BUSY_block, 9 }, - { 11, 0, OUT_WAY_block, 12 }, + { 8, TERMGROUP, TAXIWAY_BUSY_block, 8 }, { 8, TAKEOFF, TAXIWAY_BUSY_block, 9 }, { 8, HANGAR, TAXIWAY_BUSY_block, 9 }, { 8, TERM1, TERM1_block, 3 }, { 8, TO_ALL, TAXIWAY_BUSY_block, 9 }, + { 9, TERMGROUP, TAXIWAY_BUSY_block, 9 }, { 9, TAKEOFF, TAXIWAY_BUSY_block, 10 }, { 9, HANGAR, TAXIWAY_BUSY_block, 10 }, { 9, TERM2, TERM2_block, 4 }, { 9, HELIPAD1, HELIPAD1_block, 6 }, { 9, HELITAKEOFF, HELIPAD1_block, 6 }, { 9, TERM1, TAXIWAY_BUSY_block, 8 }, { 9, TO_ALL, TAXIWAY_BUSY_block, 10 }, + { 10, TERMGROUP, TAXIWAY_BUSY_block, 10 }, { 10, TERM3, TERM3_block, 5 }, { 10, HELIPAD1, 0, 9 }, { 10, HELIPAD2, HELIPAD2_block, 7 }, { 10, HELITAKEOFF, 0, 1 }, { 10, TAKEOFF, TAXIWAY_BUSY_block, 1 }, { 10, HANGAR, TAXIWAY_BUSY_block, 1 }, { 10, TO_ALL, TAXIWAY_BUSY_block, 9 }, + { 11, TO_ALL, OUT_WAY_block, 12 }, /* takeoff */ { 12, TAKEOFF, RUNWAY_IN_OUT_block, 13 }, - { 13, 0, RUNWAY_IN_OUT_block, 14 }, + { 13, TO_ALL, RUNWAY_IN_OUT_block, 14 }, { 14, STARTTAKEOFF, RUNWAY_IN_OUT_block, 15 }, { 15, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 16, FLYING, NOTHING_block, 21 }, { 16, LANDING, IN_WAY_block, 17 }, { 16, HELILANDING, 0, 25 }, { 17, LANDING, RUNWAY_IN_OUT_block, 18 }, - { 18, 0, RUNWAY_IN_OUT_block, 19 }, - { 19, 0, RUNWAY_IN_OUT_block, 20 }, + { 18, TO_ALL, RUNWAY_IN_OUT_block, 19 }, + { 19, TO_ALL, RUNWAY_IN_OUT_block, 20 }, { 20, ENDLANDING, IN_WAY_block, 2 }, /* In Air */ - { 21, 0, NOTHING_block, 22 }, - { 22, 0, NOTHING_block, 23 }, - { 23, 0, NOTHING_block, 24 }, - { 24, 0, NOTHING_block, 16 }, + { 21, TO_ALL, NOTHING_block, 22 }, + { 22, TO_ALL, NOTHING_block, 23 }, + { 23, TO_ALL, NOTHING_block, 24 }, + { 24, TO_ALL, NOTHING_block, 16 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 25, HELILANDING, PRE_HELIPAD_block, 26 }, { 26, HELIENDLANDING, PRE_HELIPAD_block, 26 }, { 26, HELIPAD1, 0, 27 }, { 26, HELIPAD2, 0, 28 }, { 26, HANGAR, 0, 33 }, - { 27, 0, NOTHING_block, 29 }, // helipad1 approach - { 28, 0, NOTHING_block, 30 }, + { 27, TO_ALL, NOTHING_block, 29 }, // helipad1 approach + { 28, TO_ALL, NOTHING_block, 30 }, /* landing */ - { 29, 255, NOTHING_block, 0 }, { 29, HELIPAD1, HELIPAD1_block, 6 }, - { 30, 255, NOTHING_block, 0 }, { 30, HELIPAD2, HELIPAD2_block, 7 }, + { 29, TERMGROUP, NOTHING_block, 0 }, { 29, HELIPAD1, HELIPAD1_block, 6 }, + { 30, TERMGROUP, NOTHING_block, 0 }, { 30, HELIPAD2, HELIPAD2_block, 7 }, /* Helicopter -- takeoff */ { 31, HELITAKEOFF, NOTHING_block, 0 }, { 32, HELITAKEOFF, NOTHING_block, 0 }, - { 33, 0, TAXIWAY_BUSY_block, 34 }, // need to go to hangar when waiting in air - { 34, 0, TAXIWAY_BUSY_block, 1 }, - { 35, 0, HELIPAD1_block, 31 }, - { 36, 0, HELIPAD2_block, 32 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 33, TO_ALL, TAXIWAY_BUSY_block, 34 }, // need to go to hangar when waiting in air + { 34, TO_ALL, TAXIWAY_BUSY_block, 1 }, + { 35, TO_ALL, HELIPAD1_block, 31 }, + { 36, TO_ALL, HELIPAD2_block, 32 }, + { 37, HELITAKEOFF, NOTHING_block, 0 }, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_city[] = { {{5, 0}, DIR_SE, 0} }; static const byte _airport_terminal_city[] = { 1, 3 }; static const byte _airport_entries_city[] = {26, 29, 27, 28}; static const AirportFTAbuildup _airport_fta_city[] = { - { 0, HANGAR, NOTHING_block, 1 }, { 0, TAKEOFF, OUT_WAY_block, 1 }, { 0, 0, 0, 1 }, - { 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7 - { 2, TERM1, TERM1_block, 7 }, { 2, TAKEOFF, OUT_WAY_block, 7 }, { 2, 0, 0, 7 }, - { 3, TERM2, TERM2_block, 5 }, { 3, TAKEOFF, OUT_WAY_block, 6 }, { 3, 0, 0, 6 }, - { 4, TERM3, TERM3_block, 5 }, { 4, TAKEOFF, OUT_WAY_block, 5 }, { 4, 0, 0, 5 }, - { 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 }, - { 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, TERM2_block, 3 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 }, - { 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, OUT_WAY_block, 8 }, { 7, HELITAKEOFF, 0, 22 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 }, + { 0, HANGAR, NOTHING_block, 1 }, { 0, TAKEOFF, OUT_WAY_block, 1 }, { 0, TO_ALL, 0, 1 }, + { 1, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, TO_ALL, 0, 7 }, // for all else, go to 7 + { 2, TERM1, TERM1_block, 7 }, { 2, TAKEOFF, OUT_WAY_block, 7 }, { 2, TO_ALL, 0, 7 }, + { 3, TERM2, TERM2_block, 5 }, { 3, TAKEOFF, OUT_WAY_block, 6 }, { 3, TO_ALL, 0, 6 }, + { 4, TERM3, TERM3_block, 5 }, { 4, TAKEOFF, OUT_WAY_block, 5 }, { 4, TO_ALL, 0, 5 }, + { 5, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, TO_ALL, 0, 6 }, + { 6, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, TERM2_block, 3 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, TO_ALL, 0, 7 }, + { 7, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, OUT_WAY_block, 8 }, { 7, HELITAKEOFF, 0, 22 }, { 7, HANGAR, 0, 1 }, { 7, TO_ALL, 0, 6 }, { 8, 0, OUT_WAY_block, 9 }, { 9, 0, RUNWAY_IN_OUT_block, 10 }, /* takeoff */ @@ -520,24 +524,24 @@ static const AirportFTAbuildup _airport_fta_city[] = { /* landing */ { 13, FLYING, NOTHING_block, 18 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 23 }, { 14, LANDING, RUNWAY_IN_OUT_block, 15 }, - { 15, 0, RUNWAY_IN_OUT_block, 17 }, - { 16, 0, RUNWAY_IN_OUT_block, 17 }, // not used, left for compatibility + { 15, TO_ALL, RUNWAY_IN_OUT_block, 17 }, + { 16, TO_ALL, RUNWAY_IN_OUT_block, 17 }, // not used, left for compatibility { 17, ENDLANDING, IN_WAY_block, 7 }, /* In Air */ - { 18, 0, NOTHING_block, 25 }, - { 19, 0, NOTHING_block, 20 }, - { 20, 0, NOTHING_block, 21 }, - { 21, 0, NOTHING_block, 13 }, + { 18, TO_ALL, NOTHING_block, 25 }, + { 19, TO_ALL, NOTHING_block, 20 }, + { 20, TO_ALL, NOTHING_block, 21 }, + { 21, TO_ALL, NOTHING_block, 13 }, /* helicopter */ { 22, HELITAKEOFF, NOTHING_block, 0 }, { 23, HELILANDING, IN_WAY_block, 24 }, { 24, HELIENDLANDING, IN_WAY_block, 17 }, - { 25, 0, NOTHING_block, 20}, - { 26, 0, NOTHING_block, 19}, - { 27, 0, NOTHING_block, 28}, - { 28, 0, NOTHING_block, 19}, - { 29, 0, NOTHING_block, 26}, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 25, TO_ALL, NOTHING_block, 20}, + { 26, TO_ALL, NOTHING_block, 19}, + { 27, TO_ALL, NOTHING_block, 28}, + { 28, TO_ALL, NOTHING_block, 19}, + { 29, TO_ALL, NOTHING_block, 26}, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_metropolitan[] = { {{5, 0}, DIR_SE, 0} }; @@ -545,13 +549,13 @@ static const byte _airport_terminal_metropolitan[] = { 1, 3 }; static const byte _airport_entries_metropolitan[] = {20, 19, 22, 21}; static const AirportFTAbuildup _airport_fta_metropolitan[] = { { 0, HANGAR, NOTHING_block, 1 }, - { 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7 + { 1, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, TO_ALL, 0, 7 }, // for all else, go to 7 { 2, TERM1, TERM1_block, 7 }, { 3, TERM2, TERM2_block, 6 }, { 4, TERM3, TERM3_block, 5 }, - { 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 }, - { 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, TERM2_block, 3 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 }, - { 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, 0, 8 }, { 7, HELITAKEOFF, 0, 23 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 }, + { 5, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, TO_ALL, 0, 6 }, + { 6, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, TERM2_block, 3 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, TO_ALL, 0, 7 }, + { 7, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, 0, 8 }, { 7, HELITAKEOFF, 0, 23 }, { 7, HANGAR, 0, 1 }, { 7, TO_ALL, 0, 6 }, { 8, 0, OUT_WAY_block, 9 }, { 9, 0, RUNWAY_OUT_block, 10 }, /* takeoff */ @@ -561,86 +565,88 @@ static const AirportFTAbuildup _airport_fta_metropolitan[] = { /* landing */ { 13, FLYING, NOTHING_block, 19 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 25 }, { 14, LANDING, RUNWAY_IN_block, 15 }, - { 15, 0, RUNWAY_IN_block, 16 }, - { 16, 255, RUNWAY_IN_block, 0 }, { 16, ENDLANDING, IN_WAY_block, 17 }, - { 17, 255, RUNWAY_OUT_block, 0 }, { 17, ENDLANDING, IN_WAY_block, 18 }, + { 15, TO_ALL, RUNWAY_IN_block, 16 }, + { 16, TERMGROUP, RUNWAY_IN_block, 0 }, { 16, ENDLANDING, IN_WAY_block, 17 }, + { 17, TERMGROUP, RUNWAY_OUT_block, 0 }, { 17, ENDLANDING, IN_WAY_block, 18 }, { 18, ENDLANDING, IN_WAY_block, 27 }, /* In Air */ - { 19, 0, NOTHING_block, 20 }, - { 20, 0, NOTHING_block, 21 }, - { 21, 0, NOTHING_block, 22 }, - { 22, 0, NOTHING_block, 13 }, + { 19, TO_ALL, NOTHING_block, 20 }, + { 20, TO_ALL, NOTHING_block, 21 }, + { 21, TO_ALL, NOTHING_block, 22 }, + { 22, TO_ALL, NOTHING_block, 13 }, /* helicopter */ - { 23, 0, NOTHING_block, 24 }, + { 23, TO_ALL, NOTHING_block, 24 }, { 24, HELITAKEOFF, NOTHING_block, 0 }, { 25, HELILANDING, IN_WAY_block, 26 }, { 26, HELIENDLANDING, IN_WAY_block, 18 }, - { 27, 255, TAXIWAY_BUSY_block, 27 }, { 27, TERM1, TERM1_block, 2 }, { 27, 0, 0, 7 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 27, TERMGROUP, TAXIWAY_BUSY_block, 27 }, { 27, TERM1, TERM1_block, 2 }, { 27, TO_ALL, 0, 7 }, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_international[] = { {{0, 3}, DIR_SE, 0}, {{6, 1}, DIR_SE, 1} }; static const byte _airport_terminal_international[] = { 2, 3, 3 }; static const byte _airport_entries_international[] = { 38, 37, 40, 39 }; static const AirportFTAbuildup _airport_fta_international[] = { - { 0, HANGAR, NOTHING_block, 2 }, { 0, 255, TERM_GROUP1_block, 0 }, { 0, 255, TERM_GROUP2_ENTER1_block, 1 }, { 0, HELITAKEOFF, HELIPAD1_block, 2 }, { 0, 0, 0, 2 }, - { 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, HELITAKEOFF, HELIPAD2_block, 3 }, { 1, 0, 0, 3 }, - { 2, 255, AIRPORT_ENTRANCE_block, 0 }, { 2, HANGAR, 0, 0 }, { 2, TERM4, 0, 12 }, { 2, TERM5, 0, 12 }, { 2, TERM6, 0, 12 }, { 2, HELIPAD1, 0, 12 }, { 2, HELIPAD2, 0, 12 }, { 2, HELITAKEOFF, 0, 12 }, { 2, 0, 0, 23 }, - { 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, 0, 0, 18 }, - { 4, TERM1, TERM1_block, 23 }, { 4, HANGAR, AIRPORT_ENTRANCE_block, 23 }, { 4, 0, 0, 23 }, - { 5, TERM2, TERM2_block, 24 }, { 5, HANGAR, AIRPORT_ENTRANCE_block, 24 }, { 5, 0, 0, 24 }, - { 6, TERM3, TERM3_block, 25 }, { 6, HANGAR, AIRPORT_ENTRANCE_block, 25 }, { 6, 0, 0, 25 }, - { 7, TERM4, TERM4_block, 16 }, { 7, HANGAR, HANGAR2_AREA_block, 16 }, { 7, 0, 0, 16 }, - { 8, TERM5, TERM5_block, 17 }, { 8, HANGAR, HANGAR2_AREA_block, 17 }, { 8, 0, 0, 17 }, - { 9, TERM6, TERM6_block, 18 }, { 9, HANGAR, HANGAR2_AREA_block, 18 }, { 9, 0, 0, 18 }, + { 0, HANGAR, NOTHING_block, 2 }, { 0, TERMGROUP, TERM_GROUP1_block, 0 }, { 0, TERMGROUP, TERM_GROUP2_ENTER1_block, 1 }, { 0, HELITAKEOFF, AIRPORT_ENTRANCE_block, 2 }, { 0, TO_ALL, 0, 2 }, + { 1, HANGAR, NOTHING_block, 3 }, { 1, TERMGROUP, HANGAR2_AREA_block, 1 }, { 1, HELITAKEOFF, HANGAR2_AREA_block, 3 }, { 1, TO_ALL, 0, 3 }, + { 2, TERMGROUP, AIRPORT_ENTRANCE_block, 0 }, { 2, HANGAR, 0, 0 }, { 2, TERM4, 0, 12 }, { 2, TERM5, 0, 12 }, { 2, TERM6, 0, 12 }, { 2, HELIPAD1, 0, 12 }, { 2, HELIPAD2, 0, 12 }, { 2, HELITAKEOFF, 0, 51 }, { 2, TO_ALL, 0, 23 }, + { 3, TERMGROUP, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, HELITAKEOFF, 0, 52 }, { 3, TO_ALL, 0, 18 }, + { 4, TERM1, TERM1_block, 23 }, { 4, HANGAR, AIRPORT_ENTRANCE_block, 23 }, { 4, TO_ALL, 0, 23 }, + { 5, TERM2, TERM2_block, 24 }, { 5, HANGAR, AIRPORT_ENTRANCE_block, 24 }, { 5, TO_ALL, 0, 24 }, + { 6, TERM3, TERM3_block, 25 }, { 6, HANGAR, AIRPORT_ENTRANCE_block, 25 }, { 6, TO_ALL, 0, 25 }, + { 7, TERM4, TERM4_block, 16 }, { 7, HANGAR, HANGAR2_AREA_block, 16 }, { 7, TO_ALL, 0, 16 }, + { 8, TERM5, TERM5_block, 17 }, { 8, HANGAR, HANGAR2_AREA_block, 17 }, { 8, TO_ALL, 0, 17 }, + { 9, TERM6, TERM6_block, 18 }, { 9, HANGAR, HANGAR2_AREA_block, 18 }, { 9, TO_ALL, 0, 18 }, { 10, HELIPAD1, HELIPAD1_block, 10 }, { 10, HANGAR, HANGAR2_AREA_block, 16 }, { 10, HELITAKEOFF, 0, 47 }, { 11, HELIPAD2, HELIPAD2_block, 11 }, { 11, HANGAR, HANGAR2_AREA_block, 17 }, { 11, HELITAKEOFF, 0, 48 }, - { 12, 0, TERM_GROUP2_ENTER1_block, 13 }, - { 13, 0, TERM_GROUP2_ENTER1_block, 14 }, - { 14, 0, TERM_GROUP2_ENTER2_block, 15 }, - { 15, 0, TERM_GROUP2_ENTER2_block, 16 }, - { 16, 255, TERM_GROUP2_block, 0 }, { 16, TERM4, TERM4_block, 7 }, { 16, HELIPAD1, HELIPAD1_block, 10 }, { 16, HELITAKEOFF, HELIPAD1_block, 10 }, { 16, 0, 0, 17 }, - { 17, 255, TERM_GROUP2_block, 0 }, { 17, TERM5, TERM5_block, 8 }, { 17, TERM4, 0, 16 }, { 17, HELIPAD1, 0, 16 }, { 17, HELIPAD2, HELIPAD2_block, 11 }, { 17, HELITAKEOFF, HELIPAD2_block, 11 }, { 17, 0, 0, 18 }, - { 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM6, TERM6_block, 9 }, { 18, TAKEOFF, 0, 19 }, { 18, HANGAR, HANGAR2_AREA_block, 3 }, { 18, 0, 0, 17 }, - { 19, 0, TERM_GROUP2_EXIT1_block, 20 }, - { 20, 0, TERM_GROUP2_EXIT1_block, 21 }, - { 21, 0, TERM_GROUP2_EXIT2_block, 22 }, - { 22, 0, TERM_GROUP2_EXIT2_block, 26 }, - { 23, 255, TERM_GROUP1_block, 0 }, { 23, TERM1, TERM1_block, 4 }, { 23, HANGAR, AIRPORT_ENTRANCE_block, 2 }, { 23, 0, 0, 24 }, - { 24, 255, TERM_GROUP1_block, 0 }, { 24, TERM2, TERM2_block, 5 }, { 24, TERM1, 0, 23 }, { 24, HANGAR, 0, 23 }, { 24, 0, 0, 25 }, - { 25, 255, TERM_GROUP1_block, 0 }, { 25, TERM3, TERM3_block, 6 }, { 25, TAKEOFF, 0, 26 }, { 25, 0, 0, 24 }, - { 26, 255, TAXIWAY_BUSY_block, 0 }, { 26, TAKEOFF, 0, 27 }, { 26, 0, 0, 25 }, - { 27, 0, OUT_WAY_block, 28 }, + { 12, TO_ALL, TERM_GROUP2_ENTER1_block, 13 }, + { 13, TO_ALL, TERM_GROUP2_ENTER1_block, 14 }, + { 14, TO_ALL, TERM_GROUP2_ENTER2_block, 15 }, + { 15, TO_ALL, TERM_GROUP2_ENTER2_block, 16 }, + { 16, TERMGROUP, TERM_GROUP2_block, 0 }, { 16, TERM4, TERM4_block, 7 }, { 16, HELIPAD1, HELIPAD1_block, 10 }, { 16, HELITAKEOFF, HELIPAD1_block, 10 }, { 16, TO_ALL, 0, 17 }, + { 17, TERMGROUP, TERM_GROUP2_block, 0 }, { 17, TERM5, TERM5_block, 8 }, { 17, TERM4, 0, 16 }, { 17, HELIPAD1, 0, 16 }, { 17, HELIPAD2, HELIPAD2_block, 11 }, { 17, HELITAKEOFF, HELIPAD2_block, 11 }, { 17, TO_ALL, 0, 18 }, + { 18, TERMGROUP, TERM_GROUP2_block, 0 }, { 18, TERM6, TERM6_block, 9 }, { 18, TAKEOFF, 0, 19 }, { 18, HANGAR, HANGAR2_AREA_block, 3 }, { 18, TO_ALL, 0, 17 }, + { 19, TO_ALL, TERM_GROUP2_EXIT1_block, 20 }, + { 20, TO_ALL, TERM_GROUP2_EXIT1_block, 21 }, + { 21, TO_ALL, TERM_GROUP2_EXIT2_block, 22 }, + { 22, TO_ALL, TERM_GROUP2_EXIT2_block, 26 }, + { 23, TERMGROUP, TERM_GROUP1_block, 0 }, { 23, TERM1, TERM1_block, 4 }, { 23, HANGAR, AIRPORT_ENTRANCE_block, 2 }, { 23, TO_ALL, 0, 24 }, + { 24, TERMGROUP, TERM_GROUP1_block, 0 }, { 24, TERM2, TERM2_block, 5 }, { 24, TERM1, 0, 23 }, { 24, HANGAR, 0, 23 }, { 24, TO_ALL, 0, 25 }, + { 25, TERMGROUP, TERM_GROUP1_block, 0 }, { 25, TERM3, TERM3_block, 6 }, { 25, TAKEOFF, 0, 26 }, { 25, TO_ALL, 0, 24 }, + { 26, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 26, TAKEOFF, 0, 27 }, { 26, TO_ALL, 0, 25 }, + { 27, TO_ALL, OUT_WAY_block, 28 }, /* takeoff */ { 28, TAKEOFF, OUT_WAY_block, 29 }, - { 29, 0, RUNWAY_OUT_block, 30 }, + { 29, TO_ALL, RUNWAY_OUT_block, 30 }, { 30, STARTTAKEOFF, NOTHING_block, 31 }, { 31, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 32, FLYING, NOTHING_block, 37 }, { 32, LANDING, 0, 33 }, { 32, HELILANDING, 0, 41 }, { 33, LANDING, RUNWAY_IN_block, 34 }, - { 34, 0, RUNWAY_IN_block, 35 }, - { 35, 0, RUNWAY_IN_block, 36 }, - { 36, ENDLANDING, IN_WAY_block, 36 }, { 36, 255, TERM_GROUP1_block, 0 }, { 36, 255, TERM_GROUP2_ENTER1_block, 1 }, { 36, TERM4, 0, 12 }, { 36, TERM5, 0, 12 }, { 36, TERM6, 0, 12 }, { 36, 0, 0, 2 }, + { 34, TO_ALL, RUNWAY_IN_block, 35 }, + { 35, TO_ALL, RUNWAY_IN_block, 36 }, + { 36, ENDLANDING, IN_WAY_block, 36 }, { 36, TERMGROUP, TERM_GROUP1_block, 0 }, { 36, TERMGROUP, TERM_GROUP2_ENTER1_block, 1 }, { 36, TERM4, 0, 12 }, { 36, TERM5, 0, 12 }, { 36, TERM6, 0, 12 }, { 36, TO_ALL, 0, 2 }, /* In Air */ - { 37, 0, NOTHING_block, 38 }, - { 38, 0, NOTHING_block, 39 }, - { 39, 0, NOTHING_block, 40 }, - { 40, 0, NOTHING_block, 32 }, + { 37, TO_ALL, NOTHING_block, 38 }, + { 38, TO_ALL, NOTHING_block, 39 }, + { 39, TO_ALL, NOTHING_block, 40 }, + { 40, TO_ALL, NOTHING_block, 32 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 41, HELILANDING, PRE_HELIPAD_block, 42 }, { 42, HELIENDLANDING, PRE_HELIPAD_block, 42 }, { 42, HELIPAD1, 0, 43 }, { 42, HELIPAD2, 0, 44 }, { 42, HANGAR, 0, 49 }, - { 43, 0, NOTHING_block, 45 }, - { 44, 0, NOTHING_block, 46 }, + { 43, TO_ALL, NOTHING_block, 45 }, + { 44, TO_ALL, NOTHING_block, 46 }, /* landing */ - { 45, 255, NOTHING_block, 0 }, { 45, HELIPAD1, HELIPAD1_block, 10 }, - { 46, 255, NOTHING_block, 0 }, { 46, HELIPAD2, HELIPAD2_block, 11 }, + { 45, TERMGROUP, NOTHING_block, 0 }, { 45, HELIPAD1, HELIPAD1_block, 10 }, + { 46, TERMGROUP, NOTHING_block, 0 }, { 46, HELIPAD2, HELIPAD2_block, 11 }, /* Helicopter -- takeoff */ { 47, HELITAKEOFF, NOTHING_block, 0 }, { 48, HELITAKEOFF, NOTHING_block, 0 }, - { 49, 0, HANGAR2_AREA_block, 50 }, // need to go to hangar when waiting in air - { 50, 0, HANGAR2_AREA_block, 3 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 49, TO_ALL, HANGAR2_AREA_block, 50 }, // need to go to hangar when waiting in air + { 50, TO_ALL, HANGAR2_AREA_block, 3 }, + { 51, HELITAKEOFF, NOTHING_block, 0 }, + { 52, HELITAKEOFF, NOTHING_block, 0 }, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; /* intercontinental */ @@ -648,92 +654,92 @@ static const HangarTileTable _airport_depots_intercontinental[] = { {{0, 5}, DIR static const byte _airport_terminal_intercontinental[] = { 2, 4, 4 }; static const byte _airport_entries_intercontinental[] = { 44, 43, 46, 45 }; static const AirportFTAbuildup _airport_fta_intercontinental[] = { - { 0, HANGAR, NOTHING_block, 2 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 0 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 1 }, { 0, TAKEOFF, HANGAR1_AREA_block | TERM_GROUP1_block, 2 }, { 0, 0, 0, 2 }, - { 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, 255, HANGAR2_AREA_block, 0 }, { 1, 0, 0, 3 }, - { 2, 255, HANGAR1_AREA_block, 0 }, { 2, 255, TERM_GROUP1_block, 0 }, { 2, 255, TERM_GROUP1_block, 1 }, { 2, HANGAR, 0, 0 }, { 2, TAKEOFF, TERM_GROUP1_block, 27 }, { 2, TERM5, 0, 26 }, { 2, TERM6, 0, 26 }, { 2, TERM7, 0, 26 }, { 2, TERM8, 0, 26 }, { 2, HELIPAD1, 0, 26 }, { 2, HELIPAD2, 0, 26 }, { 2, HELITAKEOFF, 0, 74 }, { 2, 0, 0, 27 }, - { 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, HELITAKEOFF, 0, 75 }, {3, TAKEOFF, 0, 59}, { 3, 0, 0, 20 }, - { 4, TERM1, TERM1_block, 26 }, { 4, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 26 }, { 4, 0, 0, 26 }, - { 5, TERM2, TERM2_block, 27 }, { 5, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 27 }, { 5, 0, 0, 27 }, - { 6, TERM3, TERM3_block, 28 }, { 6, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 28 }, { 6, 0, 0, 28 }, - { 7, TERM4, TERM4_block, 29 }, { 7, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 7, 0, 0, 29 }, - { 8, TERM5, TERM5_block, 18 }, { 8, HANGAR, HANGAR2_AREA_block, 18 }, { 8, 0, 0, 18 }, - { 9, TERM6, TERM6_block, 19 }, { 9, HANGAR, HANGAR2_AREA_block, 19 }, { 9, 0, 0, 19 }, - { 10, TERM7, TERM7_block, 20 }, { 10, HANGAR, HANGAR2_AREA_block, 20 }, { 10, 0, 0, 20 }, - { 11, TERM8, TERM8_block, 21 }, { 11, HANGAR, HANGAR2_AREA_block, 21 }, { 11, 0, 0, 21 }, + { 0, HANGAR, NOTHING_block, 2 }, { 0, TERMGROUP, HANGAR1_AREA_block | TERM_GROUP1_block, 0 }, { 0, TERMGROUP, HANGAR1_AREA_block | TERM_GROUP1_block, 1 }, { 0, TAKEOFF, HANGAR1_AREA_block | TERM_GROUP1_block, 2 }, { 0, TO_ALL, 0, 2 }, + { 1, HANGAR, NOTHING_block, 3 }, { 1, TERMGROUP, HANGAR2_AREA_block, 1 }, { 1, TERMGROUP, HANGAR2_AREA_block, 0 }, { 1, TO_ALL, 0, 3 }, + { 2, TERMGROUP, HANGAR1_AREA_block, 0 }, { 2, TERMGROUP, TERM_GROUP1_block, 0 }, { 2, TERMGROUP, TERM_GROUP1_block, 1 }, { 2, HANGAR, 0, 0 }, { 2, TAKEOFF, TERM_GROUP1_block, 27 }, { 2, TERM5, 0, 26 }, { 2, TERM6, 0, 26 }, { 2, TERM7, 0, 26 }, { 2, TERM8, 0, 26 }, { 2, HELIPAD1, 0, 26 }, { 2, HELIPAD2, 0, 26 }, { 2, HELITAKEOFF, 0, 74 }, { 2, TO_ALL, 0, 27 }, + { 3, TERMGROUP, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, HELITAKEOFF, 0, 75 }, {3, TAKEOFF, 0, 59}, { 3, TO_ALL, 0, 20 }, + { 4, TERM1, TERM1_block, 26 }, { 4, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 26 }, { 4, TO_ALL, 0, 26 }, + { 5, TERM2, TERM2_block, 27 }, { 5, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 27 }, { 5, TO_ALL, 0, 27 }, + { 6, TERM3, TERM3_block, 28 }, { 6, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 28 }, { 6, TO_ALL, 0, 28 }, + { 7, TERM4, TERM4_block, 29 }, { 7, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 7, TO_ALL, 0, 29 }, + { 8, TERM5, TERM5_block, 18 }, { 8, HANGAR, HANGAR2_AREA_block, 18 }, { 8, TO_ALL, 0, 18 }, + { 9, TERM6, TERM6_block, 19 }, { 9, HANGAR, HANGAR2_AREA_block, 19 }, { 9, TO_ALL, 0, 19 }, + { 10, TERM7, TERM7_block, 20 }, { 10, HANGAR, HANGAR2_AREA_block, 20 }, { 10, TO_ALL, 0, 20 }, + { 11, TERM8, TERM8_block, 21 }, { 11, HANGAR, HANGAR2_AREA_block, 21 }, { 11, TO_ALL, 0, 21 }, { 12, HELIPAD1, HELIPAD1_block, 12 }, { 12, HANGAR, 0, 70 }, { 12, HELITAKEOFF, 0, 72 }, { 13, HELIPAD2, HELIPAD2_block, 13 }, { 13, HANGAR, 0, 71 }, { 13, HELITAKEOFF, 0, 73 }, - { 14, 0, TERM_GROUP2_ENTER1_block, 15 }, - { 15, 0, TERM_GROUP2_ENTER1_block, 16 }, - { 16, 0, TERM_GROUP2_ENTER2_block, 17 }, - { 17, 0, TERM_GROUP2_ENTER2_block, 18 }, - { 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM5, TERM5_block, 8 }, { 18, TAKEOFF, 0, 19 }, { 18, HELITAKEOFF, HELIPAD1_block, 19 }, { 18, 0, TERM_GROUP2_EXIT1_block, 19 }, - { 19, 255, TERM_GROUP2_block, 0 }, { 19, TERM6, TERM6_block, 9 }, { 19, TERM5, 0, 18 }, { 19, TAKEOFF, 0, 57 }, { 19, HELITAKEOFF, HELIPAD1_block, 20 }, { 19, 0, TERM_GROUP2_EXIT1_block, 20 }, // add exit to runway out 2 - { 20, 255, TERM_GROUP2_block, 0 }, { 20, TERM7, TERM7_block, 10 }, { 20, TERM5, 0, 19 }, { 20, TERM6, 0, 19 }, { 20, HANGAR, HANGAR2_AREA_block, 3 }, { 20, TAKEOFF, 0, 19 }, { 20, 0, TERM_GROUP2_EXIT1_block, 21 }, - { 21, 255, TERM_GROUP2_block, 0 }, { 21, TERM8, TERM8_block, 11 }, { 21, HANGAR, HANGAR2_AREA_block, 20 }, { 21, TERM5, 0, 20 }, { 21, TERM6, 0, 20 }, { 21, TERM7, 0, 20 }, { 21, TAKEOFF, 0, 20 }, { 21, 0, TERM_GROUP2_EXIT1_block, 22 }, - { 22, 255, TERM_GROUP2_block, 0 }, { 22, HANGAR, 0, 21 }, { 22, TERM5, 0, 21 }, { 22, TERM6, 0, 21 }, { 22, TERM7, 0, 21 }, { 22, TERM8, 0, 21 }, { 22, TAKEOFF, 0, 21 }, { 22, 0, 0, 23 }, - { 23, 0, TERM_GROUP2_EXIT1_block, 70 }, - { 24, 0, TERM_GROUP2_EXIT2_block, 25 }, - { 25, 255, TERM_GROUP2_EXIT2_block, 0 }, { 25, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 25, 0, 0, 29 }, - { 26, 255, TERM_GROUP1_block, 0 }, { 26, TERM1, TERM1_block, 4 }, { 26, HANGAR, HANGAR1_AREA_block, 27 }, { 26, TERM5, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM6, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM7, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM8, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD1, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD2, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELITAKEOFF, TERM_GROUP2_ENTER1_block, 14 }, { 26, 0, 0, 27 }, - { 27, 255, TERM_GROUP1_block, 0 }, { 27, TERM2, TERM2_block, 5 }, { 27, HANGAR, HANGAR1_AREA_block, 2 }, { 27, TERM1, 0, 26 }, { 27, TERM5, 0, 26 }, { 27, TERM6, 0, 26 }, { 27, TERM7, 0, 26 }, { 27, TERM8, 0, 26 }, { 27, HELIPAD1, 0, 14 }, { 27, HELIPAD2, 0, 14 }, { 27, 0, 0, 28 }, - { 28, 255, TERM_GROUP1_block, 0 }, { 28, TERM3, TERM3_block, 6 }, { 28, HANGAR, HANGAR1_AREA_block, 27 }, { 28, TERM1, 0, 27 }, { 28, TERM2, 0, 27 }, { 28, TERM4, 0, 29 }, { 28, TERM5, 0, 14 }, { 28, TERM6, 0, 14 }, { 28, TERM7, 0, 14 }, { 28, TERM8, 0, 14 }, { 28, HELIPAD1, 0, 14 }, { 28, HELIPAD2, 0, 14 }, { 28, 0, 0, 29 }, - { 29, 255, TERM_GROUP1_block, 0 }, { 29, TERM4, TERM4_block, 7 }, { 29, HANGAR, HANGAR1_AREA_block, 27 }, { 29, TAKEOFF, 0, 30 }, { 29, 0, 0, 28 }, - { 30, 0, OUT_WAY_block2, 31 }, - { 31, 0, OUT_WAY_block, 32 }, + { 14, TO_ALL, TERM_GROUP2_ENTER1_block, 15 }, + { 15, TO_ALL, TERM_GROUP2_ENTER1_block, 16 }, + { 16, TO_ALL, TERM_GROUP2_ENTER2_block, 17 }, + { 17, TO_ALL, TERM_GROUP2_ENTER2_block, 18 }, + { 18, TERMGROUP, TERM_GROUP2_block, 0 }, { 18, TERM5, TERM5_block, 8 }, { 18, TAKEOFF, 0, 19 }, { 18, HELITAKEOFF, HELIPAD1_block, 19 }, { 18, TO_ALL, TERM_GROUP2_EXIT1_block, 19 }, + { 19, TERMGROUP, TERM_GROUP2_block, 0 }, { 19, TERM6, TERM6_block, 9 }, { 19, TERM5, 0, 18 }, { 19, TAKEOFF, 0, 57 }, { 19, HELITAKEOFF, HELIPAD1_block, 20 }, { 19, TO_ALL, TERM_GROUP2_EXIT1_block, 20 }, // add exit to runway out 2 + { 20, TERMGROUP, TERM_GROUP2_block, 0 }, { 20, TERM7, TERM7_block, 10 }, { 20, TERM5, 0, 19 }, { 20, TERM6, 0, 19 }, { 20, HANGAR, HANGAR2_AREA_block, 3 }, { 20, TAKEOFF, 0, 19 }, { 20, TO_ALL, TERM_GROUP2_EXIT1_block, 21 }, + { 21, TERMGROUP, TERM_GROUP2_block, 0 }, { 21, TERM8, TERM8_block, 11 }, { 21, HANGAR, HANGAR2_AREA_block, 20 }, { 21, TERM5, 0, 20 }, { 21, TERM6, 0, 20 }, { 21, TERM7, 0, 20 }, { 21, TAKEOFF, 0, 20 }, { 21, TO_ALL, TERM_GROUP2_EXIT1_block, 22 }, + { 22, TERMGROUP, TERM_GROUP2_block, 0 }, { 22, HANGAR, 0, 21 }, { 22, TERM5, 0, 21 }, { 22, TERM6, 0, 21 }, { 22, TERM7, 0, 21 }, { 22, TERM8, 0, 21 }, { 22, TAKEOFF, 0, 21 }, { 22, TO_ALL, 0, 23 }, + { 23, TO_ALL, TERM_GROUP2_EXIT1_block, 70 }, + { 24, TO_ALL, TERM_GROUP2_EXIT2_block, 25 }, + { 25, TERMGROUP, TERM_GROUP2_EXIT2_block, 0 }, { 25, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 25, TO_ALL, 0, 29 }, + { 26, TERMGROUP, TERM_GROUP1_block, 0 }, { 26, TERM1, TERM1_block, 4 }, { 26, HANGAR, HANGAR1_AREA_block, 27 }, { 26, TERM5, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM6, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM7, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM8, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD1, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD2, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELITAKEOFF, TERM_GROUP2_ENTER1_block, 14 }, { 26, TO_ALL, 0, 27 }, + { 27, TERMGROUP, TERM_GROUP1_block, 0 }, { 27, TERM2, TERM2_block, 5 }, { 27, HANGAR, HANGAR1_AREA_block, 2 }, { 27, TERM1, 0, 26 }, { 27, TERM5, 0, 26 }, { 27, TERM6, 0, 26 }, { 27, TERM7, 0, 26 }, { 27, TERM8, 0, 26 }, { 27, HELIPAD1, 0, 14 }, { 27, HELIPAD2, 0, 14 }, { 27, TO_ALL, 0, 28 }, + { 28, TERMGROUP, TERM_GROUP1_block, 0 }, { 28, TERM3, TERM3_block, 6 }, { 28, HANGAR, HANGAR1_AREA_block, 27 }, { 28, TERM1, 0, 27 }, { 28, TERM2, 0, 27 }, { 28, TERM4, 0, 29 }, { 28, TERM5, 0, 14 }, { 28, TERM6, 0, 14 }, { 28, TERM7, 0, 14 }, { 28, TERM8, 0, 14 }, { 28, HELIPAD1, 0, 14 }, { 28, HELIPAD2, 0, 14 }, { 28, TO_ALL, 0, 29 }, + { 29, TERMGROUP, TERM_GROUP1_block, 0 }, { 29, TERM4, TERM4_block, 7 }, { 29, HANGAR, HANGAR1_AREA_block, 27 }, { 29, TAKEOFF, 0, 30 }, { 29, TO_ALL, 0, 28 }, + { 30, TO_ALL, OUT_WAY_block2, 31 }, + { 31, TO_ALL, OUT_WAY_block, 32 }, /* takeoff */ { 32, TAKEOFF, RUNWAY_OUT_block, 33 }, - { 33, 0, RUNWAY_OUT_block, 34 }, + { 33, TO_ALL, RUNWAY_OUT_block, 34 }, { 34, STARTTAKEOFF, NOTHING_block, 35 }, { 35, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ - { 36, 0, 0, 0 }, + { 36, TO_ALL, 0, 0 }, { 37, LANDING, RUNWAY_IN_block, 38 }, - { 38, 0, RUNWAY_IN_block, 39 }, - { 39, 0, RUNWAY_IN_block, 40 }, + { 38, TO_ALL, RUNWAY_IN_block, 39 }, + { 39, TO_ALL, RUNWAY_IN_block, 40 }, { 40, ENDLANDING, RUNWAY_IN_block, 41 }, - { 41, 0, IN_WAY_block, 42 }, - { 42, 255, IN_WAY_block, 0 }, { 42, 255, TERM_GROUP1_block, 0 }, { 42, 255, TERM_GROUP1_block, 1 }, { 42, HANGAR, 0, 2 }, { 42, 0, 0, 26 }, + { 41, TO_ALL, IN_WAY_block, 42 }, + { 42, TERMGROUP, IN_WAY_block, 0 }, { 42, TERMGROUP, TERM_GROUP1_block, 0 }, { 42, TERMGROUP, TERM_GROUP1_block, 1 }, { 42, HANGAR, 0, 2 }, { 42, TO_ALL, 0, 26 }, /* In Air */ - { 43, 0, 0, 44 }, - { 44, FLYING, 0, 45 }, { 44, HELILANDING, 0, 47 }, { 44, LANDING, 0, 69 }, { 44, 0, 0, 45 }, - { 45, 0, 0, 46 }, - { 46, FLYING, 0, 43 }, { 46, LANDING, 0, 76 }, { 46, 0, 0, 43 }, + { 43, TO_ALL, 0, 44 }, + { 44, FLYING, 0, 45 }, { 44, HELILANDING, 0, 47 }, { 44, LANDING, 0, 69 }, { 44, TO_ALL, 0, 45 }, + { 45, TO_ALL, 0, 46 }, + { 46, FLYING, 0, 43 }, { 46, LANDING, 0, 76 }, { 46, TO_ALL, 0, 43 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 47, HELILANDING, PRE_HELIPAD_block, 48 }, { 48, HELIENDLANDING, PRE_HELIPAD_block, 48 }, { 48, HELIPAD1, 0, 49 }, { 48, HELIPAD2, 0, 50 }, { 48, HANGAR, 0, 55 }, - { 49, 0, NOTHING_block, 51 }, - { 50, 0, NOTHING_block, 52 }, + { 49, TO_ALL, NOTHING_block, 51 }, + { 50, TO_ALL, NOTHING_block, 52 }, /* landing */ - { 51, 255, NOTHING_block, 0 }, { 51, HELIPAD1, HELIPAD1_block, 12 }, { 51, HANGAR, 0, 55 }, { 51, 0, 0, 12 }, - { 52, 255, NOTHING_block, 0 }, { 52, HELIPAD2, HELIPAD2_block, 13 }, { 52, HANGAR, 0, 55 }, { 52, 0, 0, 13 }, + { 51, TERMGROUP, NOTHING_block, 0 }, { 51, HELIPAD1, HELIPAD1_block, 12 }, { 51, HANGAR, 0, 55 }, { 51, TO_ALL, 0, 12 }, + { 52, TERMGROUP, NOTHING_block, 0 }, { 52, HELIPAD2, HELIPAD2_block, 13 }, { 52, HANGAR, 0, 55 }, { 52, TO_ALL, 0, 13 }, /* Helicopter -- takeoff */ { 53, HELITAKEOFF, NOTHING_block, 0 }, { 54, HELITAKEOFF, NOTHING_block, 0 }, - { 55, 0, HANGAR2_AREA_block, 56 }, // need to go to hangar when waiting in air - { 56, 0, HANGAR2_AREA_block, 3 }, + { 55, TO_ALL, HANGAR2_AREA_block, 56 }, // need to go to hangar when waiting in air + { 56, TO_ALL, HANGAR2_AREA_block, 3 }, /* runway 2 out support */ - { 57, 255, OUT_WAY2_block, 0 }, { 57, TAKEOFF, 0, 58 }, { 57, 0, 0, 58 }, - { 58, 0, OUT_WAY2_block, 59 }, + { 57, TERMGROUP, OUT_WAY2_block, 0 }, { 57, TAKEOFF, 0, 58 }, { 57, TO_ALL, 0, 58 }, + { 58, TO_ALL, OUT_WAY2_block, 59 }, { 59, TAKEOFF, RUNWAY_OUT2_block, 60 }, // takeoff - { 60, 0, RUNWAY_OUT2_block, 61 }, + { 60, TO_ALL, RUNWAY_OUT2_block, 61 }, { 61, STARTTAKEOFF, NOTHING_block, 62 }, { 62, ENDTAKEOFF, NOTHING_block, 0 }, /* runway 2 in support */ { 63, LANDING, RUNWAY_IN2_block, 64 }, - { 64, 0, RUNWAY_IN2_block, 65 }, - { 65, 0, RUNWAY_IN2_block, 66 }, - { 66, ENDLANDING, RUNWAY_IN2_block, 0 }, { 66, 255, 0, 1 }, { 66, 255, 0, 0 }, { 66, 0, 0, 67 }, - { 67, 0, IN_WAY2_block, 68 }, - { 68, 255, IN_WAY2_block, 0 }, { 68, 255, TERM_GROUP2_block, 1 }, { 68, 255, TERM_GROUP1_block, 0 }, { 68, HANGAR, HANGAR2_AREA_block, 22 }, { 68, 0, 0, 22 }, - { 69, 255, RUNWAY_IN2_block, 0 }, { 69, 0, RUNWAY_IN2_block, 63 }, - { 70, 255, TERM_GROUP2_EXIT1_block, 0 }, { 70, HELIPAD1, HELIPAD1_block, 12 }, { 70, HELITAKEOFF, HELIPAD1_block, 12 }, { 70, 0, 0, 71 }, - { 71, 255, TERM_GROUP2_EXIT1_block, 0 }, { 71, HELIPAD2, HELIPAD2_block, 13 }, { 71, HELITAKEOFF, HELIPAD1_block, 12 }, { 71, 0, 0, 24 }, - { 72, 0, HELIPAD1_block, 53 }, - { 73, 0, HELIPAD2_block, 54 }, + { 64, TO_ALL, RUNWAY_IN2_block, 65 }, + { 65, TO_ALL, RUNWAY_IN2_block, 66 }, + { 66, ENDLANDING, RUNWAY_IN2_block, 0 }, { 66, TERMGROUP, 0, 1 }, { 66, TERMGROUP, 0, 0 }, { 66, TO_ALL, 0, 67 }, + { 67, TO_ALL, IN_WAY2_block, 68 }, + { 68, TERMGROUP, IN_WAY2_block, 0 }, { 68, TERMGROUP, TERM_GROUP2_block, 1 }, { 68, TERMGROUP, TERM_GROUP1_block, 0 }, { 68, HANGAR, HANGAR2_AREA_block, 22 }, { 68, TO_ALL, 0, 22 }, + { 69, TERMGROUP, RUNWAY_IN2_block, 0 }, { 69, TO_ALL, RUNWAY_IN2_block, 63 }, + { 70, TERMGROUP, TERM_GROUP2_EXIT1_block, 0 }, { 70, HELIPAD1, HELIPAD1_block, 12 }, { 70, HELITAKEOFF, HELIPAD1_block, 12 }, { 70, TO_ALL, 0, 71 }, + { 71, TERMGROUP, TERM_GROUP2_EXIT1_block, 0 }, { 71, HELIPAD2, HELIPAD2_block, 13 }, { 71, HELITAKEOFF, HELIPAD1_block, 12 }, { 71, TO_ALL, 0, 24 }, + { 72, TO_ALL, HELIPAD1_block, 53 }, + { 73, TO_ALL, HELIPAD2_block, 54 }, { 74, HELITAKEOFF, NOTHING_block, 0 }, { 75, HELITAKEOFF, NOTHING_block, 0 }, - { 76, 255, RUNWAY_IN_block, 0 }, { 76, 0, RUNWAY_IN_block, 37 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 76, TERMGROUP, RUNWAY_IN_block, 0 }, { 76, TO_ALL, RUNWAY_IN_block, 37 }, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; @@ -742,15 +748,15 @@ static const byte _airport_entries_heliport[] = { 7, 7, 7, 7 }; static const AirportFTAbuildup _airport_fta_heliport[] = { { 0, HELIPAD1, HELIPAD1_block, 1 }, { 1, HELITAKEOFF, NOTHING_block, 0 }, // takeoff - { 2, 255, AIRPORT_BUSY_block, 0 }, { 2, HELILANDING, 0, 3 }, { 2, HELITAKEOFF, 0, 1 }, + { 2, TERMGROUP, AIRPORT_BUSY_block, 0 }, { 2, HELILANDING, 0, 3 }, { 2, HELITAKEOFF, 0, 1 }, { 3, HELILANDING, AIRPORT_BUSY_block, 4 }, { 4, HELIENDLANDING, AIRPORT_BUSY_block, 4 }, { 4, HELIPAD1, HELIPAD1_block, 0 }, { 4, HELITAKEOFF, 0, 2 }, /* In Air */ - { 5, 0, NOTHING_block, 6 }, - { 6, 0, NOTHING_block, 7 }, - { 7, 0, NOTHING_block, 8 }, + { 5, TO_ALL, NOTHING_block, 6 }, + { 6, TO_ALL, NOTHING_block, 7 }, + { 7, TO_ALL, NOTHING_block, 8 }, { 8, FLYING, NOTHING_block, 5 }, { 8, HELILANDING, HELIPAD1_block, 2 }, // landing - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; #define _airport_entries_oilrig _airport_entries_heliport #define _airport_fta_oilrig _airport_fta_heliport @@ -760,7 +766,7 @@ static const HangarTileTable _airport_depots_helidepot[] = { {{1, 0}, DIR_SE, 0} static const byte _airport_entries_helidepot[] = { 4, 4, 4, 4 }; static const AirportFTAbuildup _airport_fta_helidepot[] = { { 0, HANGAR, NOTHING_block, 1 }, - { 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELIPAD1, HELIPAD1_block, 14 }, { 1, HELITAKEOFF, 0, 15 }, { 1, 0, 0, 0 }, + { 1, TERMGROUP, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELIPAD1, HELIPAD1_block, 14 }, { 1, HELITAKEOFF, 0, 15 }, { 1, TO_ALL, 0, 0 }, { 2, FLYING, NOTHING_block, 3 }, { 2, HELILANDING, PRE_HELIPAD_block, 7 }, { 2, HANGAR, 0, 12 }, { 2, HELITAKEOFF, NOTHING_block, 16 }, /* In Air */ { 3, 0, NOTHING_block, 4 }, @@ -769,63 +775,63 @@ static const AirportFTAbuildup _airport_fta_helidepot[] = { { 6, 0, NOTHING_block, 2 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 7, HELILANDING, PRE_HELIPAD_block, 8 }, - { 8, HELIENDLANDING, PRE_HELIPAD_block, 8 }, { 8, HELIPAD1, 0, 9 }, { 8, HANGAR, 0, 12 }, { 8, 0, 0, 2 }, + { 8, HELIENDLANDING, PRE_HELIPAD_block, 8 }, { 8, HELIPAD1, 0, 9 }, { 8, HANGAR, 0, 12 }, { 8, TO_ALL, 0, 2 }, { 9, 0, NOTHING_block, 10 }, /* landing */ - { 10, 255, NOTHING_block, 10 }, { 10, HELIPAD1, HELIPAD1_block, 14 }, { 10, HANGAR, 0, 1 }, { 10, 0, 0, 14 }, + { 10, TERMGROUP, NOTHING_block, 10 }, { 10, HELIPAD1, HELIPAD1_block, 14 }, { 10, HANGAR, 0, 1 }, { 10, TO_ALL, 0, 14 }, /* Helicopter -- takeoff */ { 11, HELITAKEOFF, NOTHING_block, 0 }, - { 12, 0, HANGAR2_AREA_block, 13 }, // need to go to hangar when waiting in air - { 13, 0, HANGAR2_AREA_block, 1 }, + { 12, TO_ALL, HANGAR2_AREA_block, 13 }, // need to go to hangar when waiting in air + { 13, TO_ALL, HANGAR2_AREA_block, 1 }, { 14, HELIPAD1, HELIPAD1_block, 14 }, { 14, HANGAR, 0, 1 }, { 14, HELITAKEOFF, 0, 17 }, { 15, HELITAKEOFF, NOTHING_block, 0 }, // takeoff outside depot { 16, HELITAKEOFF, 0, 14 }, - { 17, 0, NOTHING_block, 11 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 17, TO_ALL, NOTHING_block, 11 }, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; /* helistation */ static const HangarTileTable _airport_depots_helistation[] = { {{0, 0}, DIR_SE, 0} }; static const byte _airport_entries_helistation[] = { 25, 25, 25, 25 }; static const AirportFTAbuildup _airport_fta_helistation[] = { - { 0, HANGAR, NOTHING_block, 8 }, { 0, HELIPAD1, 0, 1 }, { 0, HELIPAD2, 0, 1 }, { 0, HELIPAD3, 0, 1 }, { 0, HELITAKEOFF, 0, 1 }, { 0, 0, 0, 0 }, - { 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELITAKEOFF, 0, 3 }, { 1, 0, 0, 4 }, + { 0, HANGAR, NOTHING_block, 8 }, { 0, HELIPAD1, 0, 1 }, { 0, HELIPAD2, 0, 1 }, { 0, HELIPAD3, 0, 1 }, { 0, HELITAKEOFF, 0, 1 }, { 0, TO_ALL, 0, 0 }, + { 1, TERMGROUP, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELITAKEOFF, 0, 3 }, { 1, TO_ALL, 0, 4 }, /* landing */ - { 2, FLYING, NOTHING_block, 28 }, { 2, HELILANDING, 0, 15 }, { 2, 0, 0, 28 }, + { 2, FLYING, NOTHING_block, 28 }, { 2, HELILANDING, 0, 15 }, { 2, TO_ALL, 0, 28 }, /* helicopter side */ { 3, HELITAKEOFF, NOTHING_block, 0 }, // helitakeoff outside hangar2 - { 4, 255, TAXIWAY_BUSY_block, 0 }, { 4, HANGAR, HANGAR2_AREA_block, 1 }, { 4, HELITAKEOFF, 0, 1 }, { 4, 0, 0, 5 }, - { 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, HELIPAD1, HELIPAD1_block, 6 }, { 5, HELIPAD2, HELIPAD2_block, 7 }, { 5, HELIPAD3, HELIPAD3_block, 8 }, { 5, 0, 0, 4 }, - { 6, HELIPAD1, HELIPAD1_block, 5 }, { 6, HANGAR, HANGAR2_AREA_block, 5 }, { 6, HELITAKEOFF, 0, 9 }, { 6, 0, 0, 6 }, - { 7, HELIPAD2, HELIPAD2_block, 5 }, { 7, HANGAR, HANGAR2_AREA_block, 5 }, { 7, HELITAKEOFF, 0, 10 }, { 7, 0, 0, 7 }, - { 8, HELIPAD3, HELIPAD3_block, 5 }, { 8, HANGAR, HANGAR2_AREA_block, 5 }, { 8, HELITAKEOFF, 0, 11 }, { 8, 0, 0, 8 }, + { 4, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 4, HANGAR, HANGAR2_AREA_block, 1 }, { 4, HELITAKEOFF, 0, 1 }, { 4, TO_ALL, 0, 5 }, + { 5, TERMGROUP, TAXIWAY_BUSY_block, 0 }, { 5, HELIPAD1, HELIPAD1_block, 6 }, { 5, HELIPAD2, HELIPAD2_block, 7 }, { 5, HELIPAD3, HELIPAD3_block, 8 }, { 5, TO_ALL, 0, 4 }, + { 6, HELIPAD1, HELIPAD1_block, 5 }, { 6, HANGAR, HANGAR2_AREA_block, 5 }, { 6, HELITAKEOFF, 0, 9 }, { 6, TO_ALL, 0, 6 }, + { 7, HELIPAD2, HELIPAD2_block, 5 }, { 7, HANGAR, HANGAR2_AREA_block, 5 }, { 7, HELITAKEOFF, 0, 10 }, { 7, TO_ALL, 0, 7 }, + { 8, HELIPAD3, HELIPAD3_block, 5 }, { 8, HANGAR, HANGAR2_AREA_block, 5 }, { 8, HELITAKEOFF, 0, 11 }, { 8, TO_ALL, 0, 8 }, { 9, 0, HELIPAD1_block, 12 }, - { 10, 0, HELIPAD2_block, 13 }, - { 11, 0, HELIPAD3_block, 14 }, + { 10, TO_ALL, HELIPAD2_block, 13 }, + { 11, TO_ALL, HELIPAD3_block, 14 }, { 12, HELITAKEOFF, NOTHING_block, 0 }, { 13, HELITAKEOFF, NOTHING_block, 0 }, { 14, HELITAKEOFF, NOTHING_block, 0 }, /* heli - in flight moves */ { 15, HELILANDING, PRE_HELIPAD_block, 16 }, { 16, HELIENDLANDING, PRE_HELIPAD_block, 16 }, { 16, HELIPAD1, 0, 17 }, { 16, HELIPAD2, 0, 18 }, { 16, HELIPAD3, 0, 19 }, { 16, HANGAR, 0, 23 }, - { 17, 0, NOTHING_block, 20 }, - { 18, 0, NOTHING_block, 21 }, - { 19, 0, NOTHING_block, 22 }, + { 17, TO_ALL, NOTHING_block, 20 }, + { 18, TO_ALL, NOTHING_block, 21 }, + { 19, TO_ALL, NOTHING_block, 22 }, /* heli landing */ - { 20, 255, NOTHING_block, 0 }, { 20, HELIPAD1, HELIPAD1_block, 6 }, { 20, HANGAR, 0, 23 }, { 20, 0, 0, 6 }, - { 21, 255, NOTHING_block, 0 }, { 21, HELIPAD2, HELIPAD2_block, 7 }, { 21, HANGAR, 0, 23 }, { 21, 0, 0, 7 }, - { 22, 255, NOTHING_block, 0 }, { 22, HELIPAD3, HELIPAD3_block, 8 }, { 22, HANGAR, 0, 23 }, { 22, 0, 0, 8 }, - { 23, 0, HANGAR2_AREA_block, 24 }, // need to go to helihangar when waiting in air - { 24, 0, HANGAR2_AREA_block, 1 }, - { 25, 0, NOTHING_block, 26 }, - { 26, 0, NOTHING_block, 27 }, - { 27, 0, NOTHING_block, 2 }, - { 28, 0, NOTHING_block, 29 }, - { 29, 0, NOTHING_block, 30 }, - { 30, 0, NOTHING_block, 31 }, - { 31, 0, NOTHING_block, 32 }, - { 32, 0, NOTHING_block, 25 }, - { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE + { 20, TERMGROUP, NOTHING_block, 0 }, { 20, HELIPAD1, HELIPAD1_block, 6 }, { 20, HANGAR, 0, 23 }, { 20, TO_ALL, 0, 6 }, + { 21, TERMGROUP, NOTHING_block, 0 }, { 21, HELIPAD2, HELIPAD2_block, 7 }, { 21, HANGAR, 0, 23 }, { 21, TO_ALL, 0, 7 }, + { 22, TERMGROUP, NOTHING_block, 0 }, { 22, HELIPAD3, HELIPAD3_block, 8 }, { 22, HANGAR, 0, 23 }, { 22, TO_ALL, 0, 8 }, + { 23, TO_ALL, HANGAR2_AREA_block, 24 }, // need to go to helihangar when waiting in air + { 24, TO_ALL, HANGAR2_AREA_block, 1 }, + { 25, TO_ALL, NOTHING_block, 26 }, + { 26, TO_ALL, NOTHING_block, 27 }, + { 27, TO_ALL, NOTHING_block, 2 }, + { 28, TO_ALL, NOTHING_block, 29 }, + { 29, TO_ALL, NOTHING_block, 30 }, + { 30, TO_ALL, NOTHING_block, 31 }, + { 31, TO_ALL, NOTHING_block, 32 }, + { 32, TO_ALL, NOTHING_block, 25 }, + { MAX_ELEMENTS, TO_ALL, 0, 0 } // end marker. DO NOT REMOVE }; #endif /* AIRPORT_MOVEMENT_H */ diff --git a/src/table/bridge_land.h b/src/table/bridge_land.h index 4f6f94bb0f..b06a4076be 100644 --- a/src/table/bridge_land.h +++ b/src/table/bridge_land.h @@ -741,7 +741,7 @@ static const PalSpriteID * const * const _bridge_sprite_table[MAX_BRIDGES] = { * @param nrd description of the road bridge in query tool */ #define MBR(y, mnl, mxl, p, mxs, spr, plt, dsc, nrl, nrd) \ - {y, mnl, mxl, p, mxs, spr, plt, dsc, { nrl, nrd }, NULL, 0} + {y, mnl, mxl, p, mxs, spr, plt, dsc, { nrl, nrd }, nullptr, 0} const BridgeSpec _orig_bridge[] = { /* diff --git a/src/table/build_industry.h b/src/table/build_industry.h index 62264eb6f8..07ac84a3dc 100644 --- a/src/table/build_industry.h +++ b/src/table/build_industry.h @@ -22,22 +22,16 @@ */ #define MK(x, y, m) {{x, y}, m} -/** - * Terminator of industry tiles layout definition - */ -#define MKEND {{-0x80, 0}, 0} - -static const IndustryTileTable _tile_table_coal_mine_0[] = { +static const IndustryTileLayout _tile_table_coal_mine_0 { MK(1, 1, 0), MK(1, 2, 2), MK(0, 0, 5), MK(1, 0, 6), MK(2, 0, 3), MK(2, 2, 3), - MKEND }; -static const IndustryTileTable _tile_table_coal_mine_1[] = { +static const IndustryTileLayout _tile_table_coal_mine_1 { MK(1, 1, 0), MK(1, 2, 2), MK(2, 0, 0), @@ -47,20 +41,18 @@ static const IndustryTileTable _tile_table_coal_mine_1[] = { MK(0, 1, 4), MK(0, 2, 4), MK(2, 2, 4), - MKEND }; -static const IndustryTileTable _tile_table_coal_mine_2[] = { +static const IndustryTileLayout _tile_table_coal_mine_2 { MK(0, 0, 0), MK(0, 1, 2), MK(0, 2, 5), MK(1, 0, 3), MK(1, 1, 3), MK(1, 2, 6), - MKEND }; -static const IndustryTileTable _tile_table_coal_mine_3[] = { +static const IndustryTileLayout _tile_table_coal_mine_3 { MK(0, 1, 0), MK(0, 2, 2), MK(0, 3, 4), @@ -71,17 +63,16 @@ static const IndustryTileTable _tile_table_coal_mine_3[] = { MK(2, 0, 6), MK(2, 1, 4), MK(2, 2, 3), - MKEND }; -static const IndustryTileTable * const _tile_table_coal_mine[] = { +static const std::vector _tile_table_coal_mine { _tile_table_coal_mine_0, _tile_table_coal_mine_1, _tile_table_coal_mine_2, _tile_table_coal_mine_3, }; -static const IndustryTileTable _tile_table_power_station_0[] = { +static const IndustryTileLayout _tile_table_power_station_0 { MK(0, 0, 7), MK(0, 1, 9), MK(1, 0, 7), @@ -90,10 +81,9 @@ static const IndustryTileTable _tile_table_power_station_0[] = { MK(2, 1, 8), MK(3, 0, 10), MK(3, 1, 10), - MKEND }; -static const IndustryTileTable _tile_table_power_station_1[] = { +static const IndustryTileLayout _tile_table_power_station_1 { MK(0, 1, 7), MK(0, 2, 7), MK(1, 0, 8), @@ -102,26 +92,24 @@ static const IndustryTileTable _tile_table_power_station_1[] = { MK(2, 0, 9), MK(2, 1, 10), MK(2, 2, 9), - MKEND }; -static const IndustryTileTable _tile_table_power_station_2[] = { +static const IndustryTileLayout _tile_table_power_station_2 { MK(0, 0, 7), MK(0, 1, 7), MK(1, 0, 9), MK(1, 1, 8), MK(2, 0, 10), MK(2, 1, 9), - MKEND }; -static const IndustryTileTable * const _tile_table_power_station[] = { +static const std::vector _tile_table_power_station { _tile_table_power_station_0, _tile_table_power_station_1, _tile_table_power_station_2, }; -static const IndustryTileTable _tile_table_sawmill_0[] = { +static const IndustryTileLayout _tile_table_sawmill_0 { MK(1, 0, 14), MK(1, 1, 12), MK(1, 2, 11), @@ -130,10 +118,9 @@ static const IndustryTileTable _tile_table_sawmill_0[] = { MK(0, 0, 15), MK(0, 1, 15), MK(0, 2, 12), - MKEND }; -static const IndustryTileTable _tile_table_sawmill_1[] = { +static const IndustryTileLayout _tile_table_sawmill_1 { MK(0, 0, 15), MK(0, 1, 11), MK(0, 2, 14), @@ -142,15 +129,14 @@ static const IndustryTileTable _tile_table_sawmill_1[] = { MK(1, 2, 12), MK(2, 0, 11), MK(2, 1, 13), - MKEND }; -static const IndustryTileTable * const _tile_table_sawmill[] = { +static const std::vector _tile_table_sawmill { _tile_table_sawmill_0, _tile_table_sawmill_1, }; -static const IndustryTileTable _tile_table_forest_0[] = { +static const IndustryTileLayout _tile_table_forest_0 { MK(0, 0, 16), MK(0, 1, 16), MK(0, 2, 16), @@ -169,10 +155,9 @@ static const IndustryTileTable _tile_table_forest_0[] = { MK(3, 3, 16), MK(1, 4, 16), MK(2, 4, 16), - MKEND }; -static const IndustryTileTable _tile_table_forest_1[] = { +static const IndustryTileLayout _tile_table_forest_1 { MK(0, 0, 16), MK(1, 0, 16), MK(2, 0, 16), @@ -196,15 +181,14 @@ static const IndustryTileTable _tile_table_forest_1[] = { MK(1, 4, 16), MK(2, 4, 16), MK(3, 4, 16), - MKEND }; -static const IndustryTileTable * const _tile_table_forest[] = { +static const std::vector _tile_table_forest { _tile_table_forest_0, _tile_table_forest_1, }; -static const IndustryTileTable _tile_table_oil_refinery_0[] = { +static const IndustryTileLayout _tile_table_oil_refinery_0 { MK(0, 0, 20), MK(0, 1, 21), MK(0, 2, 22), @@ -220,10 +204,9 @@ static const IndustryTileTable _tile_table_oil_refinery_0[] = { MK(3, 3, 18), MK(2, 0, 23), MK(3, 1, 23), - MKEND }; -static const IndustryTileTable _tile_table_oil_refinery_1[] = { +static const IndustryTileLayout _tile_table_oil_refinery_1 { MK(0, 0, 18), MK(0, 1, 18), MK(0, 2, 21), @@ -239,15 +222,14 @@ static const IndustryTileTable _tile_table_oil_refinery_1[] = { MK(2, 3, 22), MK(1, 4, 23), MK(2, 4, 23), - MKEND }; -static const IndustryTileTable * const _tile_table_oil_refinery[] = { +static const std::vector _tile_table_oil_refinery { _tile_table_oil_refinery_0, _tile_table_oil_refinery_1, }; -static const IndustryTileTable _tile_table_oil_rig_0[] = { +static const IndustryTileLayout _tile_table_oil_rig_0 { MK(0, 0, 24), MK(0, 1, 24), MK(0, 2, 25), @@ -306,14 +288,13 @@ static const IndustryTileTable _tile_table_oil_rig_0[] = { MK(2, 3, 255), MK(2, 2, 255), MK(2, 1, 255), - MKEND }; -static const IndustryTileTable * const _tile_table_oil_rig[] = { +static const std::vector _tile_table_oil_rig { _tile_table_oil_rig_0, }; -static const IndustryTileTable _tile_table_factory_0[] = { +static const IndustryTileLayout _tile_table_factory_0 { MK(0, 0, 39), MK(0, 1, 40), MK(1, 0, 41), @@ -326,10 +307,9 @@ static const IndustryTileTable _tile_table_factory_0[] = { MK(2, 2, 40), MK(3, 1, 41), MK(3, 2, 42), - MKEND }; -static const IndustryTileTable _tile_table_factory_1[] = { +static const IndustryTileLayout _tile_table_factory_1 { MK(0, 0, 39), MK(0, 1, 40), MK(1, 0, 41), @@ -342,15 +322,14 @@ static const IndustryTileTable _tile_table_factory_1[] = { MK(1, 3, 40), MK(2, 2, 41), MK(2, 3, 42), - MKEND }; -static const IndustryTileTable * const _tile_table_factory[] = { +static const std::vector _tile_table_factory { _tile_table_factory_0, _tile_table_factory_1, }; -static const IndustryTileTable _tile_table_printing_works_0[] = { +static const IndustryTileLayout _tile_table_printing_works_0 { MK(0, 0, 43), MK(0, 1, 44), MK(1, 0, 45), @@ -363,10 +342,9 @@ static const IndustryTileTable _tile_table_printing_works_0[] = { MK(2, 2, 44), MK(3, 1, 45), MK(3, 2, 46), - MKEND }; -static const IndustryTileTable _tile_table_printing_works_1[] = { +static const IndustryTileLayout _tile_table_printing_works_1 { MK(0, 0, 43), MK(0, 1, 44), MK(1, 0, 45), @@ -379,15 +357,14 @@ static const IndustryTileTable _tile_table_printing_works_1[] = { MK(1, 3, 44), MK(2, 2, 45), MK(2, 3, 46), - MKEND }; -static const IndustryTileTable * const _tile_table_printing_works[] = { +static const std::vector _tile_table_printing_works { _tile_table_printing_works_0, _tile_table_printing_works_1, }; -static const IndustryTileTable _tile_table_steel_mill_0[] = { +static const IndustryTileLayout _tile_table_steel_mill_0 { MK(2, 1, 52), MK(2, 2, 53), MK(3, 1, 54), @@ -400,10 +377,9 @@ static const IndustryTileTable _tile_table_steel_mill_0[] = { MK(1, 2, 57), MK(2, 0, 56), MK(3, 0, 57), - MKEND }; -static const IndustryTileTable _tile_table_steel_mill_1[] = { +static const IndustryTileLayout _tile_table_steel_mill_1 { MK(0, 0, 52), MK(0, 1, 53), MK(1, 0, 54), @@ -418,15 +394,14 @@ static const IndustryTileTable _tile_table_steel_mill_1[] = { MK(3, 2, 57), MK(1, 3, 56), MK(2, 3, 57), - MKEND }; -static const IndustryTileTable * const _tile_table_steel_mill[] = { +static const std::vector _tile_table_steel_mill { _tile_table_steel_mill_0, _tile_table_steel_mill_1, }; -static const IndustryTileTable _tile_table_farm_0[] = { +static const IndustryTileLayout _tile_table_farm_0 { MK(1, 0, 33), MK(1, 1, 34), MK(1, 2, 36), @@ -436,10 +411,9 @@ static const IndustryTileTable _tile_table_farm_0[] = { MK(2, 0, 35), MK(2, 1, 38), MK(2, 2, 38), - MKEND }; -static const IndustryTileTable _tile_table_farm_1[] = { +static const IndustryTileLayout _tile_table_farm_1 { MK(1, 1, 33), MK(1, 2, 34), MK(0, 0, 35), @@ -452,10 +426,9 @@ static const IndustryTileTable _tile_table_farm_1[] = { MK(2, 1, 37), MK(2, 2, 38), MK(2, 3, 38), - MKEND }; -static const IndustryTileTable _tile_table_farm_2[] = { +static const IndustryTileLayout _tile_table_farm_2 { MK(2, 0, 33), MK(2, 1, 34), MK(0, 0, 36), @@ -468,16 +441,15 @@ static const IndustryTileTable _tile_table_farm_2[] = { MK(1, 3, 37), MK(2, 2, 37), MK(2, 3, 35), - MKEND }; -static const IndustryTileTable * const _tile_table_farm[] = { +static const std::vector _tile_table_farm { _tile_table_farm_0, _tile_table_farm_1, _tile_table_farm_2, }; -static const IndustryTileTable _tile_table_copper_mine_0[] = { +static const IndustryTileLayout _tile_table_copper_mine_0 { MK(0, 0, 47), MK(0, 1, 49), MK(0, 2, 51), @@ -486,10 +458,9 @@ static const IndustryTileTable _tile_table_copper_mine_0[] = { MK(1, 2, 50), MK(2, 0, 51), MK(2, 1, 51), - MKEND }; -static const IndustryTileTable _tile_table_copper_mine_1[] = { +static const IndustryTileLayout _tile_table_copper_mine_1 { MK(0, 0, 50), MK(0, 1, 47), MK(0, 2, 49), @@ -499,48 +470,44 @@ static const IndustryTileTable _tile_table_copper_mine_1[] = { MK(2, 0, 51), MK(2, 1, 47), MK(2, 2, 49), - MKEND }; -static const IndustryTileTable * const _tile_table_copper_mine[] = { +static const std::vector _tile_table_copper_mine { _tile_table_copper_mine_0, _tile_table_copper_mine_1, }; -static const IndustryTileTable _tile_table_oil_well_0[] = { +static const IndustryTileLayout _tile_table_oil_well_0 { MK(0, 0, 29), MK(1, 0, 29), MK(2, 0, 29), MK(0, 1, 29), MK(0, 2, 29), - MKEND }; -static const IndustryTileTable _tile_table_oil_well_1[] = { +static const IndustryTileLayout _tile_table_oil_well_1 { MK(0, 0, 29), MK(1, 0, 29), MK(1, 1, 29), MK(2, 2, 29), MK(2, 3, 29), - MKEND }; -static const IndustryTileTable * const _tile_table_oil_well[] = { +static const std::vector _tile_table_oil_well { _tile_table_oil_well_0, _tile_table_oil_well_1, }; -static const IndustryTileTable _tile_table_bank_0[] = { +static const IndustryTileLayout _tile_table_bank_0 { MK(0, 0, 58), MK(1, 0, 59), - MKEND }; -static const IndustryTileTable * const _tile_table_bank[] = { +static const std::vector _tile_table_bank { _tile_table_bank_0, }; -static const IndustryTileTable _tile_table_food_process_0[] = { +static const IndustryTileLayout _tile_table_food_process_0 { MK(0, 0, 60), MK(1, 0, 60), MK(2, 0, 60), @@ -553,10 +520,9 @@ static const IndustryTileTable _tile_table_food_process_0[] = { MK(0, 3, 62), MK(1, 3, 62), MK(2, 3, 63), - MKEND }; -static const IndustryTileTable _tile_table_food_process_1[] = { +static const IndustryTileLayout _tile_table_food_process_1 { MK(0, 0, 61), MK(1, 0, 60), MK(2, 0, 61), @@ -571,15 +537,14 @@ static const IndustryTileTable _tile_table_food_process_1[] = { MK(3, 2, 60), MK(0, 3, 62), MK(1, 3, 62), - MKEND }; -static const IndustryTileTable * const _tile_table_food_process[] = { +static const std::vector _tile_table_food_process { _tile_table_food_process_0, _tile_table_food_process_1, }; -static const IndustryTileTable _tile_table_paper_mill_0[] = { +static const IndustryTileLayout _tile_table_paper_mill_0 { MK(0, 0, 64), MK(1, 0, 65), MK(2, 0, 66), @@ -592,14 +557,13 @@ static const IndustryTileTable _tile_table_paper_mill_0[] = { MK(1, 2, 71), MK(2, 2, 71), MK(3, 2, 70), - MKEND }; -static const IndustryTileTable * const _tile_table_paper_mill[] = { +static const std::vector _tile_table_paper_mill { _tile_table_paper_mill_0, }; -static const IndustryTileTable _tile_table_gold_mine_0[] = { +static const IndustryTileLayout _tile_table_gold_mine_0 { MK(0, 0, 72), MK(0, 1, 73), MK(0, 2, 74), @@ -616,24 +580,22 @@ static const IndustryTileTable _tile_table_gold_mine_0[] = { MK(3, 1, 85), MK(3, 2, 86), MK(3, 3, 87), - MKEND }; -static const IndustryTileTable * const _tile_table_gold_mine[] = { +static const std::vector _tile_table_gold_mine { _tile_table_gold_mine_0, }; -static const IndustryTileTable _tile_table_bank2_0[] = { +static const IndustryTileLayout _tile_table_bank2_0 { MK(0, 0, 89), MK(1, 0, 90), - MKEND }; -static const IndustryTileTable * const _tile_table_bank2[] = { +static const std::vector _tile_table_bank2 { _tile_table_bank2_0, }; -static const IndustryTileTable _tile_table_diamond_mine_0[] = { +static const IndustryTileLayout _tile_table_diamond_mine_0 { MK(0, 0, 91), MK(0, 1, 92), MK(0, 2, 93), @@ -643,14 +605,13 @@ static const IndustryTileTable _tile_table_diamond_mine_0[] = { MK(2, 0, 97), MK(2, 1, 98), MK(2, 2, 99), - MKEND }; -static const IndustryTileTable * const _tile_table_diamond_mine[] = { +static const std::vector _tile_table_diamond_mine { _tile_table_diamond_mine_0, }; -static const IndustryTileTable _tile_table_iron_mine_0[] = { +static const IndustryTileLayout _tile_table_iron_mine_0 { MK(0, 0, 100), MK(0, 1, 101), MK(0, 2, 102), @@ -667,14 +628,13 @@ static const IndustryTileTable _tile_table_iron_mine_0[] = { MK(3, 1, 113), MK(3, 2, 114), MK(3, 3, 115), - MKEND }; -static const IndustryTileTable * const _tile_table_iron_mine[] = { +static const std::vector _tile_table_iron_mine { _tile_table_iron_mine_0, }; -static const IndustryTileTable _tile_table_fruit_plantation_0[] = { +static const IndustryTileLayout _tile_table_fruit_plantation_0 { MK(0, 0, 116), MK(0, 1, 116), MK(0, 2, 116), @@ -695,14 +655,13 @@ static const IndustryTileTable _tile_table_fruit_plantation_0[] = { MK(4, 1, 116), MK(4, 2, 116), MK(4, 3, 116), - MKEND }; -static const IndustryTileTable * const _tile_table_fruit_plantation[] = { +static const std::vector _tile_table_fruit_plantation { _tile_table_fruit_plantation_0, }; -static const IndustryTileTable _tile_table_rubber_plantation_0[] = { +static const IndustryTileLayout _tile_table_rubber_plantation_0 { MK(0, 0, 117), MK(0, 1, 117), MK(0, 2, 117), @@ -723,35 +682,32 @@ static const IndustryTileTable _tile_table_rubber_plantation_0[] = { MK(4, 1, 117), MK(4, 2, 117), MK(4, 3, 117), - MKEND }; -static const IndustryTileTable * const _tile_table_rubber_plantation[] = { +static const std::vector _tile_table_rubber_plantation { _tile_table_rubber_plantation_0, }; -static const IndustryTileTable _tile_table_water_supply_0[] = { +static const IndustryTileLayout _tile_table_water_supply_0 { MK(0, 0, 118), MK(0, 1, 119), MK(1, 0, 118), MK(1, 1, 119), - MKEND }; -static const IndustryTileTable * const _tile_table_water_supply[] = { +static const std::vector _tile_table_water_supply { _tile_table_water_supply_0, }; -static const IndustryTileTable _tile_table_water_tower_0[] = { +static const IndustryTileLayout _tile_table_water_tower_0 { MK(0, 0, 120), - MKEND }; -static const IndustryTileTable * const _tile_table_water_tower[] = { +static const std::vector _tile_table_water_tower { _tile_table_water_tower_0, }; -static const IndustryTileTable _tile_table_factory2_0[] = { +static const IndustryTileLayout _tile_table_factory2_0 { MK(0, 0, 121), MK(0, 1, 122), MK(1, 0, 123), @@ -760,10 +716,9 @@ static const IndustryTileTable _tile_table_factory2_0[] = { MK(0, 3, 122), MK(1, 2, 123), MK(1, 3, 124), - MKEND }; -static const IndustryTileTable _tile_table_factory2_1[] = { +static const IndustryTileLayout _tile_table_factory2_1 { MK(0, 0, 121), MK(0, 1, 122), MK(1, 0, 123), @@ -772,15 +727,14 @@ static const IndustryTileTable _tile_table_factory2_1[] = { MK(2, 1, 122), MK(3, 0, 123), MK(3, 1, 124), - MKEND }; -static const IndustryTileTable * const _tile_table_factory2[] = { +static const std::vector _tile_table_factory2 { _tile_table_factory2_0, _tile_table_factory2_1, }; -static const IndustryTileTable _tile_table_farm2_0[] = { +static const IndustryTileLayout _tile_table_farm2_0 { MK(1, 0, 33), MK(1, 1, 34), MK(1, 2, 36), @@ -790,10 +744,9 @@ static const IndustryTileTable _tile_table_farm2_0[] = { MK(2, 0, 35), MK(2, 1, 38), MK(2, 2, 38), - MKEND }; -static const IndustryTileTable _tile_table_farm2_1[] = { +static const IndustryTileLayout _tile_table_farm2_1 { MK(1, 1, 33), MK(1, 2, 34), MK(0, 0, 35), @@ -806,10 +759,9 @@ static const IndustryTileTable _tile_table_farm2_1[] = { MK(2, 1, 37), MK(2, 2, 38), MK(2, 3, 38), - MKEND }; -static const IndustryTileTable _tile_table_farm2_2[] = { +static const IndustryTileLayout _tile_table_farm2_2 { MK(2, 0, 33), MK(2, 1, 34), MK(0, 0, 36), @@ -822,28 +774,26 @@ static const IndustryTileTable _tile_table_farm2_2[] = { MK(1, 3, 37), MK(2, 2, 37), MK(2, 3, 35), - MKEND }; -static const IndustryTileTable * const _tile_table_farm2[] = { +static const std::vector _tile_table_farm2 { _tile_table_farm2_0, _tile_table_farm2_1, _tile_table_farm2_2, }; -static const IndustryTileTable _tile_table_lumber_mill_0[] = { +static const IndustryTileLayout _tile_table_lumber_mill_0 { MK(0, 0, 125), MK(0, 1, 126), MK(1, 0, 127), MK(1, 1, 128), - MKEND }; -static const IndustryTileTable * const _tile_table_lumber_mill[] = { +static const std::vector _tile_table_lumber_mill { _tile_table_lumber_mill_0, }; -static const IndustryTileTable _tile_table_cotton_candy_0[] = { +static const IndustryTileLayout _tile_table_cotton_candy_0 { MK(0, 0, 129), MK(0, 1, 129), MK(0, 2, 129), @@ -862,10 +812,9 @@ static const IndustryTileTable _tile_table_cotton_candy_0[] = { MK(3, 3, 129), MK(1, 4, 129), MK(2, 4, 129), - MKEND }; -static const IndustryTileTable _tile_table_cotton_candy_1[] = { +static const IndustryTileLayout _tile_table_cotton_candy_1 { MK(0, 0, 129), MK(1, 0, 129), MK(2, 0, 129), @@ -889,15 +838,14 @@ static const IndustryTileTable _tile_table_cotton_candy_1[] = { MK(1, 4, 129), MK(2, 4, 129), MK(3, 4, 129), - MKEND }; -static const IndustryTileTable * const _tile_table_cotton_candy[] = { +static const std::vector _tile_table_cotton_candy { _tile_table_cotton_candy_0, _tile_table_cotton_candy_1, }; -static const IndustryTileTable _tile_table_candy_factory_0[] = { +static const IndustryTileLayout _tile_table_candy_factory_0 { MK(0, 0, 131), MK(0, 1, 132), MK(1, 0, 133), @@ -910,10 +858,9 @@ static const IndustryTileTable _tile_table_candy_factory_0[] = { MK(2, 2, 132), MK(3, 1, 133), MK(3, 2, 134), - MKEND }; -static const IndustryTileTable _tile_table_candy_factory_1[] = { +static const IndustryTileLayout _tile_table_candy_factory_1 { MK(0, 0, 131), MK(0, 1, 132), MK(1, 0, 133), @@ -926,15 +873,14 @@ static const IndustryTileTable _tile_table_candy_factory_1[] = { MK(1, 3, 132), MK(2, 2, 133), MK(2, 3, 134), - MKEND }; -static const IndustryTileTable * const _tile_table_candy_factory[] = { +static const std::vector _tile_table_candy_factory { _tile_table_candy_factory_0, _tile_table_candy_factory_1, }; -static const IndustryTileTable _tile_table_battery_farm_0[] = { +static const IndustryTileLayout _tile_table_battery_farm_0 { MK(0, 0, 135), MK(0, 1, 135), MK(0, 2, 135), @@ -955,14 +901,13 @@ static const IndustryTileTable _tile_table_battery_farm_0[] = { MK(4, 1, 135), MK(4, 2, 135), MK(4, 3, 135), - MKEND }; -static const IndustryTileTable * const _tile_table_battery_farm[] = { +static const std::vector _tile_table_battery_farm { _tile_table_battery_farm_0, }; -static const IndustryTileTable _tile_table_cola_wells_0[] = { +static const IndustryTileLayout _tile_table_cola_wells_0 { MK(0, 0, 137), MK(0, 1, 137), MK(0, 2, 137), @@ -971,10 +916,9 @@ static const IndustryTileTable _tile_table_cola_wells_0[] = { MK(1, 2, 137), MK(2, 1, 137), MK(2, 2, 137), - MKEND }; -static const IndustryTileTable _tile_table_cola_wells_1[] = { +static const IndustryTileLayout _tile_table_cola_wells_1 { MK(0, 1, 137), MK(0, 2, 137), MK(0, 3, 137), @@ -982,27 +926,25 @@ static const IndustryTileTable _tile_table_cola_wells_1[] = { MK(1, 1, 137), MK(1, 2, 137), MK(2, 1, 137), - MKEND }; -static const IndustryTileTable * const _tile_table_cola_wells[] = { +static const std::vector _tile_table_cola_wells { _tile_table_cola_wells_0, _tile_table_cola_wells_1, }; -static const IndustryTileTable _tile_table_toy_shop_0[] = { +static const IndustryTileLayout _tile_table_toy_shop_0 { MK(0, 0, 138), MK(0, 1, 139), MK(1, 0, 140), MK(1, 1, 141), - MKEND }; -static const IndustryTileTable * const _tile_table_toy_shop[] = { +static const std::vector _tile_table_toy_shop { _tile_table_toy_shop_0, }; -static const IndustryTileTable _tile_table_toy_factory_0[] = { +static const IndustryTileLayout _tile_table_toy_factory_0 { MK(0, 0, 147), MK(0, 1, 142), MK(1, 0, 147), @@ -1011,45 +953,41 @@ static const IndustryTileTable _tile_table_toy_factory_0[] = { MK(2, 1, 144), MK(3, 0, 146), MK(3, 1, 145), - MKEND }; -static const IndustryTileTable * const _tile_table_toy_factory[] = { +static const std::vector _tile_table_toy_factory { _tile_table_toy_factory_0, }; -static const IndustryTileTable _tile_table_plastic_fountain_0[] = { +static const IndustryTileLayout _tile_table_plastic_fountain_0 { MK(0, 0, 148), MK(0, 1, 151), MK(0, 2, 154), - MKEND }; -static const IndustryTileTable _tile_table_plastic_fountain_1[] = { +static const IndustryTileLayout _tile_table_plastic_fountain_1 { MK(0, 0, 148), MK(1, 0, 151), MK(2, 0, 154), - MKEND }; -static const IndustryTileTable * const _tile_table_plastic_fountain[] = { +static const std::vector _tile_table_plastic_fountain { _tile_table_plastic_fountain_0, _tile_table_plastic_fountain_1, }; -static const IndustryTileTable _tile_table_fizzy_drink_0[] = { +static const IndustryTileLayout _tile_table_fizzy_drink_0 { MK(0, 0, 156), MK(0, 1, 157), MK(1, 0, 158), MK(1, 1, 159), - MKEND }; -static const IndustryTileTable * const _tile_table_fizzy_drink[] = { +static const std::vector _tile_table_fizzy_drink { _tile_table_fizzy_drink_0, }; -static const IndustryTileTable _tile_table_bubble_generator_0[] = { +static const IndustryTileLayout _tile_table_bubble_generator_0 { MK(0, 0, 163), MK(0, 1, 160), MK(1, 0, 163), @@ -1062,25 +1000,23 @@ static const IndustryTileTable _tile_table_bubble_generator_0[] = { MK(1, 3, 161), MK(2, 2, 163), MK(2, 3, 162), - MKEND }; -static const IndustryTileTable * const _tile_table_bubble_generator[] = { +static const std::vector _tile_table_bubble_generator { _tile_table_bubble_generator_0, }; -static const IndustryTileTable _tile_table_toffee_quarry_0[] = { +static const IndustryTileLayout _tile_table_toffee_quarry_0 { MK(0, 0, 164), MK(1, 0, 165), MK(2, 0, 166), - MKEND }; -static const IndustryTileTable * const _tile_table_toffee_quarry[] = { +static const std::vector _tile_table_toffee_quarry { _tile_table_toffee_quarry_0, }; -static const IndustryTileTable _tile_table_sugar_mine_0[] = { +static const IndustryTileLayout _tile_table_sugar_mine_0 { MK(0, 0, 167), MK(0, 1, 168), MK(1, 0, 169), @@ -1089,15 +1025,13 @@ static const IndustryTileTable _tile_table_sugar_mine_0[] = { MK(2, 1, 172), MK(3, 0, 173), MK(3, 1, 174), - MKEND }; -static const IndustryTileTable * const _tile_table_sugar_mine[] = { +static const std::vector _tile_table_sugar_mine { _tile_table_sugar_mine_0, }; #undef MK -#undef MKEND /** Array with saw sound, for sawmill */ static const uint8 _sawmill_sounds[] = { SND_28_SAWMILL }; @@ -1195,7 +1129,7 @@ enum IndustryTypes { #define MI(tbl, sndc, snd, d, pc, ai1, ai2, ai3, ai4, ag1, ag2, ag3, ag4, col, \ c1, c2, c3, proc, p1, r1, p2, r2, m, a1, im1, a2, im2, a3, im3, pr, clim, bev, in, intx, s1, s2, s3) \ - {tbl, lengthof(tbl), d, 0, pc, {c1, c2, c3}, proc, \ + {tbl, d, 0, pc, {c1, c2, c3}, proc, \ {p1, p2, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID}, \ {r1, r2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, m, \ {a1, a2, a3, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID}, \ @@ -1213,7 +1147,7 @@ enum IndustryTypes { industry name building text messages : Closure production up production down */ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { - MI(_tile_table_coal_mine, 0, NULL, + MI(_tile_table_coal_mine, 0, nullptr, 210, 0xB3333333, 2, 3, 0, 0, 8, 8, 0, 0, 1, IT_POWER_STATION, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COAL, 15, CT_INVALID, 0, 5, @@ -1223,7 +1157,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_COAL_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_power_station, 0, NULL, + MI(_tile_table_power_station, 0, nullptr, 240, 0xFFFFFFFF, 2, 2, 0, 0, 5, 5, 0, 0, 184, IT_COAL_MINE, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_INVALID, 0, CT_INVALID, 0, 5, @@ -1243,7 +1177,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_SAWMILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_forest, 0, NULL, + MI(_tile_table_forest, 0, nullptr, 200, 0xBFFFFFFF, 3, 4, 0, 0, 5, 5, 0, 0, 86, IT_SAWMILL, IT_PAPER_MILL, IT_INVALID, CHECK_FOREST, CT_WOOD, 13, CT_INVALID, 0, 30, @@ -1253,7 +1187,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_FOREST, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), - MI(_tile_table_oil_refinery, 0, NULL, + MI(_tile_table_oil_refinery, 0, nullptr, 244, 0xFFFFFFFF, 2, 2, 2, 0, 4, 4, 4, 0, 191, IT_OIL_RIG, IT_INVALID, IT_INVALID, CHECK_REFINERY, CT_GOODS, 0, CT_INVALID, 0, 5, @@ -1263,7 +1197,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_OIL_REFINERY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_oil_rig, 0, NULL, + MI(_tile_table_oil_rig, 0, nullptr, 240, 0x99999999, 6, 0, 0, 0, 0, 0, 0, 0, 152, IT_OIL_REFINERY, IT_INVALID, IT_INVALID, CHECK_OIL_RIG, CT_OIL, 15, CT_PASSENGERS, 2, 5, @@ -1293,7 +1227,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_PRINTING_WORKS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_steel_mill, 0, NULL, + MI(_tile_table_steel_mill, 0, nullptr, 215, 0xFFFFFFFF, 2, 0, 0, 0, 5, 0, 0, 0, 10, IT_IRON_MINE, IT_FACTORY, IT_INVALID, CHECK_NOTHING, CT_STEEL, 0, CT_INVALID, 0, 5, @@ -1313,7 +1247,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_FARM, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), - MI(_tile_table_copper_mine, 0, NULL, + MI(_tile_table_copper_mine, 0, nullptr, 205, 0xB3333333, 0, 0, 3, 0, 0, 0, 4, 0, 10, IT_FACTORY_2, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COPPER_ORE, 10, CT_INVALID, 0, 5, @@ -1323,7 +1257,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_COPPER_ORE_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_oil_well, 0, NULL, + MI(_tile_table_oil_well, 0, nullptr, 220, 0x99999999, 0, 5, 3, 0, 4, 5, 5, 0, 152, IT_OIL_REFINERY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_OIL, 12, CT_INVALID, 0, 5, @@ -1333,7 +1267,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_OIL_WELLS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_bank, 0, NULL, + MI(_tile_table_bank, 0, nullptr, 255, 0xA6666666, 7, 0, 0, 0, 0, 0, 0, 0, 15, IT_BANK_TEMP, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_VALUABLES, 6, CT_INVALID, 0, 5, @@ -1343,7 +1277,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_BANK, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_food_process, 0, NULL, + MI(_tile_table_food_process, 0, nullptr, 206, 0xFFFFFFFF, 0, 2, 2, 0, 0, 3, 4, 0, 55, IT_FRUIT_PLANTATION, IT_FARM, IT_FARM_2, CHECK_NOTHING, CT_FOOD, 0, CT_INVALID, 0, 5, @@ -1363,7 +1297,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_PAPER_MILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_gold_mine, 0, NULL, + MI(_tile_table_gold_mine, 0, nullptr, 208, 0x99999999, 0, 3, 0, 0, 0, 4, 0, 0, 194, IT_BANK_TROPIC_ARCTIC, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_GOLD, 7, CT_INVALID, 0, 5, @@ -1373,7 +1307,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_GOLD_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_bank2, 0, NULL, + MI(_tile_table_bank2, 0, nullptr, 151, 0xA6666666, 0, 3, 3, 0, 0, 6, 5, 0, 15, IT_GOLD_MINE, IT_DIAMOND_MINE, IT_INVALID, CHECK_NOTHING, CT_INVALID, 0, CT_INVALID, 0, 5, @@ -1383,7 +1317,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_diamond_mine, 0, NULL, + MI(_tile_table_diamond_mine, 0, nullptr, 213, 0x99999999, 0, 0, 3, 0, 0, 0, 4, 0, 184, IT_BANK_TROPIC_ARCTIC, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_DIAMONDS, 7, CT_INVALID, 0, 5, @@ -1393,7 +1327,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_DIAMOND_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_iron_mine, 0, NULL, + MI(_tile_table_iron_mine, 0, nullptr, 220, 0xB3333333, 2, 0, 0, 0, 5, 0, 0, 0, 55, IT_STEEL_MILL, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_IRON_ORE, 10, CT_INVALID, 0, 5, @@ -1403,7 +1337,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_IRON_ORE_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_fruit_plantation, 0, NULL, + MI(_tile_table_fruit_plantation, 0, nullptr, 225, 0xBFFFFFFF, 0, 0, 2, 0, 0, 0, 4, 0, 86, IT_FOOD_PROCESS, IT_INVALID, IT_INVALID, CHECK_PLANTATION, CT_FRUIT, 10, CT_INVALID, 0, 15, @@ -1413,7 +1347,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_FRUIT_PLANTATION, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), - MI(_tile_table_rubber_plantation, 0, NULL, + MI(_tile_table_rubber_plantation, 0, nullptr, 218, 0xBFFFFFFF, 0, 0, 3, 0, 0, 0, 4, 0, 39, IT_FACTORY_2, IT_INVALID, IT_INVALID, CHECK_PLANTATION, CT_RUBBER, 10, CT_INVALID, 0, 15, @@ -1423,7 +1357,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_RUBBER_PLANTATION, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), - MI(_tile_table_water_supply, 0, NULL, + MI(_tile_table_water_supply, 0, nullptr, 199, 0xB3333333, 0, 0, 3, 0, 0, 0, 4, 0, 37, IT_WATER_TOWER, IT_INVALID, IT_INVALID, CHECK_WATER, CT_WATER, 12, CT_INVALID, 0, 5, @@ -1433,7 +1367,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_WATER_SUPPLY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_water_tower, 0, NULL, + MI(_tile_table_water_tower, 0, nullptr, 115, 0xFFFFFFFF, 0, 0, 4, 0, 0, 0, 8, 0, 208, IT_WATER_SUPPLY, IT_INVALID, IT_INVALID, CHECK_WATER, CT_INVALID, 0, CT_INVALID, 0, 5, @@ -1453,7 +1387,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_FACTORY_2, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_farm2, 0, NULL, + MI(_tile_table_farm2, 0, nullptr, 250, 0xD9999999, 0, 0, 1, 0, 0, 0, 2, 0, 48, IT_FOOD_PROCESS, IT_INVALID, IT_INVALID, CHECK_PLANTATION, CT_MAIZE, 11, CT_INVALID, 0, 5, @@ -1463,7 +1397,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_FARM_2, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), - MI(_tile_table_lumber_mill, 0, NULL, + MI(_tile_table_lumber_mill, 0, nullptr, 135, 0xFFFFFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 194, IT_FACTORY_2, IT_INVALID, IT_INVALID, CHECK_LUMBERMILL, CT_WOOD, 0, CT_INVALID, 0, 5, @@ -1473,7 +1407,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_LUMBER_MILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_cotton_candy, 0, NULL, + MI(_tile_table_cotton_candy, 0, nullptr, 195, 0xBFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 5, 48, IT_CANDY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COTTON_CANDY, 13, CT_INVALID, 0, 30, @@ -1483,7 +1417,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_COTTON_CANDY_FOREST, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_candy_factory, 0, NULL, + MI(_tile_table_candy_factory, 0, nullptr, 206, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 5, 174, IT_COTTON_CANDY, IT_TOFFEE_QUARRY, IT_SUGAR_MINE, CHECK_NOTHING, CT_CANDY, 0, CT_INVALID, 0, 5, @@ -1493,7 +1427,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_CANDY_FACTORY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_battery_farm, 0, NULL, + MI(_tile_table_battery_farm, 0, nullptr, 187, 0xB3333333, 0, 0, 0, 3, 0, 0, 0, 4, 39, IT_TOY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_BATTERIES, 11, CT_INVALID, 0, 30, @@ -1503,7 +1437,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_BATTERY_FARM, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), - MI(_tile_table_cola_wells, 0, NULL, + MI(_tile_table_cola_wells, 0, nullptr, 193, 0x99999999, 0, 0, 0, 3, 0, 0, 0, 5, 55, IT_FIZZY_DRINK_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COLA, 12, CT_INVALID, 0, 5, @@ -1513,7 +1447,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_COLA_WELLS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_toy_shop, 0, NULL, + MI(_tile_table_toy_shop, 0, nullptr, 133, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 4, 208, IT_TOY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_INVALID, 0, CT_INVALID, 0, 5, @@ -1523,7 +1457,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_TOY_SHOP, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_toy_factory, 0, NULL, + MI(_tile_table_toy_factory, 0, nullptr, 163, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 5, 10, IT_PLASTIC_FOUNTAINS, IT_BATTERY_FARM, IT_TOY_SHOP, CHECK_NOTHING, CT_TOYS, 0, CT_INVALID, 0, 5, @@ -1543,7 +1477,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_fizzy_drink, 0, NULL, + MI(_tile_table_fizzy_drink, 0, nullptr, 177, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 4, 184, IT_COLA_WELLS, IT_BUBBLE_GENERATOR, IT_INVALID, CHECK_NOTHING, CT_FIZZY_DRINKS, 0, CT_INVALID, 0, 5, @@ -1553,7 +1487,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_bubble_generator, 0, NULL, + MI(_tile_table_bubble_generator, 0, nullptr, 203, 0xB3333333, 0, 0, 0, 3, 0, 0, 0, 5, 152, IT_FIZZY_DRINK_FACTORY, IT_INVALID, IT_INVALID, CHECK_BUBBLEGEN, CT_BUBBLES, 13, CT_INVALID, 0, 5, @@ -1563,7 +1497,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_BUBBLE_GENERATOR, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_toffee_quarry, 0, NULL, + MI(_tile_table_toffee_quarry, 0, nullptr, 213, 0xCCCCCCCC, 0, 0, 0, 3, 0, 0, 0, 5, 194, IT_CANDY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_TOFFEE, 10, CT_INVALID, 0, 5, @@ -1573,7 +1507,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { STR_INDUSTRY_NAME_TOFFEE_QUARRY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), - MI(_tile_table_sugar_mine, 0, NULL, + MI(_tile_table_sugar_mine, 0, nullptr, 210, 0xBFFFFFFF, 0, 0, 0, 2, 0, 0, 0, 4, 15, IT_CANDY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_SUGAR, 11, CT_INVALID, 0, 5, diff --git a/src/table/cargo_const.h b/src/table/cargo_const.h index c2ce5bc78b..bc3f139563 100644 --- a/src/table/cargo_const.h +++ b/src/table/cargo_const.h @@ -11,7 +11,7 @@ /** Construction macro for a #CargoSpec structure. */ #define MK(bt, label, c, e, f, g, h, fr, te, ks1, ks2, ks3, ks4, ks5, l, m, cmult) \ - {bt, label, c, c, e, cmult, f, {g, h}, fr, te, 0, 0, ks1, ks2, ks3, ks4, ks5, l, m, NULL, NULL, 0} + {bt, label, c, c, e, cmult, f, {g, h}, fr, te, 0, 0, ks1, ks2, ks3, ks4, ks5, l, m, nullptr, nullptr, 0} /** Cargo types available by default. */ static const CargoSpec _default_cargo[] = { MK( 0, 'PASS', 152, 1, 3185, 0, 24, false, TE_PASSENGERS, diff --git a/src/table/company_settings.ini b/src/table/company_settings.ini index a6e873f659..3ff5d64299 100644 --- a/src/table/company_settings.ini +++ b/src/table/company_settings.ini @@ -29,8 +29,8 @@ interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index bcce65801b..d68f4bfc28 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -18,13 +18,13 @@ SDT_END = SDT_END() [defaults] flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -guiflags = 0 +guiflags = SGF_NONE interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED @@ -57,7 +57,7 @@ max = MAX_YEAR base = CurrencySpec var = prefix type = SLE_STRBQ -def = NULL +def = nullptr [SDT_STR] base = CurrencySpec diff --git a/src/table/elrail_data.h b/src/table/elrail_data.h index 6915360035..df5788fa87 100644 --- a/src/table/elrail_data.h +++ b/src/table/elrail_data.h @@ -412,7 +412,7 @@ static const SortableSpriteStruct RailCatenarySpriteData_Tunnel[] = { * Identifiers for Wires: *
      1. Direction of the wire
      2. *
      3. Slope of the tile for diagonals, placement inside the track for horiz/vertical pieces
      4. - *
      5. Place where a pylon shoule be
      + *
    • Place where a pylon should be
    • * Identifiers for Pylons: *
      1. Direction of the wire
      2. *
      3. Slope of the tile
      4. diff --git a/src/table/engines.h b/src/table/engines.h index 3b29a8dc17..7a40e4f7ed 100644 --- a/src/table/engines.h +++ b/src/table/engines.h @@ -388,7 +388,7 @@ static const EngineInfo _orig_engine_info[] = { * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Air drag value depends on the top speed of the vehicle. */ -#define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, {j}, d, e, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0 } +#define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, j, d, e, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0 } #define M RAILVEH_MULTIHEAD #define W RAILVEH_WAGON #define G RAILVEH_SINGLEHEAD @@ -669,7 +669,7 @@ static const AircraftVehicleInfo _orig_aircraft_vehicle_info[] = { * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Air drag value depends on the top speed of the vehicle. */ -#define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e, f, g, h, 76, 0, VE_DEFAULT, 0 } +#define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e, f, g, h, 76, 0, VE_DEFAULT, 0, ROADTYPE_ROAD } static const RoadVehicleInfo _orig_road_vehicle_info[] = { /* image_index sfx max_speed power * | cost_factor | | capacity | diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index 624d475c31..b18ed9d75f 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -12,7 +12,7 @@ static uint16 _old_diff_custom[GAME_DIFFICULTY_NUM]; uint8 _old_diff_level; ///< Old difficulty level from old savegames uint8 _old_units; ///< Old units from old savegames -/* Most of these strings are used both for gameopt-backward compatability +/* Most of these strings are used both for gameopt-backward compatibility * and the settings tables. The rest is here for consistency. */ static const char *_locale_currencies = "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|RON|RUR|SIT|SEK|YTL|SKK|BRL|EEK|custom"; static const char *_locale_units = "imperial|metric|si"; @@ -21,9 +21,7 @@ static const char *_climates = "temperate|arctic|tropic|toyland"; static const char *_autosave_interval = "off|monthly|quarterly|half year|yearly"; static const char *_roadsides = "left|right"; static const char *_savegame_date = "long|short|iso"; -#ifdef ENABLE_NETWORK static const char *_server_langs = "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN|AFRIKAANS|CROATIAN|CATALAN|ESTONIAN|GALICIAN|GREEK|LATVIAN"; -#endif /* ENABLE_NETWORK */ static const char *_osk_activation = "disabled|double|single|immediately"; static const char *_settings_profiles = "easy|medium|hard"; static const char *_news_display = "off|summarized|full"; @@ -52,13 +50,13 @@ SDT_END = SDT_END() [defaults] flags = 0 -guiflags = 0 +guiflags = SGF_NONE interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED @@ -76,7 +74,7 @@ length = 17 def = 0 min = 0 max = 0 -full = NULL +full = nullptr to = SLV_4 [SDTG_GENERAL] @@ -90,7 +88,7 @@ length = 18 def = 0 min = 0 max = 0 -full = NULL +full = nullptr from = SLV_4 ## diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 787a82dd86..f920f515d2 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -25,13 +25,13 @@ SDTG_END = SDTG_END() [defaults] flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -guiflags = 0 +guiflags = SGF_NONE interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED @@ -64,55 +64,55 @@ cat = SC_BASIC name = ""graphicsset"" type = SLE_STRQ var = BaseGraphics::ini_set -def = NULL +def = nullptr cat = SC_BASIC [SDTG_STR] name = ""soundsset"" type = SLE_STRQ var = BaseSounds::ini_set -def = NULL +def = nullptr cat = SC_BASIC [SDTG_STR] name = ""musicset"" type = SLE_STRQ var = BaseMusic::ini_set -def = NULL +def = nullptr cat = SC_BASIC [SDTG_STR] name = ""videodriver"" type = SLE_STRQ var = _ini_videodriver -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_STR] name = ""musicdriver"" type = SLE_STRQ var = _ini_musicdriver -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_STR] name = ""sounddriver"" type = SLE_STRQ var = _ini_sounddriver -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_STR] name = ""blitter"" type = SLE_STRQ var = _ini_blitter -def = NULL +def = nullptr [SDTG_STR] name = ""language"" type = SLE_STRB var = _config_language_file -def = NULL +def = nullptr cat = SC_BASIC ; workaround for implicit lengthof() in SDTG_LIST @@ -128,14 +128,14 @@ cat = SC_BASIC name = ""screenshot_format"" type = SLE_STRB var = _screenshot_format_name -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_STR] name = ""savegame_format"" type = SLE_STRB var = _savegame_format -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_BOOL] @@ -144,35 +144,35 @@ var = _rightclick_emulate def = false [SDTG_STR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""small_font"" type = SLE_STRB var = _freetype.small.font -def = NULL +def = nullptr [SDTG_STR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""medium_font"" type = SLE_STRB var = _freetype.medium.font -def = NULL +def = nullptr [SDTG_STR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""large_font"" type = SLE_STRB var = _freetype.large.font -def = NULL +def = nullptr [SDTG_STR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""mono_font"" type = SLE_STRB var = _freetype.mono.font -def = NULL +def = nullptr [SDTG_VAR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""small_size"" type = SLE_UINT var = _freetype.small.size @@ -181,7 +181,7 @@ min = 0 max = 72 [SDTG_VAR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""medium_size"" type = SLE_UINT var = _freetype.medium.size @@ -190,7 +190,7 @@ min = 0 max = 72 [SDTG_VAR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""large_size"" type = SLE_UINT var = _freetype.large.size @@ -199,7 +199,7 @@ min = 0 max = 72 [SDTG_VAR] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""mono_size"" type = SLE_UINT var = _freetype.mono.size @@ -208,25 +208,25 @@ min = 0 max = 72 [SDTG_BOOL] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""small_aa"" var = _freetype.small.aa def = false [SDTG_BOOL] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""medium_aa"" var = _freetype.medium.aa def = false [SDTG_BOOL] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""large_aa"" var = _freetype.large.aa def = false [SDTG_BOOL] -ifdef = WITH_FREETYPE +ifdef = HAS_TRUETYPE_FONT name = ""mono_aa"" var = _freetype.mono.aa def = false @@ -280,14 +280,14 @@ cat = SC_BASIC name = ""keyboard"" type = SLE_STRB var = _keyboard_opt[0] -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_STR] name = ""keyboard_caps"" type = SLE_STRB var = _keyboard_opt[1] -def = NULL +def = nullptr cat = SC_EXPERT [SDTG_VAR] diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 19b411fed0..89c289355a 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -11,18 +11,19 @@ #include "../newgrf_house.h" #include "../newgrf_engine.h" +#include "../newgrf_roadtype.h" /* Helper for filling property tables */ #define NIP(prop, base, variable, type, name) { name, (ptrdiff_t)cpp_offsetof(base, variable), cpp_sizeof(base, variable), prop, type } -#define NIP_END() { NULL, 0, 0, 0, 0 } +#define NIP_END() { nullptr, 0, 0, 0, 0 } /* Helper for filling callback tables */ #define NIC(cb_id, base, variable, bit) { #cb_id, (ptrdiff_t)cpp_offsetof(base, variable), cpp_sizeof(base, variable), bit, cb_id } -#define NIC_END() { NULL, 0, 0, 0, 0 } +#define NIC_END() { nullptr, 0, 0, 0, 0 } /* Helper for filling variable tables */ #define NIV(var, name) { name, var } -#define NIV_END() { NULL, 0 } +#define NIV_END() { nullptr, 0 } /*** NewGRF Vehicles ***/ @@ -58,7 +59,7 @@ static const NIVariable _niv_vehicles[] = { NIV(0x47, "vehicle cargo info"), NIV(0x48, "vehicle type info"), NIV(0x49, "year of construction"), - NIV(0x4A, "current rail type info"), + NIV(0x4A, "current rail/road type info"), NIV(0x4B, "long date of last service"), NIV(0x4C, "current max speed"), NIV(0x4D, "position in articulated vehicle"), @@ -69,14 +70,14 @@ static const NIVariable _niv_vehicles[] = { }; class NIHVehicle : public NIHelper { - bool IsInspectable(uint index) const { return Vehicle::Get(index)->GetGRF() != NULL; } - uint GetParent(uint index) const { const Vehicle *first = Vehicle::Get(index)->First(); return GetInspectWindowNumber(GetGrfSpecFeature(first->type), first->index); } - const void *GetInstance(uint index)const { return Vehicle::Get(index); } - const void *GetSpec(uint index) const { return Vehicle::Get(index)->GetEngine(); } - void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); } - uint32 GetGRFID(uint index) const { return Vehicle::Get(index)->GetGRFID(); } + bool IsInspectable(uint index) const override { return Vehicle::Get(index)->GetGRF() != nullptr; } + uint GetParent(uint index) const override { const Vehicle *first = Vehicle::Get(index)->First(); return GetInspectWindowNumber(GetGrfSpecFeature(first->type), first->index); } + const void *GetInstance(uint index)const override { return Vehicle::Get(index); } + const void *GetSpec(uint index) const override { return Vehicle::Get(index)->GetEngine(); } + void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); } + uint32 GetGRFID(uint index) const override { return Vehicle::Get(index)->GetGRFID(); } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { Vehicle *v = Vehicle::Get(index); VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED); @@ -85,7 +86,7 @@ class NIHVehicle : public NIHelper { }; static const NIFeature _nif_vehicle = { - NULL, + nullptr, _nic_vehicles, _niv_vehicles, new NIHVehicle(), @@ -132,14 +133,14 @@ static const NIVariable _niv_stations[] = { }; class NIHStation : public NIHelper { - bool IsInspectable(uint index) const { return GetStationSpec(index) != NULL; } - uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); } - const void *GetInstance(uint index)const { return NULL; } - const void *GetSpec(uint index) const { return GetStationSpec(index); } - void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } - uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; } + bool IsInspectable(uint index) const override { return GetStationSpec(index) != nullptr; } + uint GetParent(uint index) const override { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); } + const void *GetInstance(uint index)const override { return nullptr; } + const void *GetSpec(uint index) const override { return GetStationSpec(index); } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } + uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { StationResolverObject ro(GetStationSpec(index), Station::GetByTile(index), index); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); @@ -147,7 +148,7 @@ class NIHStation : public NIHelper { }; static const NIFeature _nif_station = { - NULL, + nullptr, _nic_stations, _niv_stations, new NIHStation(), @@ -197,14 +198,14 @@ static const NIVariable _niv_house[] = { }; class NIHHouse : public NIHelper { - bool IsInspectable(uint index) const { return HouseSpec::Get(GetHouseType(index))->grf_prop.grffile != NULL; } - uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, GetTownIndex(index)); } - const void *GetInstance(uint index)const { return NULL; } - const void *GetSpec(uint index) const { return HouseSpec::Get(GetHouseType(index)); } - void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); } - uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? HouseSpec::Get(GetHouseType(index))->grf_prop.grffile->grfid : 0; } + bool IsInspectable(uint index) const override { return HouseSpec::Get(GetHouseType(index))->grf_prop.grffile != nullptr; } + uint GetParent(uint index) const override { return GetInspectWindowNumber(GSF_FAKE_TOWNS, GetTownIndex(index)); } + const void *GetInstance(uint index)const override { return nullptr; } + const void *GetSpec(uint index) const override { return HouseSpec::Get(GetHouseType(index)); } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); } + uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? HouseSpec::Get(GetHouseType(index))->grf_prop.grffile->grfid : 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { HouseResolverObject ro(GetHouseType(index), index, Town::GetByTile(index)); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); @@ -212,7 +213,7 @@ class NIHHouse : public NIHelper { }; static const NIFeature _nif_house = { - NULL, + nullptr, _nic_house, _niv_house, new NIHHouse(), @@ -247,14 +248,14 @@ static const NIVariable _niv_industrytiles[] = { }; class NIHIndustryTile : public NIHelper { - bool IsInspectable(uint index) const { return GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile != NULL; } - uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_INDUSTRIES, GetIndustryIndex(index)); } - const void *GetInstance(uint index)const { return NULL; } - const void *GetSpec(uint index) const { return GetIndustryTileSpec(GetIndustryGfx(index)); } - void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); } - uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile->grfid : 0; } + bool IsInspectable(uint index) const override { return GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile != nullptr; } + uint GetParent(uint index) const override { return GetInspectWindowNumber(GSF_INDUSTRIES, GetIndustryIndex(index)); } + const void *GetInstance(uint index)const override { return nullptr; } + const void *GetSpec(uint index) const override { return GetIndustryTileSpec(GetIndustryGfx(index)); } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); } + uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile->grfid : 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { IndustryTileResolverObject ro(GetIndustryGfx(index), index, Industry::GetByTile(index)); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); @@ -262,7 +263,7 @@ class NIHIndustryTile : public NIHelper { }; static const NIFeature _nif_industrytile = { - NULL, + nullptr, _nic_industrytiles, _niv_industrytiles, new NIHIndustryTile(), @@ -346,26 +347,26 @@ static const NIVariable _niv_industries[] = { }; class NIHIndustry : public NIHelper { - bool IsInspectable(uint index) const { return GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile != NULL; } - uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Industry::Get(index)->town->index); } - const void *GetInstance(uint index)const { return Industry::Get(index); } - const void *GetSpec(uint index) const { return GetIndustrySpec(Industry::Get(index)->type); } - void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); } - uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile->grfid : 0; } + bool IsInspectable(uint index) const override { return GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile != nullptr; } + uint GetParent(uint index) const override { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Industry::Get(index)->town->index); } + const void *GetInstance(uint index)const override { return Industry::Get(index); } + const void *GetSpec(uint index) const override { return GetIndustrySpec(Industry::Get(index)->type); } + void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); } + uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile->grfid : 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { Industry *i = Industry::Get(index); IndustriesResolverObject ro(i->location.tile, i, i->type); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } - uint GetPSASize(uint index, uint32 grfid) const { return cpp_lengthof(PersistentStorage, storage); } + uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); } - const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const + const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const override { const Industry *i = (const Industry *)this->GetInstance(index); - if (i->psa == NULL) return NULL; + if (i->psa == nullptr) return nullptr; return (int32 *)(&i->psa->storage); } }; @@ -411,14 +412,14 @@ static const NIVariable _niv_objects[] = { }; class NIHObject : public NIHelper { - bool IsInspectable(uint index) const { return ObjectSpec::GetByTile(index)->grf_prop.grffile != NULL; } - uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Object::GetByTile(index)->town->index); } - const void *GetInstance(uint index)const { return Object::GetByTile(index); } - const void *GetSpec(uint index) const { return ObjectSpec::GetByTile(index); } - void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); } - uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; } + bool IsInspectable(uint index) const override { return ObjectSpec::GetByTile(index)->grf_prop.grffile != nullptr; } + uint GetParent(uint index) const override { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Object::GetByTile(index)->town->index); } + const void *GetInstance(uint index)const override { return Object::GetByTile(index); } + const void *GetSpec(uint index) const override { return ObjectSpec::GetByTile(index); } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); } + uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { ObjectResolverObject ro(ObjectSpec::GetByTile(index), Object::GetByTile(index), index); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); @@ -426,7 +427,7 @@ class NIHObject : public NIHelper { }; static const NIFeature _nif_object = { - NULL, + nullptr, _nic_objects, _niv_objects, new NIHObject(), @@ -445,25 +446,25 @@ static const NIVariable _niv_railtypes[] = { }; class NIHRailType : public NIHelper { - bool IsInspectable(uint index) const { return true; } - uint GetParent(uint index) const { return UINT32_MAX; } - const void *GetInstance(uint index)const { return NULL; } - const void *GetSpec(uint index) const { return NULL; } - void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } - uint32 GetGRFID(uint index) const { return 0; } + bool IsInspectable(uint index) const override { return true; } + uint GetParent(uint index) const override { return UINT32_MAX; } + const void *GetInstance(uint index)const override { return nullptr; } + const void *GetSpec(uint index) const override { return nullptr; } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } + uint32 GetGRFID(uint index) const override { return 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { /* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype. * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */ - RailTypeResolverObject ro(NULL, index, TCX_NORMAL, RTSG_END); + RailTypeResolverObject ro(nullptr, index, TCX_NORMAL, RTSG_END); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_railtype = { - NULL, - NULL, + nullptr, + nullptr, _niv_railtypes, new NIHRailType(), }; @@ -481,14 +482,14 @@ static const NICallback _nic_airporttiles[] = { }; class NIHAirportTile : public NIHelper { - bool IsInspectable(uint index) const { return AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile != NULL; } - uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); } - const void *GetInstance(uint index)const { return NULL; } - const void *GetSpec(uint index) const { return AirportTileSpec::Get(GetAirportGfx(index)); } - void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } - uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile->grfid : 0; } + bool IsInspectable(uint index) const override { return AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile != nullptr; } + uint GetParent(uint index) const override { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); } + const void *GetInstance(uint index)const override { return nullptr; } + const void *GetSpec(uint index) const override { return AirportTileSpec::Get(GetAirportGfx(index)); } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } + uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile->grfid : 0; } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { AirportTileResolverObject ro(AirportTileSpec::GetByTile(index), index, Station::GetByTile(index)); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); @@ -496,7 +497,7 @@ class NIHAirportTile : public NIHelper { }; static const NIFeature _nif_airporttile = { - NULL, + nullptr, _nic_airporttiles, _niv_industrytiles, // Yes, they share this (at least now) new NIHAirportTile(), @@ -519,22 +520,22 @@ static const NIVariable _niv_towns[] = { }; class NIHTown : public NIHelper { - bool IsInspectable(uint index) const { return Town::IsValidID(index); } - uint GetParent(uint index) const { return UINT32_MAX; } - const void *GetInstance(uint index)const { return Town::Get(index); } - const void *GetSpec(uint index) const { return NULL; } - void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_TOWN_NAME, index); } - uint32 GetGRFID(uint index) const { return 0; } - bool PSAWithParameter() const { return true; } - uint GetPSASize(uint index, uint32 grfid) const { return cpp_lengthof(PersistentStorage, storage); } + bool IsInspectable(uint index) const override { return Town::IsValidID(index); } + uint GetParent(uint index) const override { return UINT32_MAX; } + const void *GetInstance(uint index)const override { return Town::Get(index); } + const void *GetSpec(uint index) const override { return nullptr; } + void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_TOWN_NAME, index); } + uint32 GetGRFID(uint index) const override { return 0; } + bool PSAWithParameter() const override { return true; } + uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); } - /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const + uint Resolve(uint index, uint var, uint param, bool *avail) const override { - TownResolverObject ro(NULL, Town::Get(index), true); + TownResolverObject ro(nullptr, Town::Get(index), true); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } - const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const + const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const override { Town *t = Town::Get(index); @@ -543,17 +544,59 @@ class NIHTown : public NIHelper { if ((*iter)->grfid == grfid) return (int32 *)(&(*iter)->storage[0]); } - return NULL; + return nullptr; } }; static const NIFeature _nif_town = { - NULL, - NULL, + nullptr, + nullptr, _niv_towns, new NIHTown(), }; +/*** NewGRF road types ***/ + +static const NIVariable _niv_roadtypes[] = { + NIV(0x40, "terrain type"), + NIV(0x41, "enhanced tunnels"), + NIV(0x42, "level crossing status"), + NIV(0x43, "construction date"), + NIV(0x44, "town zone"), + NIV_END() +}; + +class NIHRoadType : public NIHelper { + bool IsInspectable(uint index) const override { return true; } + uint GetParent(uint index) const override { return UINT32_MAX; } + const void *GetInstance(uint index) const override { return nullptr; } + const void *GetSpec(uint index) const override { return nullptr; } + void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } + uint32 GetGRFID(uint index) const override { return 0; } + + uint Resolve(uint index, uint var, uint param, bool *avail) const override + { + /* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype. + * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */ + RoadTypeResolverObject ro(nullptr, index, TCX_NORMAL, ROTSG_END); + return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); + } +}; + +static const NIFeature _nif_roadtype = { + nullptr, + nullptr, + _niv_roadtypes, + new NIHRoadType(), +}; + +static const NIFeature _nif_tramtype = { + nullptr, + nullptr, + _niv_roadtypes, + new NIHRoadType(), +}; + /** Table with all NIFeatures. */ static const NIFeature * const _nifeatures[] = { &_nif_vehicle, // GSF_TRAINS @@ -561,19 +604,21 @@ static const NIFeature * const _nifeatures[] = { &_nif_vehicle, // GSF_SHIPS &_nif_vehicle, // GSF_AIRCRAFT &_nif_station, // GSF_STATIONS - NULL, // GSF_CANALS (no callbacks/action2 implemented) - NULL, // GSF_BRIDGES (no callbacks/action2) + nullptr, // GSF_CANALS (no callbacks/action2 implemented) + nullptr, // GSF_BRIDGES (no callbacks/action2) &_nif_house, // GSF_HOUSES - NULL, // GSF_GLOBALVAR (has no "physical" objects) + nullptr, // GSF_GLOBALVAR (has no "physical" objects) &_nif_industrytile, // GSF_INDUSTRYTILES &_nif_industry, // GSF_INDUSTRIES - NULL, // GSF_CARGOES (has no "physical" objects) - NULL, // GSF_SOUNDFX (has no "physical" objects) - NULL, // GSF_AIRPORTS (feature not implemented) - NULL, // GSF_SIGNALS (feature not implemented) + nullptr, // GSF_CARGOES (has no "physical" objects) + nullptr, // GSF_SOUNDFX (has no "physical" objects) + nullptr, // GSF_AIRPORTS (feature not implemented) + nullptr, // GSF_SIGNALS (feature not implemented) &_nif_object, // GSF_OBJECTS &_nif_railtype, // GSF_RAILTYPES &_nif_airporttile, // GSF_AIRPORTTILES + &_nif_roadtype, // GSF_ROADTYPES + &_nif_tramtype, // GSF_TRAMTYPES &_nif_town, // GSF_FAKE_TOWNS }; assert_compile(lengthof(_nifeatures) == GSF_FAKE_END); diff --git a/src/table/railtypes.h b/src/table/railtypes.h index f52a1524bd..829b223b5e 100644 --- a/src/table/railtypes.h +++ b/src/table/railtypes.h @@ -112,8 +112,8 @@ static const RailtypeInfo _original_railtypes[] = { /* sort order */ 0 << 4 | 7, - { NULL }, - { NULL }, + { nullptr }, + { nullptr }, }, /** Electrified railway */ @@ -156,7 +156,7 @@ static const RailtypeInfo _original_railtypes[] = { STR_RAIL_MENU_ELRAIL_CONSTRUCTION, STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION, STR_REPLACE_ELRAIL_VEHICLES, - STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE, + STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE, }, /* Offset of snow tiles */ @@ -213,8 +213,8 @@ static const RailtypeInfo _original_railtypes[] = { /* sort order */ 1 << 4 | 7, - { NULL }, - { NULL }, + { nullptr }, + { nullptr }, }, /** Monorail */ @@ -310,8 +310,8 @@ static const RailtypeInfo _original_railtypes[] = { /* sort order */ 2 << 4 | 7, - { NULL }, - { NULL }, + { nullptr }, + { nullptr }, }, /** Maglev */ @@ -407,8 +407,8 @@ static const RailtypeInfo _original_railtypes[] = { /* sort order */ 3 << 4 | 7, - { NULL }, - { NULL }, + { nullptr }, + { nullptr }, }, }; diff --git a/src/table/road_land.h b/src/table/road_land.h index 19b8f57119..2b3a4177f8 100644 --- a/src/table/road_land.h +++ b/src/table/road_land.h @@ -41,35 +41,6 @@ static const DrawTileSprites _road_depot[] = { { {0xA4A, PAL_NONE}, _road_depot_NW } }; -static const DrawTileSeqStruct _tram_depot_NE[] = { - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x35) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 15, 16, 1) - TILE_SEQ_END() -}; - -static const DrawTileSeqStruct _tram_depot_SE[] = { - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x31) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 1, 16) - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x32) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) - TILE_SEQ_END() -}; - -static const DrawTileSeqStruct _tram_depot_SW[] = { - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x33) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 1) - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x34) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 15, 16, 1) - TILE_SEQ_END() -}; - -static const DrawTileSeqStruct _tram_depot_NW[] = { - TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x36) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) - TILE_SEQ_END() -}; - -static const DrawTileSprites _tram_depot[] = { - { {0xA4A, PAL_NONE}, _tram_depot_NE }, - { {0xA4A, PAL_NONE}, _tram_depot_SE }, - { {0xA4A, PAL_NONE}, _tram_depot_SW }, - { {0xA4A, PAL_NONE}, _tram_depot_NW } -}; - /* Sprite layout for level crossings. The SpriteIDs are actually offsets * from the base SpriteID returned from the NewGRF sprite resolver. */ static const DrawTileSeqStruct _crossing_layout_ALL[] = { diff --git a/src/table/roadtypes.h b/src/table/roadtypes.h new file mode 100644 index 0000000000..4fcd3d6e76 --- /dev/null +++ b/src/table/roadtypes.h @@ -0,0 +1,183 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file roadtypes.h + * All the roadtype-specific information is stored here. + */ + +#ifndef ROADTYPES_H +#define ROADTYPES_H + +/** + * Global Roadtype definition + */ +static const RoadTypeInfo _original_roadtypes[] = { + /* Road */ + { + /* GUI sprites */ + { + SPR_IMG_ROAD_X_DIR, + SPR_IMG_ROAD_Y_DIR, + SPR_IMG_AUTOROAD, + SPR_IMG_ROAD_DEPOT, + SPR_IMG_ROAD_TUNNEL, + SPR_IMG_CONVERT_ROAD, + }, + + { + SPR_CURSOR_ROAD_NESW, + SPR_CURSOR_ROAD_NWSE, + SPR_CURSOR_AUTOROAD, + SPR_CURSOR_ROAD_DEPOT, + SPR_CURSOR_ROAD_TUNNEL, + SPR_CURSOR_CONVERT_ROAD, + }, + + /* strings */ + { + STR_ROAD_NAME_ROAD, + STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, + STR_ROAD_MENU_ROAD_CONSTRUCTION, + STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION, + STR_REPLACE_ROAD_VEHICLES, + STR_ENGINE_PREVIEW_ROAD_VEHICLE, + + STR_ERROR_CAN_T_BUILD_ROAD_HERE, + STR_ERROR_CAN_T_REMOVE_ROAD_FROM, + STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, + { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, + { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, + STR_ERROR_CAN_T_CONVERT_ROAD, + { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, + { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, + }, + + /* Powered roadtypes */ + ROADTYPES_ROAD, + + /* flags */ + ROTFB_TOWN_BUILD, + + /* cost multiplier */ + 8, + + /* maintenance cost multiplier */ + 16, + + /* max speed */ + 0, + + /* road type label */ + 'ROAD', + + /* alternate labels */ + RoadTypeLabelList(), + + /* map colour */ + 0x01, + + /* introduction date */ + MIN_YEAR, + + /* roadtypes required for this to be introduced */ + ROADTYPES_NONE, + + /* introduction road types */ + ROADTYPES_ROAD, + + /* sort order */ + 0x07, + + { nullptr }, + { nullptr }, + }, + + /* Electrified Tram */ + { + /* GUI sprites */ + { + SPR_IMG_TRAMWAY_X_DIR, + SPR_IMG_TRAMWAY_Y_DIR, + SPR_IMG_AUTOTRAM, + SPR_IMG_ROAD_DEPOT, + SPR_IMG_ROAD_TUNNEL, + SPR_IMG_CONVERT_TRAM, + }, + + { + SPR_CURSOR_TRAMWAY_NESW, + SPR_CURSOR_TRAMWAY_NWSE, + SPR_CURSOR_AUTOTRAM, + SPR_CURSOR_ROAD_DEPOT, + SPR_CURSOR_ROAD_TUNNEL, + SPR_CURSOR_CONVERT_TRAM, + }, + + /* strings */ + { + STR_ROAD_NAME_TRAM, + STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, + STR_ROAD_MENU_TRAM_CONSTRUCTION, + STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION, + STR_REPLACE_TRAM_VEHICLES, + STR_ENGINE_PREVIEW_TRAM_VEHICLE, + + STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, + STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, + STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, + { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, + { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, + STR_ERROR_CAN_T_CONVERT_TRAMWAY, + { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, + { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, + }, + + /* Powered roadtypes */ + ROADTYPES_TRAM, + + /* flags */ + ROTFB_CATENARY | ROTFB_NO_HOUSES, + + /* cost multiplier */ + 16, + + /* maintenance cost multiplier */ + 24, + + /* max speed */ + 0, + + /* road type label */ + 'ELRL', + + /* alternate labels */ + RoadTypeLabelList(), + + /* map colour */ + 0x01, + + /* introduction date */ + INVALID_DATE, + + /* roadtypes required for this to be introduced */ + ROADTYPES_NONE, + + /* introduction road types */ + ROADTYPES_TRAM, + + /* sort order */ + 0x17, + + { nullptr }, + { nullptr }, + }, +}; + +#endif /* ROADTYPES_H */ diff --git a/src/table/roadveh_movement.h b/src/table/roadveh_movement.h index 5b202b2b59..f6f75c834b 100644 --- a/src/table/roadveh_movement.h +++ b/src/table/roadveh_movement.h @@ -1445,39 +1445,39 @@ static const RoadDriveEntry * const _road_tram_drive_data[] = { _roadveh_drive_data_29, _roadveh_tram_turn_sw_1, _roadveh_tram_turn_nw_1, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, }; static const RoadDriveEntry * const * const _road_drive_data[2] = { diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index f475e305bc..65fc489fac 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -33,7 +33,7 @@ static size_t ConvertLandscape(const char *value); * Thse are for members in the struct described by the current * #SettingDesc list / .ini file. Here, 'base' specifies type of the * struct while 'var' points out the member of the struct (the actual - * struct to store it in is implicitely defined by the #SettingDesc + * struct to store it in is implicitly defined by the #SettingDesc * list / .ini file preamble the entry is in). * * The something part defines the type of variable to store. There are a @@ -57,24 +57,24 @@ static size_t ConvertLandscape(const char *value); */ #define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat)\ - {name, (const void*)(size_t)(def), {(byte)cmd}, {(uint16)guiflags}, min, max, interval, many, str, strhelp, strval, proc, load, cat} + {name, (const void*)(size_t)(def), cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat} /* Macros for various objects to go in the configuration file. * This section is for global variables */ #define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat)\ - {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, NULL, cat), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)} + {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, nullptr, cat), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)} #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, sizeof(var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat) @@ -83,9 +83,9 @@ static size_t ConvertLandscape(const char *value); SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat) #define SDTG_NULL(length, from, to)\ - {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_NULL(length, from, to)} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE}, SLEG_NULL(length, from, to)} -#define SDTG_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_END()} +#define SDTG_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE}, SLEG_END()} /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ @@ -93,44 +93,44 @@ static size_t ConvertLandscape(const char *value); {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)} #define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\ - SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, NULL, from, to, cat) + SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat) #define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) + SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat) #define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) + SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat) #define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) + SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat) #define SDT_CHR(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) + SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat) #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat)\ SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat) #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat)\ - SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, NULL, from, to, cat) + SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, nullptr, from, to, cat) #define SDT_NULL(length, from, to)\ - {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_CONDNULL(length, from, to)} + {{"", nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE}, SLE_CONDNULL(length, from, to)} #define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTC_STR(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ - SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, sizeof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) + SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, sizeof(_settings_client.var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, from, to, cat) #define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat) -#define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_END()} +#define SDT_END() {{nullptr, nullptr, SDT_NUMX, SGF_NONE, 0, 0, 0, nullptr, STR_NULL, STR_NULL, STR_NULL, nullptr, nullptr, SC_NONE}, SLE_END()} diff --git a/src/table/settings.ini b/src/table/settings.ini index b18ca34f4a..8553238edd 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -44,12 +44,11 @@ static bool ZoomMinMaxChanged(int32 p1); static bool MaxVehiclesChanged(int32 p1); static bool InvalidateShipPathCache(int32 p1); -#ifdef ENABLE_NETWORK static bool UpdateClientName(int32 p1); static bool UpdateServerPassword(int32 p1); static bool UpdateRconPassword(int32 p1); static bool UpdateClientConfigValues(int32 p1); -#endif /* ENABLE_NETWORK */ + /* End - Callback Functions for the various settings */ /* Some settings do not need to be synchronised when playing in multiplayer. @@ -82,13 +81,13 @@ SDT_END = SDT_END() [defaults] flags = 0 -guiflags = 0 +guiflags = SGF_NONE interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED @@ -96,7 +95,7 @@ cat = SC_ADVANCED ; Saved settings variables. -; Do not ADD or REMOVE something in this "difficulty.XXX" table or before it. It breaks savegame compatability. +; Do not ADD or REMOVE something in this "difficulty.XXX" table or before it. It breaks savegame compatibility. [SDT_VAR] base = GameSettings var = difficulty.max_no_competitors @@ -618,6 +617,21 @@ def = true str = STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS strhelp = STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT +[SDT_VAR] +base = GameSettings +var = economy.town_cargogen_mode +type = SLE_UINT8 +from = SLV_TOWN_CARGOGEN +guiflags = SGF_MULTISTRING +def = TCGM_BITCOUNT +min = TCGM_BEGIN +max = TCGM_END - 1 +interval = 1 +str = STR_CONFIG_SETTING_TOWN_CARGOGENMODE +strhelp = STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT +strval = STR_CONFIG_SETTING_TOWN_CARGOGENMODE_ORIGINAL +cat = SC_ADVANCED + ; link graph [SDT_VAR] @@ -938,12 +952,12 @@ type = SLE_UINT8 from = SLV_87 guiflags = SGF_MULTISTRING def = 2 -min = 0 +min = 1 max = 2 interval = 1 str = STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS strhelp = STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT -strval = STR_CONFIG_SETTING_PATHFINDER_OPF +strval = STR_CONFIG_SETTING_PATHFINDER_NPF proc = InvalidateShipPathCache cat = SC_EXPERT @@ -1008,14 +1022,14 @@ proc = MaxVehiclesChanged cat = SC_BASIC [SDTG_BOOL] -name = NULL +name = nullptr guiflags = SGF_NO_NETWORK var = _old_vds.servint_ispercent def = false to = SLV_120 [SDTG_VAR] -name = NULL +name = nullptr type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_trains @@ -1025,7 +1039,7 @@ max = 800 to = SLV_120 [SDTG_VAR] -name = NULL +name = nullptr type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_roadveh @@ -1035,7 +1049,7 @@ max = 800 to = SLV_120 [SDTG_VAR] -name = NULL +name = nullptr type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_ships @@ -1045,7 +1059,7 @@ max = 800 to = SLV_120 [SDTG_VAR] -name = NULL +name = nullptr type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_aircraft @@ -1204,6 +1218,15 @@ strhelp = STR_CONFIG_SETTING_CATCHMENT_HELPTEXT proc = StationCatchmentChanged cat = SC_EXPERT +[SDT_BOOL] +base = GameSettings +var = station.serve_neutral_industries +def = true +from = SLV_SERVE_NEUTRAL_INDUSTRIES +str = STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES +strhelp = STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT +proc = StationCatchmentChanged + [SDT_BOOL] base = GameSettings var = order.gradual_loading @@ -1401,6 +1424,20 @@ str = STR_CONFIG_SETTING_ALLOW_SHARES strhelp = STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT proc = InvalidateCompanyWindow +[SDT_VAR] +base = GameSettings +var = economy.min_years_for_shares +type = SLE_UINT8 +from = SLV_TRADING_AGE +def = 6 +min = 0 +max = 255 +interval = 1 +str = STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES +strhelp = STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT +strval = STR_JUST_INT +cat = SC_EXPERT + [SDT_VAR] base = GameSettings var = economy.feeder_payment_share @@ -1532,6 +1569,21 @@ strhelp = STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT strval = STR_JUST_COMMA cat = SC_EXPERT +[SDT_VAR] +base = GameSettings +var = script.script_max_memory_megabytes +type = SLE_UINT32 +from = SLV_SCRIPT_MEMLIMIT +guiflags = SGF_NEWGAME_ONLY +def = 1024 +min = 8 +max = 8192 +interval = 8 +str = STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY +strhelp = STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT +strval = STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE +cat = SC_EXPERT + ## [SDT_VAR] base = GameSettings @@ -1646,23 +1698,10 @@ max = 255 cat = SC_EXPERT ## -[SDT_VAR] -base = GameSettings -var = pf.opf.pf_maxlength -type = SLE_UINT16 -def = 4096 -min = 64 -max = 65535 -cat = SC_EXPERT - -[SDT_VAR] -base = GameSettings -var = pf.opf.pf_maxdepth -type = SLE_UINT8 -def = 48 -min = 4 -max = 255 -cat = SC_EXPERT +; Used to be pf.opf.pf_maxlength & pf.opf.pf_maxdepth +[SDT_NULL] +length = 3 +to = SLV_REMOVE_OPF ## [SDT_VAR] @@ -2148,6 +2187,26 @@ min = 0 max = 1000000 cat = SC_EXPERT +[SDT_VAR] +base = GameSettings +var = pf.yapf.ship_curve45_penalty +type = SLE_UINT +from = SLV_SHIP_CURVE_PENALTY +def = 1 * YAPF_TILE_LENGTH +min = 0 +max = 1000000 +cat = SC_EXPERT + +[SDT_VAR] +base = GameSettings +var = pf.yapf.ship_curve90_penalty +type = SLE_UINT +from = SLV_SHIP_CURVE_PENALTY +def = 6 * YAPF_TILE_LENGTH +min = 0 +max = 1000000 +cat = SC_EXPERT + ## [SDT_VAR] base = GameSettings @@ -2483,7 +2542,7 @@ var = locale.digit_group_separator type = SLE_STRQ from = SLV_118 flags = SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr proc = RedrawScreen cat = SC_BASIC @@ -2493,7 +2552,7 @@ var = locale.digit_group_separator_currency type = SLE_STRQ from = SLV_118 flags = SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr proc = RedrawScreen cat = SC_BASIC @@ -2503,7 +2562,7 @@ var = locale.digit_decimal_separator type = SLE_STRQ from = SLV_126 flags = SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr proc = RedrawScreen cat = SC_BASIC @@ -3340,14 +3399,14 @@ cat = SC_BASIC var = music.custom_1 type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr cat = SC_BASIC [SDTC_LIST] var = music.custom_2 type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr cat = SC_BASIC [SDTC_BOOL] @@ -3543,7 +3602,6 @@ strhelp = STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_VAR] -ifdef = ENABLE_NETWORK var = gui.network_chat_box_width_pct type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3553,7 +3611,6 @@ max = 100 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = gui.network_chat_box_height type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3563,7 +3620,6 @@ max = 255 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = gui.network_chat_timeout type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3573,7 +3629,6 @@ max = 65535 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.sync_freq type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NOT_IN_CONFIG | SLF_NO_NETWORK_SYNC @@ -3584,7 +3639,6 @@ max = 100 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.frame_freq type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NOT_IN_CONFIG | SLF_NO_NETWORK_SYNC @@ -3595,7 +3649,6 @@ max = 100 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.commands_per_frame type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3606,7 +3659,6 @@ max = 65535 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_commands_in_queue type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3617,7 +3669,6 @@ max = 65535 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.bytes_per_frame type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3628,7 +3679,6 @@ max = 65535 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.bytes_per_frame_burst type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3639,7 +3689,6 @@ max = 65535 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_init_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3650,7 +3699,6 @@ max = 32000 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_join_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3660,7 +3708,6 @@ min = 0 max = 32000 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_download_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3670,7 +3717,6 @@ min = 0 max = 32000 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_password_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3680,7 +3726,6 @@ min = 0 max = 32000 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_lag_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3690,14 +3735,12 @@ min = 0 max = 32000 [SDTC_BOOL] -ifdef = ENABLE_NETWORK var = network.pause_on_join flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = true [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.server_port type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3708,7 +3751,6 @@ max = 65535 cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.server_admin_port type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3719,7 +3761,6 @@ max = 65535 cat = SC_EXPERT [SDTC_BOOL] -ifdef = ENABLE_NETWORK var = network.server_admin_chat flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY @@ -3727,14 +3768,12 @@ def = true cat = SC_EXPERT [SDTC_BOOL] -ifdef = ENABLE_NETWORK var = network.server_advertise flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = false [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.lan_internet type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3744,83 +3783,73 @@ min = 0 max = 1 [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.client_name type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr proc = UpdateClientName cat = SC_BASIC [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.server_password type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY -def = NULL +def = nullptr proc = UpdateServerPassword cat = SC_BASIC [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.rcon_password type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY -def = NULL +def = nullptr proc = UpdateRconPassword cat = SC_BASIC [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.admin_password type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY -def = NULL +def = nullptr cat = SC_BASIC [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.default_company_pass type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.server_name type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY -def = NULL +def = nullptr cat = SC_BASIC [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.connect_to_ip type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = NULL +def = nullptr [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.network_id type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY -def = NULL +def = nullptr [SDTC_BOOL] -ifdef = ENABLE_NETWORK var = network.autoclean_companies flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = false [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.autoclean_unprotected type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3830,7 +3859,6 @@ min = 0 max = 240 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.autoclean_protected type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3840,7 +3868,6 @@ min = 0 max = 240 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.autoclean_novehicles type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3850,7 +3877,6 @@ min = 0 max = 240 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_companies type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3862,7 +3888,6 @@ proc = UpdateClientConfigValues cat = SC_BASIC [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_clients type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3873,7 +3898,6 @@ max = MAX_CLIENTS cat = SC_BASIC [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.max_spectators type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3885,7 +3909,6 @@ proc = UpdateClientConfigValues cat = SC_BASIC [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.restart_game_year type = SLE_INT32 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3896,7 +3919,6 @@ max = MAX_YEAR interval = 1 [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.min_active_clients type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3906,7 +3928,6 @@ min = 0 max = MAX_CLIENTS [SDTC_OMANY] -ifdef = ENABLE_NETWORK var = network.server_lang type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3917,7 +3938,6 @@ full = _server_langs cat = SC_BASIC [SDTC_BOOL] -ifdef = ENABLE_NETWORK var = network.reload_cfg flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY @@ -3925,7 +3945,6 @@ def = false cat = SC_EXPERT [SDTC_STR] -ifdef = ENABLE_NETWORK var = network.last_host type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3933,7 +3952,6 @@ def = """" cat = SC_EXPERT [SDTC_VAR] -ifdef = ENABLE_NETWORK var = network.last_port type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -3943,7 +3961,6 @@ max = UINT16_MAX cat = SC_EXPERT [SDTC_BOOL] -ifdef = ENABLE_NETWORK var = network.no_http_content_downloads flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false @@ -3952,7 +3969,7 @@ cat = SC_EXPERT ; Since the network code (CmdChangeSetting and friends) use the index in this array to decide ; which setting the server is talking about all conditional compilation of this array must be at the ; end. This isn't really the best solution, the settings the server can tell the client about should -; either use a seperate array or some other form of identifier. +; either use a separate array or some other form of identifier. ; ; We might need to emulate a right mouse button on mac diff --git a/src/table/sprites.h b/src/table/sprites.h index ede797c856..95c070ce57 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -27,10 +27,10 @@ * All sprites which are described here are referenced only one to a handful of times * throughout the code. When introducing new sprite enums, use meaningful names. * Don't be lazy and typing, and only use abbreviations when their meaning is clear or - * the length of the enum would get out of hand. In that case EXPLAIN THE ABBREVATION + * the length of the enum would get out of hand. In that case EXPLAIN THE ABBREVIATION * IN THIS FILE, and perhaps add some comments in the code where it is used. * Now, don't whine about this being too much typing work if the enums are like - * 30 characters in length. If your editor doen't help you simplifying your work, + * 30 characters in length. If your editor doesn't help you simplifying your work, * get a proper editor. If your Operating Systems don't have any decent editors, * get a proper Operating System. * @@ -56,7 +56,7 @@ static const SpriteID SPR_LARGE_SMALL_WINDOW = 682; /** Extra graphic spritenumbers */ static const SpriteID SPR_OPENTTD_BASE = 4896; -static const uint16 OPENTTD_SPRITE_COUNT = 179; +static const uint16 OPENTTD_SPRITE_COUNT = 184; /* Halftile-selection sprites */ static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE; @@ -273,13 +273,15 @@ static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_X_W = SPR_TRAMWAY_BASE + 24; static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_X_E = SPR_TRAMWAY_BASE + 26; static const SpriteID SPR_TRAMWAY_PAVED_STRAIGHT_Y = SPR_TRAMWAY_BASE + 46; static const SpriteID SPR_TRAMWAY_PAVED_STRAIGHT_X = SPR_TRAMWAY_BASE + 47; +static const SpriteID SPR_TRAMWAY_DEPOT_WITH_TRACK = SPR_TRAMWAY_BASE + 49; static const SpriteID SPR_TRAMWAY_BACK_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 55; static const SpriteID SPR_TRAMWAY_FRONT_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 56; static const SpriteID SPR_TRAMWAY_BACK_WIRES_SLOPED = SPR_TRAMWAY_BASE + 72; static const SpriteID SPR_TRAMWAY_FRONT_WIRES_SLOPED = SPR_TRAMWAY_BASE + 68; static const SpriteID SPR_TRAMWAY_TUNNEL_WIRES = SPR_TRAMWAY_BASE + 80; static const SpriteID SPR_TRAMWAY_BRIDGE = SPR_TRAMWAY_BASE + 107; -static const uint16 TRAMWAY_SPRITE_COUNT = 113; +static const SpriteID SPR_TRAMWAY_DEPOT_NO_TRACK = SPR_TRAMWAY_BASE + 113; +static const uint16 TRAMWAY_SPRITE_COUNT = 119; /** One way road sprites */ static const SpriteID SPR_ONEWAY_BASE = SPR_TRAMWAY_BASE + TRAMWAY_SPRITE_COUNT; @@ -577,6 +579,7 @@ static const SpriteID SPR_ROAD_SLOPE_START = 1343; static const SpriteID SPR_ROAD_Y_SNOW = 1351; static const SpriteID SPR_ROAD_X_SNOW = 1352; /* see _road_sloped_sprites_offset in road_cmd.cpp for offsets for sloped road tiles */ +static const SpriteID SPR_ROAD_DEPOT = 1408; static const SpriteID SPR_EXCAVATION_X = 1414; static const SpriteID SPR_EXCAVATION_Y = 1415; @@ -1113,6 +1116,7 @@ static const SpriteID SPR_IMG_ZOOMIN = 735; static const SpriteID SPR_IMG_ZOOMOUT = 736; static const SpriteID SPR_IMG_BUILDRAIL = 727; static const SpriteID SPR_IMG_BUILDROAD = 728; +static const SpriteID SPR_IMG_BUILDTRAMS = SPR_OPENTTD_BASE + 179; static const SpriteID SPR_IMG_BUILDWATER = 729; static const SpriteID SPR_IMG_BUILDAIR = 730; static const SpriteID SPR_IMG_LANDSCAPING = 4083; @@ -1357,6 +1361,11 @@ static const SpriteID SPR_IMG_GOAL = SPR_OPENTTD_BASE + 171; static const SpriteID SPR_IMG_GOAL_COMPLETED = SPR_OPENTTD_BASE + 172; static const SpriteID SPR_IMG_GOAL_BROKEN_REF= SPR_OPENTTD_BASE + 173; +static const SpriteID SPR_IMG_CONVERT_ROAD = SPR_OPENTTD_BASE + 180; +static const CursorID SPR_CURSOR_CONVERT_ROAD = SPR_OPENTTD_BASE + 181; +static const SpriteID SPR_IMG_CONVERT_TRAM = SPR_OPENTTD_BASE + 182; +static const CursorID SPR_CURSOR_CONVERT_TRAM = SPR_OPENTTD_BASE + 183; + /* intro_gui.cpp, genworld_gui.cpp */ static const SpriteID SPR_SELECT_TEMPERATE = 4882; static const SpriteID SPR_SELECT_TEMPERATE_PUSHED = 4883; diff --git a/src/table/station_land.h b/src/table/station_land.h index 3327dab5dd..b678297d90 100644 --- a/src/table/station_land.h +++ b/src/table/station_land.h @@ -789,7 +789,7 @@ static const DrawTileSeqStruct _station_display_datas_waypoint_Y[] = { * @param dtss Sequence child sprites of the tile */ #define TILE_SPRITE_LINE(img, dtss) { {img, PAL_NONE}, dtss }, -#define TILE_SPRITE_NULL() { {0, 0}, NULL }, +#define TILE_SPRITE_NULL() { {0, 0}, nullptr }, extern const DrawTileSprites _station_display_datas_rail[] = { TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_0) diff --git a/src/table/win32_settings.ini b/src/table/win32_settings.ini index bb241f50cd..4b3d6f5598 100644 --- a/src/table/win32_settings.ini +++ b/src/table/win32_settings.ini @@ -23,13 +23,13 @@ SDTG_END = SDTG_END() [defaults] flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -guiflags = 0 +guiflags = SGF_NONE interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED diff --git a/src/table/window_settings.ini b/src/table/window_settings.ini index 41223586a6..998afc8dbb 100644 --- a/src/table/window_settings.ini +++ b/src/table/window_settings.ini @@ -19,13 +19,13 @@ SDT_END = SDT_END() [defaults] base = WindowDesc flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -guiflags = 0 +guiflags = SGF_NONE interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL -proc = NULL -load = NULL +proc = nullptr +load = nullptr from = SL_MIN_VERSION to = SL_MAX_VERSION cat = SC_ADVANCED diff --git a/src/tar_type.h b/src/tar_type.h index 6306fb6500..14b23aea64 100644 --- a/src/tar_type.h +++ b/src/tar_type.h @@ -25,7 +25,7 @@ struct TarListEntry { /* MSVC goes copying around this struct after initialisation, so it tries * to free filename, which isn't set at that moment... but because it * initializes the variable with garbage, it's going to segfault. */ - TarListEntry() : filename(NULL), dirname(NULL) {} + TarListEntry() : filename(nullptr), dirname(nullptr) {} ~TarListEntry() { free(this->filename); free(this->dirname); } }; diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp index 9839f5e34b..eb6ec2b530 100644 --- a/src/terraform_cmd.cpp +++ b/src/terraform_cmd.cpp @@ -278,7 +278,7 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin /* Is the tile already cleared? */ const ClearedObjectArea *coa = FindClearedObject(tile); - bool indirectly_cleared = coa != NULL && coa->first_tile != tile; + bool indirectly_cleared = coa != nullptr && coa->first_tile != tile; /* Check tiletype-specific things, and add extra-cost */ const bool curr_gen = _generating_world; @@ -304,7 +304,7 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin } Company *c = Company::GetIfValid(_current_company); - if (c != NULL && GB(c->terraform_limit, 16, 16) < ts.tile_to_new_height.size()) { + if (c != nullptr && GB(c->terraform_limit, 16, 16) < ts.tile_to_new_height.size()) { return_cmd_error(STR_ERROR_TERRAFORM_LIMIT_REACHED); } @@ -326,7 +326,7 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin SetTileHeight(tile, (uint)height); } - if (c != NULL) c->terraform_limit -= (uint32)ts.tile_to_new_height.size() << 16; + if (c != nullptr) c->terraform_limit -= (uint32)ts.tile_to_new_height.size() << 16; } return total_cost; } @@ -371,7 +371,7 @@ CommandCost CmdLevelLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 bool had_success = false; const Company *c = Company::GetIfValid(_current_company); - int limit = (c == NULL ? INT32_MAX : GB(c->terraform_limit, 16, 16)); + int limit = (c == nullptr ? INT32_MAX : GB(c->terraform_limit, 16, 16)); if (limit == 0) return_cmd_error(STR_ERROR_TERRAFORM_LIMIT_REACHED); TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1); diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index c38bc11c87..46b4689faa 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -222,11 +222,11 @@ struct TerraformToolbarWindow : Window { { } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget == WID_TT_DEMOLISH_TREES) { uint offset = this->IsWidgetLowered(WID_TT_DEMOLISH_TREES) ? 1 : 0; - ZoomLevelByte temp_zoom; + ZoomLevel temp_zoom; switch (_gui_zoom) { case ZOOM_LVL_NORMAL: temp_zoom = ZOOM_LVL_OUT_2X; @@ -237,20 +237,23 @@ struct TerraformToolbarWindow : Window { case ZOOM_LVL_OUT_4X: temp_zoom = ZOOM_LVL_OUT_8X; break; + default: + temp_zoom = ZOOM_LVL_OUT_8X; + break; } Dimension d = GetSpriteSize(SPR_IMG_PLANTTREES, (Point *)0, temp_zoom); DrawSprite(SPR_IMG_PLANTTREES, PAL_NONE, (r.left + r.right - d.width) / 2 + offset, (r.top + r.bottom - d.height) / 2 + offset, nullptr, temp_zoom); } } - virtual void OnInit() + void OnInit() override { /* Don't show the place object button when there are no objects to place. */ NWidgetStacked *show_object = this->GetWidget(WID_TT_SHOW_PLACE_OBJECT); show_object->SetDisplayedPlane(ObjectClass::GetUIClassCount() != 0 ? 0 : SZSP_NONE); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget < WID_TT_BUTTONS_START) return; @@ -302,7 +305,7 @@ struct TerraformToolbarWindow : Window { } } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { switch (this->last_user_action) { case WID_TT_LOWER_LAND: // Lower land button @@ -337,19 +340,19 @@ struct TerraformToolbarWindow : Window { } } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt = GetToolbarAlignedWindowPosition(sm_width); pt.y += sm_height; return pt; } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1) { switch (select_proc) { @@ -365,7 +368,7 @@ struct TerraformToolbarWindow : Window { } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->RaiseButtons(); } @@ -381,8 +384,8 @@ struct TerraformToolbarWindow : Window { static EventState TerraformToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; - Window *w = ShowTerraformToolbar(NULL); - if (w == NULL) return ES_NOT_HANDLED; + Window *w = ShowTerraformToolbar(nullptr); + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -444,14 +447,14 @@ static WindowDesc _terraform_desc( /** * Show the toolbar for terraforming in the game. * @param link The toolbar we might want to link to. - * @return The allocated toolbar if the window was newly opened, else \c NULL. + * @return The allocated toolbar if the window was newly opened, else \c nullptr. */ Window *ShowTerraformToolbar(Window *link) { - if (!Company::IsValidID(_local_company)) return NULL; + if (!Company::IsValidID(_local_company)) return nullptr; Window *w; - if (link == NULL) { + if (link == nullptr) { w = AllocateWindowDescFront(&_terraform_desc, 0); return w; } @@ -629,7 +632,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { this->last_user_action = WIDGET_LIST_END; } - virtual void OnPaint() + void OnPaint() override { this->DrawWidgets(); @@ -638,7 +641,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget != WID_ETT_DOTS) return; @@ -646,7 +649,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { size->height = max(size->height, ScaleGUITrad(31)); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_ETT_DOTS) return; @@ -663,7 +666,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { } while (--n); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget < WID_ETT_BUTTONS_START) return; @@ -722,14 +725,14 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { break; case WID_ETT_RESET_LANDSCAPE: // Reset landscape - ShowQuery(STR_QUERY_RESET_LANDSCAPE_CAPTION, STR_RESET_LANDSCAPE_CONFIRMATION_TEXT, NULL, ResetLandscapeConfirmationCallback); + ShowQuery(STR_QUERY_RESET_LANDSCAPE_CAPTION, STR_RESET_LANDSCAPE_CONFIRMATION_TEXT, nullptr, ResetLandscapeConfirmationCallback); break; default: NOT_REACHED(); } } - virtual void OnTimeout() + void OnTimeout() override { for (uint i = WID_ETT_START; i < this->nested_array_size; i++) { if (i == WID_ETT_BUTTONS_START) i = WID_ETT_BUTTONS_END; // skip the buttons @@ -740,7 +743,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { } } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { switch (this->last_user_action) { case WID_ETT_DEMOLISH: // Demolish aka dynamite button @@ -771,12 +774,12 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { } } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1) { switch (select_proc) { @@ -793,7 +796,7 @@ struct ScenarioEditorLandscapeGenerationWindow : Window { } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->RaiseButtons(); this->SetDirty(); @@ -811,7 +814,7 @@ static EventState TerraformToolbarEditorGlobalHotkeys(int hotkey) { if (_game_mode != GM_EDITOR) return ES_NOT_HANDLED; Window *w = ShowEditorTerraformToolbar(); - if (w == NULL) return ES_NOT_HANDLED; + if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } @@ -838,7 +841,7 @@ static WindowDesc _scen_edit_land_gen_desc( /** * Show the toolbar for terraforming in the scenario editor. - * @return The allocated toolbar if the window was newly opened, else \c NULL. + * @return The allocated toolbar if the window was newly opened, else \c nullptr. */ Window *ShowEditorTerraformToolbar() { diff --git a/src/terraform_gui.h b/src/terraform_gui.h index 26a1c5e9a1..22cfe79c50 100644 --- a/src/terraform_gui.h +++ b/src/terraform_gui.h @@ -14,7 +14,7 @@ #include "window_type.h" -Window *ShowTerraformToolbar(Window *link = NULL); +Window *ShowTerraformToolbar(Window *link = nullptr); Window *ShowEditorTerraformToolbar(); #endif /* TERRAFORM_GUI_H */ diff --git a/src/textbuf.cpp b/src/textbuf.cpp index 61e449d3ae..3847575661 100644 --- a/src/textbuf.cpp +++ b/src/textbuf.cpp @@ -164,18 +164,18 @@ bool Textbuf::InsertChar(WChar key) bool Textbuf::InsertString(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) { uint16 insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos; - if (insert_location != NULL) { + if (insert_location != nullptr) { insertpos = insert_location - this->buf; if (insertpos > this->bytes) return false; - if (replacement_end != NULL) { - this->DeleteText(insertpos, replacement_end - this->buf, str == NULL); + if (replacement_end != nullptr) { + this->DeleteText(insertpos, replacement_end - this->buf, str == nullptr); } } else { - if (marked) this->DiscardMarkedText(str == NULL); + if (marked) this->DiscardMarkedText(str == nullptr); } - if (str == NULL) return false; + if (str == nullptr) return false; uint16 bytes = 0, chars = 0; WChar c; @@ -205,7 +205,7 @@ bool Textbuf::InsertString(const char *str, bool marked, const char *caret, cons this->bytes += bytes; this->chars += chars; - if (!marked && caret == NULL) this->caretpos += bytes; + if (!marked && caret == nullptr) this->caretpos += bytes; assert(this->bytes <= this->max_bytes); assert(this->chars <= this->max_chars); this->buf[this->bytes - 1] = '\0'; // terminating zero diff --git a/src/textbuf_gui.h b/src/textbuf_gui.h index ec134c11c6..e8f5159f94 100644 --- a/src/textbuf_gui.h +++ b/src/textbuf_gui.h @@ -22,6 +22,7 @@ enum QueryStringFlags { QSF_ACCEPT_UNCHANGED = 0x01, ///< return success even when the text didn't change QSF_ENABLE_DEFAULT = 0x02, ///< enable the 'Default' button ("\0" is returned) QSF_LEN_IN_CHARS = 0x04, ///< the length of the string is counted in characters + QSF_PASSWORD = 0x08, ///< password entry box, show warning about password security }; DECLARE_ENUM_AS_BIT_SET(QueryStringFlags) diff --git a/src/textbuf_type.h b/src/textbuf_type.h index 1d927b72d9..22dfd3ffdc 100644 --- a/src/textbuf_type.h +++ b/src/textbuf_type.h @@ -56,7 +56,7 @@ struct Textbuf { bool InsertClipboard(); bool InsertChar(uint32 key); - bool InsertString(const char *str, bool marked, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL); + bool InsertString(const char *str, bool marked, const char *caret = nullptr, const char *insert_location = nullptr, const char *replacement_end = nullptr); bool DeleteChar(uint16 keycode); bool MovePos(uint16 keycode); diff --git a/src/texteff.cpp b/src/texteff.cpp index ee5ce592b4..5e8c749858 100644 --- a/src/texteff.cpp +++ b/src/texteff.cpp @@ -37,7 +37,7 @@ struct TextEffect : public ViewportSign { } }; -static SmallVector _text_effects; ///< Text effects are stored there +static std::vector _text_effects; ///< Text effects are stored there /* Text Effects */ TextEffectID AddTextEffect(StringID msg, int center, int y, uint8 duration, TextEffectMode mode) @@ -45,23 +45,23 @@ TextEffectID AddTextEffect(StringID msg, int center, int y, uint8 duration, Text if (_game_mode == GM_MENU) return INVALID_TE_ID; TextEffectID i; - for (i = 0; i < _text_effects.Length(); i++) { + for (i = 0; i < _text_effects.size(); i++) { if (_text_effects[i].string_id == INVALID_STRING_ID) break; } - if (i == _text_effects.Length()) _text_effects.Append(); + if (i == _text_effects.size()) _text_effects.emplace_back(); - TextEffect *te = _text_effects.Get(i); + TextEffect &te = _text_effects[i]; /* Start defining this object */ - te->string_id = msg; - te->duration = duration; - te->params_1 = GetDParam(0); - te->params_2 = GetDParam(1); - te->mode = mode; + te.string_id = msg; + te.duration = duration; + te.params_1 = GetDParam(0); + te.params_2 = GetDParam(1); + te.mode = mode; /* Make sure we only dirty the new area */ - te->width_normal = 0; - te->UpdatePosition(center, y, msg); + te.width_normal = 0; + te.UpdatePosition(center, y, msg); return i; } @@ -69,7 +69,7 @@ TextEffectID AddTextEffect(StringID msg, int center, int y, uint8 duration, Text void UpdateTextEffect(TextEffectID te_id, StringID msg) { /* Update details */ - TextEffect *te = _text_effects.Get(te_id); + TextEffect *te = _text_effects.data() + te_id; if (msg == te->string_id && GetDParam(0) == te->params_1) return; te->string_id = msg; te->params_1 = GetDParam(0); @@ -89,26 +89,26 @@ void MoveAllTextEffects(uint delta_ms) uint count = texteffecttimer.CountElapsed(delta_ms); if (count == 0) return; - const TextEffect *end = _text_effects.End(); - for (TextEffect *te = _text_effects.Begin(); te != end; te++) { - if (te->string_id == INVALID_STRING_ID) continue; - if (te->mode != TE_RISING) continue; + for (TextEffect &te : _text_effects) { + if (te.string_id == INVALID_STRING_ID) continue; + if (te.mode != TE_RISING) continue; - if (te->duration < count) { - te->Reset(); + if (te.duration < count) { + te.Reset(); continue; } - te->MarkDirty(ZOOM_LVL_OUT_8X); - te->duration -= count; - te->top -= count * ZOOM_LVL_BASE; - te->MarkDirty(ZOOM_LVL_OUT_8X); + te.MarkDirty(ZOOM_LVL_OUT_8X); + te.duration -= count; + te.top -= count * ZOOM_LVL_BASE; + te.MarkDirty(ZOOM_LVL_OUT_8X); } } void InitTextEffects() { - _text_effects.Reset(); + _text_effects.clear(); + _text_effects.shrink_to_fit(); } void DrawTextEffects(DrawPixelInfo *dpi) @@ -116,11 +116,10 @@ void DrawTextEffects(DrawPixelInfo *dpi) /* Don't draw the text effects when zoomed out a lot */ if (dpi->zoom > ZOOM_LVL_OUT_8X) return; - const TextEffect *end = _text_effects.End(); - for (TextEffect *te = _text_effects.Begin(); te != end; te++) { - if (te->string_id == INVALID_STRING_ID) continue; - if (te->mode == TE_RISING || (_settings_client.gui.loading_indicators && !IsTransparencySet(TO_LOADING))) { - ViewportAddString(dpi, ZOOM_LVL_OUT_8X, te, te->string_id, te->string_id - 1, STR_NULL, te->params_1, te->params_2); + for (TextEffect &te : _text_effects) { + if (te.string_id == INVALID_STRING_ID) continue; + if (te.mode == TE_RISING || (_settings_client.gui.loading_indicators && !IsTransparencySet(TO_LOADING))) { + ViewportAddString(dpi, ZOOM_LVL_OUT_8X, &te, te.string_id, te.string_id - 1, STR_NULL, te.params_1, te.params_2); } } } diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index ff5226c2b5..5676a7d101 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -25,7 +25,7 @@ #include #endif -#if defined(WITH_LZMA) +#if defined(WITH_LIBLZMA) #include #endif @@ -86,7 +86,7 @@ uint TextfileWindow::GetContentHeight() int max_width = this->GetWidget(WID_TF_BACKGROUND)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT; uint height = 0; - for (uint i = 0; i < this->lines.Length(); i++) { + for (uint i = 0; i < this->lines.size(); i++) { height += GetStringHeight(this->lines[i], max_width, FS_MONO); } @@ -113,10 +113,10 @@ void TextfileWindow::SetupScrollbars() this->hscroll->SetCount(0); } else { uint max_length = 0; - for (uint i = 0; i < this->lines.Length(); i++) { + for (uint i = 0; i < this->lines.size(); i++) { max_length = max(max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width); } - this->vscroll->SetCount(this->lines.Length() * FONT_HEIGHT_MONO); + this->vscroll->SetCount((uint)this->lines.size() * FONT_HEIGHT_MONO); this->hscroll->SetCount(max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); } @@ -152,7 +152,7 @@ void TextfileWindow::SetupScrollbars() int line_height = FONT_HEIGHT_MONO; int y_offset = -this->vscroll->GetPosition(); - for (uint i = 0; i < this->lines.Length(); i++) { + for (uint i = 0; i < this->lines.size(); i++) { if (IsWidgetLowered(WID_TF_WRAPTEXT)) { y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); } else { @@ -184,7 +184,7 @@ void TextfileWindow::SetupScrollbars() /* virtual */ const char *TextfileWindow::NextString() { - if (this->search_iterator >= this->lines.Length()) return NULL; + if (this->search_iterator >= this->lines.size()) return nullptr; return this->lines[this->search_iterator++]; } @@ -194,11 +194,13 @@ void TextfileWindow::SetupScrollbars() return true; } -/* virtual */ void TextfileWindow::SetFontNames(FreeTypeSettings *settings, const char *font_name) +/* virtual */ void TextfileWindow::SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data) { -#ifdef WITH_FREETYPE +#if defined(WITH_FREETYPE) || defined(_WIN32) strecpy(settings->mono.font, font_name, lastof(settings->mono.font)); -#endif /* WITH_FREETYPE */ + free(settings->mono.os_handle); + settings->mono.os_handle = os_data; +#endif } #if defined(WITH_ZLIB) @@ -214,13 +216,13 @@ void TextfileWindow::SetupScrollbars() * After the call, it contains the size of the uncompressed * data. * - * When decompressing fails, *bufp is set to NULL and *sizep to 0. The + * When decompressing fails, *bufp is set to nullptr and *sizep to 0. The * compressed buffer passed in is still freed in this case. */ static void Gunzip(byte **bufp, size_t *sizep) { static const int BLOCKSIZE = 8192; - byte *buf = NULL; + byte *buf = nullptr; size_t alloc_size = 0; z_stream z; int res; @@ -250,14 +252,14 @@ static void Gunzip(byte **bufp, size_t *sizep) *sizep = alloc_size - z.avail_out; } else { /* Something went wrong */ - *bufp = NULL; + *bufp = nullptr; *sizep = 0; free(buf); } } #endif -#if defined(WITH_LZMA) +#if defined(WITH_LIBLZMA) /** * Do an in-memory xunzip operation. This works on a .xz or (legacy) @@ -270,13 +272,13 @@ static void Gunzip(byte **bufp, size_t *sizep) * After the call, it contains the size of the uncompressed * data. * - * When decompressing fails, *bufp is set to NULL and *sizep to 0. The + * When decompressing fails, *bufp is set to nullptr and *sizep to 0. The * compressed buffer passed in is still freed in this case. */ static void Xunzip(byte **bufp, size_t *sizep) { static const int BLOCKSIZE = 8192; - byte *buf = NULL; + byte *buf = nullptr; size_t alloc_size = 0; lzma_stream z = LZMA_STREAM_INIT; int res; @@ -304,7 +306,7 @@ static void Xunzip(byte **bufp, size_t *sizep) *sizep = alloc_size - z.avail_out; } else { /* Something went wrong */ - *bufp = NULL; + *bufp = nullptr; *sizep = 0; free(buf); } @@ -317,14 +319,14 @@ static void Xunzip(byte **bufp, size_t *sizep) */ /* virtual */ void TextfileWindow::LoadTextfile(const char *textfile, Subdirectory dir) { - if (textfile == NULL) return; + if (textfile == nullptr) return; - this->lines.Clear(); + this->lines.clear(); /* Get text from file */ size_t filesize; FILE *handle = FioFOpenFile(textfile, "rb", dir, &filesize); - if (handle == NULL) return; + if (handle == nullptr) return; this->text = ReallocT(this->text, filesize); size_t read = fread(this->text, 1, filesize, handle); @@ -332,9 +334,9 @@ static void Xunzip(byte **bufp, size_t *sizep) if (read != filesize) return; -#if defined(WITH_ZLIB) || defined(WITH_LZMA) +#if defined(WITH_ZLIB) || defined(WITH_LIBLZMA) const char *suffix = strrchr(textfile, '.'); - if (suffix == NULL) return; + if (suffix == nullptr) return; #endif #if defined(WITH_ZLIB) @@ -342,7 +344,7 @@ static void Xunzip(byte **bufp, size_t *sizep) if (strcmp(suffix, ".gz") == 0) Gunzip((byte**)&this->text, &filesize); #endif -#if defined(WITH_LZMA) +#if defined(WITH_LIBLZMA) /* In-place xunzip */ if (strcmp(suffix, ".xz") == 0) Xunzip((byte**)&this->text, &filesize); #endif @@ -365,11 +367,11 @@ static void Xunzip(byte **bufp, size_t *sizep) str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE); /* Split the string on newlines. */ - *this->lines.Append() = p; + this->lines.push_back(p); for (; *p != '\0'; p++) { if (*p == '\n') { *p = '\0'; - *this->lines.Append() = p + 1; + this->lines.push_back(p + 1); } } @@ -381,7 +383,7 @@ static void Xunzip(byte **bufp, size_t *sizep) * @param type The type of the textfile to search for. * @param dir The subdirectory to search in. * @param filename The filename of the content to look for. - * @return The path to the textfile, \c NULL otherwise. + * @return The path to the textfile, \c nullptr otherwise. */ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filename) { @@ -394,20 +396,20 @@ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filenam const char *prefix = prefixes[type]; - if (filename == NULL) return NULL; + if (filename == nullptr) return nullptr; static char file_path[MAX_PATH]; strecpy(file_path, filename, lastof(file_path)); char *slash = strrchr(file_path, PATHSEPCHAR); - if (slash == NULL) return NULL; + if (slash == nullptr) return nullptr; static const char * const exts[] = { "txt", #if defined(WITH_ZLIB) "txt.gz", #endif -#if defined(WITH_LZMA) +#if defined(WITH_LIBLZMA) "txt.xz", #endif }; @@ -422,5 +424,5 @@ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filenam seprintf(slash + 1, lastof(file_path), "%s.%s", prefix, exts[i]); if (FioCheckFileExists(file_path, dir)) return file_path; } - return NULL; + return nullptr; } diff --git a/src/textfile_gui.h b/src/textfile_gui.h index 9495fa3f08..237b360539 100644 --- a/src/textfile_gui.h +++ b/src/textfile_gui.h @@ -21,28 +21,32 @@ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filenam /** Window for displaying a textfile */ struct TextfileWindow : public Window, MissingGlyphSearcher { - TextfileType file_type; ///< Type of textfile to view. - Scrollbar *vscroll; ///< Vertical scrollbar. - Scrollbar *hscroll; ///< Horizontal scrollbar. - char *text; ///< Lines of text from the NewGRF's textfile. - SmallVector lines; ///< #text, split into lines in a table with lines. - uint search_iterator; ///< Iterator for the font check search. + TextfileType file_type; ///< Type of textfile to view. + Scrollbar *vscroll; ///< Vertical scrollbar. + Scrollbar *hscroll; ///< Horizontal scrollbar. + char *text; ///< Lines of text from the NewGRF's textfile. + std::vector lines; ///< #text, split into lines in a table with lines. + uint search_iterator; ///< Iterator for the font check search. static const int TOP_SPACING = WD_FRAMETEXT_TOP; ///< Additional spacing at the top of the #WID_TF_BACKGROUND widget. static const int BOTTOM_SPACING = WD_FRAMETEXT_BOTTOM; ///< Additional spacing at the bottom of the #WID_TF_BACKGROUND widget. TextfileWindow(TextfileType file_type); - virtual ~TextfileWindow(); - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize); - virtual void OnClick(Point pt, int widget, int click_count); - virtual void DrawWidget(const Rect &r, int widget) const; - virtual void OnResize(); - virtual void Reset(); - virtual FontSize DefaultSize(); - virtual const char *NextString(); - virtual bool Monospace(); - virtual void SetFontNames(FreeTypeSettings *settings, const char *font_name); + ~TextfileWindow(); + + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override; + void OnClick(Point pt, int widget, int click_count) override; + void DrawWidget(const Rect &r, int widget) const override; + void OnResize() override; + + void Reset() override; + FontSize DefaultSize() override; + const char *NextString() override; + bool Monospace() override; + void SetFontNames(FreeTypeSettings *settings, const char *font_name, const void *os_data) override; + virtual void LoadTextfile(const char *textfile, Subdirectory dir); + private: uint GetContentHeight(); void SetupScrollbars(); diff --git a/src/tgp.cpp b/src/tgp.cpp index 4dbb79aa82..3fd42e0fdb 100644 --- a/src/tgp.cpp +++ b/src/tgp.cpp @@ -184,7 +184,7 @@ struct HeightMap }; /** Global height map instance */ -static HeightMap _height_map = {NULL, 0, 0, 0, 0}; +static HeightMap _height_map = {nullptr, 0, 0, 0, 0}; /** Conversion: int to height_t */ #define I2H(i) ((i) << height_decimal_bits) @@ -325,7 +325,7 @@ static inline bool AllocHeightMap() static inline void FreeHeightMap() { free(_height_map.h); - _height_map.h = NULL; + _height_map.h = nullptr; } /** @@ -349,7 +349,7 @@ static inline height_t RandomHeight(amplitude_t rMax) static void HeightMapGenerate() { /* Trying to apply noise to uninitialized height map */ - assert(_height_map.h != NULL); + assert(_height_map.h != nullptr); int start = max(MAX_TGP_FREQUENCIES - (int)min(MapLogX(), MapLogY()), 0); bool first = true; @@ -423,9 +423,9 @@ static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t h_avg = (height_t)(h_accu / (_height_map.size_x * _height_map.size_y)); /* Return required results */ - if (min_ptr != NULL) *min_ptr = h_min; - if (max_ptr != NULL) *max_ptr = h_max; - if (avg_ptr != NULL) *avg_ptr = h_avg; + if (min_ptr != nullptr) *min_ptr = h_min; + if (max_ptr != nullptr) *max_ptr = h_max; + if (avg_ptr != nullptr) *avg_ptr = h_avg; } /** Dill histogram and return pointer to its base point - to the count of zero heights */ @@ -1011,5 +1011,5 @@ void GenerateTerrainPerlin() IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); FreeHeightMap(); - GenerateWorldSetAbortCallback(NULL); + GenerateWorldSetAbortCallback(nullptr); } diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 0000000000..be1d7d4636 --- /dev/null +++ b/src/thread.h @@ -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 thread.h Base of all threads. */ + +#ifndef THREAD_H +#define THREAD_H + +#include "debug.h" +#include +#include + +/** Signal used for signalling we knowingly want to end the thread. */ +class OTTDThreadExitSignal { }; + + +/** + * Sleep on the current thread for a defined time. + * @param milliseconds Time to sleep for in milliseconds. + */ +inline void CSleep(int milliseconds) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); +} + +/** + * Name the thread this function is called on for the debugger. + * @param name Name to set for the thread.. + */ +void SetCurrentThreadName(const char *name); + + +/** + * Start a new thread. + * @tparam TFn Type of the function to call on the thread. + * @tparam TArgs Type of the parameters of the thread function. + * @param thr Pointer to a thread object; may be \c nullptr if a detached thread is wanted. + * @param name Name of the thread. + * @param _Fx Function to call on the thread. + * @param _Ax Arguments for the thread function. + * @return True if the thread was successfully started, false otherwise. + */ +template +inline bool StartNewThread(std::thread *thr, const char *name, TFn&& _Fx, TArgs&&... _Ax) +{ +#ifndef NO_THREADS + try { + std::thread t([] (const char *name, TFn&& F, TArgs&&... A) { + SetCurrentThreadName(name); + try { + /* Call user function with the given arguments. */ + F(A...); + } catch (OTTDThreadExitSignal&) { + } catch (...) { + NOT_REACHED(); + } + }, name, std::forward(_Fx), std::forward(_Ax)...); + + if (thr != nullptr) { + *thr = std::move(t); + } else { + t.detach(); + } + + return true; + } catch (const std::system_error& e) { + /* Something went wrong, the system we are running on might not support threads. */ + DEBUG(misc, 1, "Can't create thread '%s': %s", name, e.what()); + } +#endif + + return false; +} + +#endif /* THREAD_H */ diff --git a/src/tile_cmd.h b/src/tile_cmd.h index 0ab3c5a9a0..558600dcc3 100644 --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -64,8 +64,11 @@ struct TileDesc { uint64 dparam[2]; ///< Parameters of the \a str string StringID railtype; ///< Type of rail on the tile. uint16 rail_speed; ///< Speed limit of rail (bridges and track) - uint16 road_speed; ///< Speed limit of road (bridges) - uint16 population; + uint16 population; ///< CM + StringID roadtype; ///< Type of road on the tile. + uint16 road_speed; ///< Speed limit of road (bridges and track) + StringID tramtype; ///< Type of tram on the tile. + uint16 tram_speed; ///< Speed limit of tram (bridges and track) }; /** @@ -169,29 +172,29 @@ void GetTileDesc(TileIndex tile, TileDesc *td); static inline void AddAcceptedCargo(TileIndex tile, CargoArray &acceptance, CargoTypes *always_accepted) { AddAcceptedCargoProc *proc = _tile_type_procs[GetTileType(tile)]->add_accepted_cargo_proc; - if (proc == NULL) return; - CargoTypes dummy = 0; // use dummy bitmask so there don't need to be several 'always_accepted != NULL' checks - proc(tile, acceptance, always_accepted == NULL ? &dummy : always_accepted); + if (proc == nullptr) return; + CargoTypes dummy = 0; // use dummy bitmask so there don't need to be several 'always_accepted != nullptr' checks + proc(tile, acceptance, always_accepted == nullptr ? &dummy : always_accepted); } static inline void AddProducedCargo(TileIndex tile, CargoArray &produced) { AddProducedCargoProc *proc = _tile_type_procs[GetTileType(tile)]->add_produced_cargo_proc; - if (proc == NULL) return; + if (proc == nullptr) return; proc(tile, produced); } static inline void AnimateTile(TileIndex tile) { AnimateTileProc *proc = _tile_type_procs[GetTileType(tile)]->animate_tile_proc; - assert(proc != NULL); + assert(proc != nullptr); proc(tile); } static inline bool ClickTile(TileIndex tile) { ClickTileProc *proc = _tile_type_procs[GetTileType(tile)]->click_tile_proc; - if (proc == NULL) return false; + if (proc == nullptr) return false; return proc(tile); } diff --git a/src/tile_map.cpp b/src/tile_map.cpp index 200a203089..a30d1e4426 100644 --- a/src/tile_map.cpp +++ b/src/tile_map.cpp @@ -34,7 +34,7 @@ static Slope GetTileSlopeGivenHeight(int hnorth, int hwest, int heast, int hsout int hmines = min(heast, hsouth); int hmin = min(hminnw, hmines); - if (h != NULL) *h = hmin; + if (h != nullptr) *h = hmin; int hmaxnw = max(hnorth, hwest); int hmaxes = max(heast, hsouth); @@ -55,7 +55,7 @@ static Slope GetTileSlopeGivenHeight(int hnorth, int hwest, int heast, int hsout /** * Return the slope of a given tile inside the map. * @param tile Tile to compute slope of - * @param h If not \c NULL, pointer to storage of z height + * @param h If not \c nullptr, pointer to storage of z height * @return Slope of the tile, except for the HALFTILE part */ Slope GetTileSlope(TileIndex tile, int *h) @@ -76,9 +76,9 @@ Slope GetTileSlope(TileIndex tile, int *h) /** * Return the slope of a given tile, also for tiles outside the map (virtual "black" tiles). * - * @param x X coordinate of the tile to compute slope of, may be ouside the map. - * @param y Y coordinate of the tile to compute slope of, may be ouside the map. - * @param h If not \c NULL, pointer to storage of z height. + * @param x X coordinate of the tile to compute slope of, may be outside the map. + * @param y Y coordinate of the tile to compute slope of, may be outside the map. + * @param h If not \c nullptr, pointer to storage of z height. * @return Slope of the tile, except for the HALFTILE part. */ Slope GetTilePixelSlopeOutsideMap(int x, int y, int *h) @@ -89,14 +89,14 @@ Slope GetTilePixelSlopeOutsideMap(int x, int y, int *h) int hsouth = TileHeightOutsideMap(x + 1, y + 1); // S corner. Slope s = GetTileSlopeGivenHeight(hnorth, hwest, heast, hsouth, h); - if (h != NULL) *h *= TILE_HEIGHT; + if (h != nullptr) *h *= TILE_HEIGHT; return s; } /** * Check if a given tile is flat * @param tile Tile to check - * @param h If not \c NULL, pointer to storage of z height (only if tile is flat) + * @param h If not \c nullptr, pointer to storage of z height (only if tile is flat) * @return Whether the tile is flat */ bool IsTileFlat(TileIndex tile, int *h) @@ -111,7 +111,7 @@ bool IsTileFlat(TileIndex tile, int *h) if (TileHeight(TileXY(x1, y2)) != z) return false; if (TileHeight(TileXY(x2, y2)) != z) return false; - if (h != NULL) *h = z; + if (h != nullptr) *h = z; return true; } diff --git a/src/tile_map.h b/src/tile_map.h index 7a76f2b974..89467c4d0a 100644 --- a/src/tile_map.h +++ b/src/tile_map.h @@ -37,8 +37,8 @@ static inline uint TileHeight(TileIndex tile) /** * Returns the height of a tile, also for tiles outside the map (virtual "black" tiles). * - * @param x X coordinate of the tile, may be ouside the map. - * @param y Y coordinate of the tile, may be ouside the map. + * @param x X coordinate of the tile, may be outside the map. + * @param y Y coordinate of the tile, may be outside the map. * @return The height in the same unit as TileHeight. */ static inline uint TileHeightOutsideMap(int x, int y) @@ -79,8 +79,8 @@ static inline uint TilePixelHeight(TileIndex tile) /** * Returns the height of a tile in pixels, also for tiles outside the map (virtual "black" tiles). * - * @param x X coordinate of the tile, may be ouside the map. - * @param y Y coordinate of the tile, may be ouside the map. + * @param x X coordinate of the tile, may be outside the map. + * @param y Y coordinate of the tile, may be outside the map. * @return The height in pixels in the same unit as TilePixelHeight. */ static inline uint TilePixelHeightOutsideMap(int x, int y) @@ -267,22 +267,22 @@ static inline void SetAnimationFrame(TileIndex t, byte frame) _me[t].m7 = frame; } -Slope GetTileSlope(TileIndex tile, int *h = NULL); +Slope GetTileSlope(TileIndex tile, int *h = nullptr); int GetTileZ(TileIndex tile); int GetTileMaxZ(TileIndex tile); -bool IsTileFlat(TileIndex tile, int *h = NULL); +bool IsTileFlat(TileIndex tile, int *h = nullptr); /** * Return the slope of a given tile * @param tile Tile to compute slope of - * @param h If not \c NULL, pointer to storage of z height + * @param h If not \c nullptr, pointer to storage of z height * @return Slope of the tile, except for the HALFTILE part */ static inline Slope GetTilePixelSlope(TileIndex tile, int *h) { Slope s = GetTileSlope(tile, h); - if (h != NULL) *h *= TILE_HEIGHT; + if (h != nullptr) *h *= TILE_HEIGHT; return s; } diff --git a/src/tilearea.cpp b/src/tilearea.cpp index ec3b9aafbb..33850c7203 100644 --- a/src/tilearea.cpp +++ b/src/tilearea.cpp @@ -117,6 +117,27 @@ bool OrthogonalTileArea::Contains(TileIndex tile) const return IsInsideBS(tile_x, left, this->w) && IsInsideBS(tile_y, top, this->h); } +/** + * Expand a tile area by rad tiles in each direction, keeping within map bounds. + * @param rad Number of tiles to expand + * @return The OrthogonalTileArea. + */ +OrthogonalTileArea &OrthogonalTileArea::Expand(int rad) +{ + int x = TileX(this->tile); + int y = TileY(this->tile); + + int sx = max(x - rad, 0); + int sy = max(y - rad, 0); + int ex = min(x + this->w + rad, MapSizeX()); + int ey = min(y + this->h + rad, MapSizeY()); + + this->tile = TileXY(sx, sy); + this->w = ex - sx; + this->h = ey - sy; + return *this; +} + /** * Clamp the tile area to map borders. */ diff --git a/src/tilearea_type.h b/src/tilearea_type.h index 36bb89f3c9..ae6b83a8fe 100644 --- a/src/tilearea_type.h +++ b/src/tilearea_type.h @@ -48,6 +48,8 @@ struct OrthogonalTileArea { bool Contains(TileIndex tile) const; + OrthogonalTileArea &Expand(int rad); + void ClampToMap(); /** diff --git a/src/tilehighlight_type.h b/src/tilehighlight_type.h index 6e89013a75..f1151b2574 100644 --- a/src/tilehighlight_type.h +++ b/src/tilehighlight_type.h @@ -59,6 +59,8 @@ struct TileHighlightData { Point outersize; ///< Size, in tile "units", of the blue coverage area excluding the side of the selected area. bool diagonal; ///< Whether the dragged area is a 45 degrees rotated rectangle. + bool freeze; ///< Freeze highlight in place. + Point new_pos; ///< New value for \a pos; used to determine whether to redraw the selection. Point new_size; ///< New value for \a size; used to determine whether to redraw the selection. Point new_offs; ///< New value for \a offs; used to determine whether to redraw the selection. diff --git a/src/tilematrix_type.hpp b/src/tilematrix_type.hpp index f9c7392b24..78cde1643c 100644 --- a/src/tilematrix_type.hpp +++ b/src/tilematrix_type.hpp @@ -69,7 +69,7 @@ public: T *data; ///< Pointer to data array. - TileMatrix() : area(INVALID_TILE, 0, 0), data(NULL) {} + TileMatrix() : area(INVALID_TILE, 0, 0), data(nullptr) {} ~TileMatrix() { diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 29986c353d..979534bb37 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -16,7 +16,6 @@ #include "window_func.h" #include "vehicle_base.h" #include "cmd_helper.h" -#include "core/sort_func.hpp" #include "table/strings.h" @@ -61,7 +60,7 @@ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 val, v->orders.list->UpdateTotalDuration(total_delta); v->orders.list->UpdateTimetableDuration(timetable_delta); - for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { + for (v = v->FirstShared(); v != nullptr; v = v->NextShared()) { if (v->cur_real_order_index == order_number && v->current_order.Equals(*order)) { switch (mtf) { case MTF_WAIT_TIME: @@ -105,14 +104,14 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, u VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; VehicleOrderID order_number = GB(p1, 20, 8); Order *order = v->GetOrder(order_number); - if (order == NULL || order->IsType(OT_IMPLICIT)) return CMD_ERROR; + if (order == nullptr || order->IsType(OT_IMPLICIT)) return CMD_ERROR; ModifyTimetableFlags mtf = Extract(p1); if (mtf >= MTF_END) return CMD_ERROR; @@ -199,7 +198,7 @@ CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -216,15 +215,12 @@ CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, * Order vehicles based on their timetable. The vehicles will be sorted in order * they would reach the first station. * - * @param ap First Vehicle pointer. - * @param bp Second Vehicle pointer. + * @param a First Vehicle pointer. + * @param b Second Vehicle pointer. * @return Comparison value. */ -static int CDECL VehicleTimetableSorter(Vehicle * const *ap, Vehicle * const *bp) +static bool VehicleTimetableSorter(Vehicle * const &a, Vehicle * const &b) { - const Vehicle *a = *ap; - const Vehicle *b = *bp; - VehicleOrderID a_order = a->cur_real_order_index; VehicleOrderID b_order = b->cur_real_order_index; int j = (int)b_order - (int)a_order; @@ -242,15 +238,15 @@ static int CDECL VehicleTimetableSorter(Vehicle * const *ap, Vehicle * const *bp /* First check the order index that accounted for loading, then just the raw one. */ int i = (int)b_order - (int)a_order; - if (i != 0) return i; - if (j != 0) return j; + if (i != 0) return i < 0; + if (j != 0) return j < 0; /* Look at the time we spent in this order; the higher, the closer to its destination. */ i = b->current_order_time - a->current_order_time; - if (i != 0) return i; + if (i != 0) return i < 0; /* If all else is equal, use some unique index to sort it the same way. */ - return b->unitnumber - a->unitnumber; + return b->unitnumber < a->unitnumber; } /** @@ -268,7 +264,7 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, { bool timetable_all = HasBit(p1, 20); Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); - if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -281,34 +277,33 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, if (timetable_all && !v->orders.list->IsCompleteTimetable()) return CMD_ERROR; if (flags & DC_EXEC) { - SmallVector vehs; + std::vector vehs; if (timetable_all) { - for (Vehicle *w = v->orders.list->GetFirstSharedVehicle(); w != NULL; w = w->NextShared()) { - *vehs.Append() = w; + for (Vehicle *w = v->orders.list->GetFirstSharedVehicle(); w != nullptr; w = w->NextShared()) { + vehs.push_back(w); } } else { - *vehs.Append() = v; + vehs.push_back(v); } int total_duration = v->orders.list->GetTimetableTotalDuration(); - int num_vehs = vehs.Length(); + int num_vehs = (uint)vehs.size(); if (num_vehs >= 2) { - QSortT(vehs.Begin(), vehs.Length(), &VehicleTimetableSorter); + std::sort(vehs.begin(), vehs.end(), &VehicleTimetableSorter); } - int base = vehs.FindIndex(v); + int idx = vehs.begin() - std::find(vehs.begin(), vehs.end(), v); - for (Vehicle **viter = vehs.Begin(); viter != vehs.End(); viter++) { - int idx = (viter - vehs.Begin()) - base; - Vehicle *w = *viter; + for (Vehicle *w : vehs) { w->lateness_counter = 0; ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED); /* Do multiplication, then division to reduce rounding errors. */ w->timetable_start = start_date + idx * total_duration / num_vehs / DAY_TICKS; SetWindowDirty(WC_VEHICLE_TIMETABLE, w->index); + ++idx; } } @@ -335,7 +330,7 @@ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); - if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle() || v->orders.list == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -358,7 +353,7 @@ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } - for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { + for (Vehicle *v2 = v->FirstShared(); v2 != nullptr; v2 = v2->NextShared()) { if (v2 != v) { /* Stop autofilling; only one vehicle at a time can perform autofill */ ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE); @@ -388,7 +383,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) Order *real_current_order = v->GetOrder(v->cur_real_order_index); VehicleOrderID first_manual_order = 0; - for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) { + for (Order *o = v->GetFirstOrder(); o != nullptr && o->IsType(OT_IMPLICIT); o = o->next) { ++first_manual_order; } @@ -478,7 +473,7 @@ void UpdateVehicleTimetable(Vehicle *v, bool travelling) } } - for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { + for (v = v->FirstShared(); v != nullptr; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } } diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index 5dd45561f3..087f3f66f0 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -87,7 +87,7 @@ static bool CanDetermineTimeTaken(const Order *order, bool travelling) */ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID start, bool travelling, TimetableArrivalDeparture *table, Ticks offset) { - assert(table != NULL); + assert(table != nullptr); assert(v->GetNumOrders() >= 2); assert(start < v->GetNumOrders()); @@ -122,7 +122,7 @@ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID order = order->next; if (i >= v->GetNumOrders()) { i = 0; - assert(order == NULL); + assert(order == nullptr); order = v->orders.list->GetFirstOrder(); } } while (i != start); @@ -189,7 +189,7 @@ struct TimetableWindow : Window { return (travelling && v->lateness_counter < 0); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_VT_ARRIVAL_DEPARTURE_PANEL: @@ -227,7 +227,7 @@ struct TimetableWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { switch (data) { case VIWD_AUTOREPLACE: @@ -297,7 +297,7 @@ struct TimetableWindow : Window { } - virtual void OnPaint() + void OnPaint() override { const Vehicle *v = this->vehicle; int selected = this->sel_index; @@ -309,9 +309,9 @@ struct TimetableWindow : Window { if (selected != -1) { const Order *order = v->GetOrder(((selected + 1) / 2) % v->GetNumOrders()); if (selected % 2 == 1) { - disable = order != NULL && (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT)); + disable = order != nullptr && (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT)); } else { - disable = order == NULL || ((!order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL)); + disable = order == nullptr || ((!order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL)); } } bool disable_speed = disable || selected % 2 != 1 || v->type == VEH_AIRCRAFT; @@ -322,9 +322,9 @@ struct TimetableWindow : Window { this->SetWidgetDisabledState(WID_VT_CLEAR_SPEED, disable_speed); this->SetWidgetDisabledState(WID_VT_SHARED_ORDER_LIST, !v->IsOrderListShared()); - this->SetWidgetDisabledState(WID_VT_START_DATE, v->orders.list == NULL); - this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == NULL); - this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == NULL); + this->SetWidgetDisabledState(WID_VT_START_DATE, v->orders.list == nullptr); + this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == nullptr); + this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == nullptr); } else { this->DisableWidget(WID_VT_START_DATE); this->DisableWidget(WID_VT_CHANGE_TIME); @@ -341,7 +341,7 @@ struct TimetableWindow : Window { this->DrawWidgets(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_VT_CAPTION: SetDParam(0, this->vehicle->index); break; @@ -349,7 +349,7 @@ struct TimetableWindow : Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { const Vehicle *v = this->vehicle; int selected = this->sel_index; @@ -367,7 +367,7 @@ struct TimetableWindow : Window { int middle = rtl ? r.right - WD_FRAMERECT_RIGHT - index_column_width : r.left + WD_FRAMERECT_LEFT + index_column_width; const Order *order = v->GetOrder(order_id); - while (order != NULL) { + while (order != nullptr) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; @@ -424,7 +424,7 @@ struct TimetableWindow : Window { * i.e. are only shown if we can calculate all times. * Excluding order lists with only one order makes some things easier. */ - Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; + Ticks total_time = v->orders.list != nullptr ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break; TimetableArrivalDeparture *arr_dep = AllocaM(TimetableArrivalDeparture, v->GetNumOrders()); @@ -475,7 +475,7 @@ struct TimetableWindow : Window { case WID_VT_SUMMARY_PANEL: { int y = r.top + WD_FRAMERECT_TOP; - Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; + Ticks total_time = v->orders.list != nullptr ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time != 0) { SetTimetableParams(0, 1, total_time); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->orders.list->IsCompleteTimetable() ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE); @@ -513,7 +513,7 @@ struct TimetableWindow : Window { return v->index | (order_number << 20) | (mtf << 28); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { const Vehicle *v = this->vehicle; @@ -543,7 +543,7 @@ struct TimetableWindow : Window { const Order *order = v->GetOrder(real); StringID current = STR_EMPTY; - if (order != NULL) { + if (order != nullptr) { uint time = (selected % 2 == 1) ? order->GetTravelTime() : order->GetWaitTime(); if (!_settings_client.gui.timetable_in_ticks) time /= DAY_TICKS; @@ -566,7 +566,7 @@ struct TimetableWindow : Window { StringID current = STR_EMPTY; const Order *order = v->GetOrder(real); - if (order != NULL) { + if (order != nullptr) { if (order->GetMaxSpeed() != UINT16_MAX) { SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->GetMaxSpeed())); current = STR_JUST_INT; @@ -614,15 +614,15 @@ struct TimetableWindow : Window { this->SetDirty(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; const Vehicle *v = this->vehicle; uint32 p1 = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query); - uint64 val = StrEmpty(str) ? 0 : strtoul(str, NULL, 10); + uint64 val = StrEmpty(str) ? 0 : strtoul(str, nullptr, 10); if (this->query_is_speed_query) { val = ConvertDisplaySpeedToKmhishSpeed(val); } else { @@ -634,7 +634,7 @@ struct TimetableWindow : Window { DoCommandP(0, p1, p2, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); } - virtual void OnResize() + void OnResize() override { /* Update the scroll bar */ this->vscroll->SetCapacityFromWidget(this, WID_VT_TIMETABLE_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 4afa304b2a..588aed5b4a 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -17,6 +17,7 @@ #include "command_func.h" #include "vehicle_gui.h" #include "rail_gui.h" +#include "road.h" #include "road_gui.h" #include "date_func.h" #include "vehicle_func.h" @@ -68,6 +69,7 @@ uint _toolbar_width = 0; RailType _last_built_railtype; RoadType _last_built_roadtype; +RoadType _last_built_tramtype; static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm. @@ -102,14 +104,12 @@ public: this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3; } - virtual ~DropDownListCheckedItem() {} - uint Width() const { return DropDownListStringItem::Width() + this->checkmark_width; } - void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const { bool rtl = _current_text_dir == TD_RTL; if (this->checked) { @@ -134,14 +134,12 @@ public: this->lock_size = GetSpriteSize(SPR_LOCK); } - virtual ~DropDownListCompanyItem() {} - - bool Selectable() const + bool Selectable() const override { return true; } - uint Width() const + uint Width() const override { CompanyID company = (CompanyID)this->result; SetDParam(0, company); @@ -149,12 +147,12 @@ public: return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + this->lock_size.width + 6; } - uint Height(uint width) const + uint Height(uint width) const override { return max(max(this->icon_size.height, this->lock_size.height) + 2U, (uint)FONT_HEIGHT_NORMAL); } - void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const + void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override { CompanyID company = (CompanyID)this->result; bool rtl = _current_text_dir == TD_RTL; @@ -167,11 +165,9 @@ public: int lock_offset = (bottom - top - lock_size.height) / 2; DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset); -#ifdef ENABLE_NETWORK if (NetworkCompanyIsPassworded(company)) { DrawSprite(SPR_LOCK, PAL_NONE, rtl ? left + WD_FRAMERECT_LEFT : right - this->lock_size.width - WD_FRAMERECT_RIGHT, top + lock_offset); } -#endif SetDParam(0, company); SetDParam(1, company); @@ -192,9 +188,9 @@ public: * @param list List of items * @param def Default item */ -static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def) +static void PopupMainToolbMenu(Window *w, int widget, DropDownList &&list, int def) { - ShowDropDownList(w, list, def, widget, 0, true, true); + ShowDropDownList(w, std::move(list), def, widget, 0, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } @@ -207,11 +203,11 @@ static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int de */ static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count) { - DropDownList *list = new DropDownList(); + DropDownList list; for (int i = 0; i < count; i++) { - *list->Append() = new DropDownListStringItem(string + i, i, false); + list.emplace_back(new DropDownListStringItem(string + i, i, false)); } - PopupMainToolbMenu(w, widget, list, 0); + PopupMainToolbMenu(w, widget, std::move(list), 0); } /** Enum for the Company Toolbar's network related buttons */ @@ -228,39 +224,37 @@ static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator */ static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0) { - DropDownList *list = new DropDownList(); + DropDownList list; switch (widget) { case WID_TN_COMPANIES: -#ifdef ENABLE_NETWORK if (!_networking) break; /* Add the client list button for the companies menu */ - *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false); + list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false)); if (_local_company == COMPANY_SPECTATOR) { - *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()); + list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached())); } else { - *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()); + list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached())); } -#endif /* ENABLE_NETWORK */ break; case WID_TN_STORY: - *list->Append() = new DropDownListStringItem(STR_STORY_BOOK_SPECTATOR, CTMN_SPECTATOR, false); + list.emplace_back(new DropDownListStringItem(STR_STORY_BOOK_SPECTATOR, CTMN_SPECTATOR, false)); break; case WID_TN_GOAL: - *list->Append() = new DropDownListStringItem(STR_GOALS_SPECTATOR, CTMN_SPECTATOR, false); + list.emplace_back(new DropDownListStringItem(STR_GOALS_SPECTATOR, CTMN_SPECTATOR, false)); break; } for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (!Company::IsValidID(c)) continue; - *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c)); + list.emplace_back(new DropDownListCompanyItem(c, false, HasBit(grey, c))); } - PopupMainToolbMenu(w, widget, list, _local_company == COMPANY_SPECTATOR ? (widget == WID_TN_COMPANIES ? CTMN_CLIENT_LIST : CTMN_SPECTATOR) : (int)_local_company); + PopupMainToolbMenu(w, widget, std::move(list), _local_company == COMPANY_SPECTATOR ? (widget == WID_TN_COMPANIES ? CTMN_CLIENT_LIST : CTMN_SPECTATOR) : (int)_local_company); } @@ -343,28 +337,28 @@ enum OptionMenuEntries { */ static CallBackFunction ToolbarOptionsClick(Window *w) { - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false); + DropDownList list; + list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false)); + list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false)); /* Changes to the per-AI settings don't get send from the server to the clients. Clients get * the settings once they join but never update it. As such don't show the window at all * to network clients. */ - if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_ZONING, OME_ZONING, false); - *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false); - *list->Append() = new DropDownListItem(-1, false); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)); - *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)); + if (!_networking || _network_server) list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false)); + list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false)); + list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_ZONING, OME_ZONING, false)); + list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false)); + list.emplace_back(new DropDownListItem(-1, false)); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES))); + list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS))); - ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true); + ShowDropDownList(w, std::move(list), 0, WID_TN_SETTINGS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } @@ -491,24 +485,24 @@ enum MapMenuEntries { static CallBackFunction ToolbarMapClick(Window *w) { - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); - PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0); + DropDownList list; + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false)); + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false)); + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false)); + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false)); + PopupMainToolbMenu(w, WID_TN_SMALL_MAP, std::move(list), 0); return CBF_NONE; } static CallBackFunction ToolbarScenMapTownDir(Window *w) { - DropDownList *list = new DropDownList(); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); - *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); - *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false); - *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false); - PopupMainToolbMenu(w, WID_TE_SMALL_MAP, list, 0); + DropDownList list; + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false)); + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false)); + list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false)); + list.emplace_back(new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false)); + list.emplace_back(new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false)); + PopupMainToolbMenu(w, WID_TE_SMALL_MAP, std::move(list), 0); return CBF_NONE; } @@ -665,7 +659,6 @@ static CallBackFunction ToolbarCompaniesClick(Window *w) */ static CallBackFunction MenuClickCompany(int index) { -#ifdef ENABLE_NETWORK if (_networking) { switch (index) { case CTMN_CLIENT_LIST: @@ -676,7 +669,7 @@ static CallBackFunction MenuClickCompany(int index) if (_network_server) { DoCommandP(0, CCA_NEW, _network_own_client_id, CMD_COMPANY_CTRL); } else { - NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company); + NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company); } return CBF_NONE; @@ -690,7 +683,6 @@ static CallBackFunction MenuClickCompany(int index) return CBF_NONE; } } -#endif /* ENABLE_NETWORK */ ShowCompany((CompanyID)index); return CBF_NONE; } @@ -954,22 +946,7 @@ static CallBackFunction MenuClickBuildRail(int index) static CallBackFunction ToolbarBuildRoadClick(Window *w) { - const Company *c = Company::Get(_local_company); - DropDownList *list = new DropDownList(); - - /* Road is always visible and available. */ - *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false); - - /* Tram is only visible when there will be a tram, and available when that has been introduced. */ - Engine *e; - 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; - - *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM)); - break; - } - ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true); + ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TN_ROADS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } @@ -987,11 +964,35 @@ static CallBackFunction MenuClickBuildRoad(int index) return CBF_NONE; } +/* --- Tram button menu --- */ + +static CallBackFunction ToolbarBuildTramClick(Window *w) +{ + ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TN_TRAMS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Tram menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction MenuClickBuildTram(int index) +{ + _last_built_tramtype = (RoadType)index; + ShowBuildRoadToolbar(_last_built_tramtype); + return CBF_NONE; +} + /* --- Water button menu --- */ static CallBackFunction ToolbarBuildWaterClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1); + DropDownList list; + list.emplace_back(new DropDownListIconItem(SPR_IMG_BUILD_CANAL, PAL_NONE, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 0, false)); + ShowDropDownList(w, std::move(list), 0, WID_TN_WATER, 140, true, true); return CBF_NONE; } @@ -1011,7 +1012,9 @@ static CallBackFunction MenuClickBuildWater(int index) static CallBackFunction ToolbarBuildAirClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1); + DropDownList list; + list.emplace_back(new DropDownListIconItem(SPR_IMG_AIRPORT, PAL_NONE, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 0, false)); + ShowDropDownList(w, std::move(list), 0, WID_TN_AIR, 140, true, true); return CBF_NONE; } @@ -1031,7 +1034,11 @@ static CallBackFunction MenuClickBuildAir(int index) static CallBackFunction ToolbarForestClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3); + DropDownList list; + list.emplace_back(new DropDownListIconItem(SPR_IMG_LANDSCAPING, PAL_NONE, STR_LANDSCAPING_MENU_LANDSCAPING, 0, false)); + list.emplace_back(new DropDownListIconItem(SPR_IMG_PLANTTREES, PAL_NONE, STR_LANDSCAPING_MENU_PLANT_TREES, 1, false)); + list.emplace_back(new DropDownListIconItem(SPR_IMG_SIGN, PAL_NONE, STR_LANDSCAPING_MENU_PLACE_SIGN, 2, false)); + ShowDropDownList(w, std::move(list), 0, WID_TN_LANDSCAPE, 100, true, true); return CBF_NONE; } @@ -1055,7 +1062,7 @@ static CallBackFunction MenuClickForest(int index) static CallBackFunction ToolbarMusicClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1); + PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_MUSIC_SOUND : (int)WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1); return CBF_NONE; } @@ -1110,13 +1117,13 @@ static CallBackFunction PlaceLandBlockInfo() static CallBackFunction ToolbarHelpClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 14 : 10); + PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 14 : 10); return CBF_NONE; } static void MenuClickSmallScreenshot() { - MakeScreenshot(SC_VIEWPORT, NULL); + MakeScreenshot(SC_VIEWPORT, nullptr); } /** @@ -1126,7 +1133,7 @@ static void MenuClickSmallScreenshot() */ static void ScreenshotConfirmCallback(Window *w, bool confirmed) { - if (confirmed) MakeScreenshot(_confirmed_screenshot_type, NULL); + if (confirmed) MakeScreenshot(_confirmed_screenshot_type, nullptr); } /** @@ -1143,10 +1150,10 @@ static void MenuClickLargeWorldScreenshot(ScreenshotType t) SetDParam(0, vp.width); SetDParam(1, vp.height); _confirmed_screenshot_type = t; - ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, NULL, ScreenshotConfirmCallback); + ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, nullptr, ScreenshotConfirmCallback); } else { /* Less than 64M pixels, just do it */ - MakeScreenshot(t, NULL); + MakeScreenshot(t, nullptr); } } @@ -1239,7 +1246,7 @@ static CallBackFunction ToolbarSwitchClick(Window *w) } w->ReInit(); - w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER); + w->SetWidgetLoweredState(_game_mode == GM_EDITOR ? (uint)WID_TE_SWITCH_BAR : (uint)WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } @@ -1309,11 +1316,43 @@ static CallBackFunction ToolbarScenGenIndustry(Window *w) return CBF_NONE; } -static CallBackFunction ToolbarScenBuildRoad(Window *w) +static CallBackFunction ToolbarScenBuildRoadClick(Window *w) { - w->HandleButtonClick(WID_TE_ROADS); + ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TE_ROADS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); - ShowBuildRoadScenToolbar(); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Road menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarScenBuildRoad(int index) +{ + _last_built_roadtype = (RoadType)index; + ShowBuildRoadScenToolbar(_last_built_roadtype); + return CBF_NONE; +} + +static CallBackFunction ToolbarScenBuildTramClick(Window *w) +{ + ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TE_TRAMS, 140, true, true); + if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); + return CBF_NONE; +} + +/** + * Handle click on the entry in the Build Tram menu. + * + * @param index RoadType to show the build toolbar for. + * @return #CBF_NONE + */ +static CallBackFunction ToolbarScenBuildTram(int index) +{ + _last_built_tramtype = (RoadType)index; + ShowBuildRoadScenToolbar(_last_built_tramtype); return CBF_NONE; } @@ -1348,8 +1387,8 @@ static CallBackFunction ToolbarBtn_NULL(Window *w) typedef CallBackFunction MenuClickedProc(int index); static MenuClickedProc * const _menu_clicked_procs[] = { - NULL, // 0 - NULL, // 1 + nullptr, // 0 + nullptr, // 1 MenuClickSettings, // 2 MenuClickSaveLoad, // 3 MenuClickMap, // 4 @@ -1370,15 +1409,16 @@ static MenuClickedProc * const _menu_clicked_procs[] = { MenuClickShowShips, // 17 MenuClickShowAir, // 18 MenuClickMap, // 19 - NULL, // 20 + nullptr, // 20 MenuClickBuildRail, // 21 MenuClickBuildRoad, // 22 - MenuClickBuildWater, // 23 - MenuClickBuildAir, // 24 - MenuClickForest, // 25 - MenuClickMusicWindow, // 26 - MenuClickNewspaper, // 27 - MenuClickHelp, // 28 + MenuClickBuildTram, // 23 + MenuClickBuildWater, // 24 + MenuClickBuildAir, // 25 + MenuClickForest, // 26 + MenuClickMusicWindow, // 27 + MenuClickNewspaper, // 28 + MenuClickHelp, // 29 }; /** Full blown container to make it behave exactly as we want :) */ @@ -1402,7 +1442,7 @@ public: return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN; } - void SetupSmallestSize(Window *w, bool init_array) + void SetupSmallestSize(Window *w, bool init_array) override { this->smallest_x = 0; // Biggest child this->smallest_y = 0; // Biggest child @@ -1414,7 +1454,7 @@ public: uint nbuttons = 0; /* First initialise some variables... */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); if (this->IsButton(child_wid->type)) { @@ -1426,7 +1466,7 @@ public: } /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->current_y = this->smallest_y; if (!this->IsButton(child_wid->type)) { child_wid->current_x = child_wid->smallest_x; @@ -1435,7 +1475,7 @@ public: _toolbar_width = nbuttons * this->smallest_x; } - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); @@ -1454,7 +1494,7 @@ public: /* Create us ourselves a quick lookup table */ NWidgetBase *widgets[WID_TN_END]; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (child_wid->type == NWID_SPACER) continue; widgets[((NWidgetCore*)child_wid)->index] = child_wid; } @@ -1473,7 +1513,7 @@ public: /* If we have to give space to the spacers, do that */ if (spacer_space != 0) { NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev; - if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) { + if (possible_spacer != nullptr && possible_spacer->type == NWID_SPACER) { uint add = spacer_space / (spacer_count - spacer_i); position += add; spacer_space -= add; @@ -1498,14 +1538,14 @@ public: } } - /* virtual */ void Draw(const Window *w) + void Draw(const Window *w) override { /* Draw brown-red toolbar bg. */ GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_VERY_DARK_RED); GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_DARK_RED, FILLRECT_CHECKER); bool rtl = _current_text_dir == TD_RTL; - for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) { + for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != nullptr; child_wid = rtl ? child_wid->prev : child_wid->next) { if (child_wid->type == NWID_SPACER) continue; if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; @@ -1513,18 +1553,18 @@ public: } } - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y) + NWidgetCore *GetWidgetFromPos(int x, int y) override { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (child_wid->type == NWID_SPACER) continue; if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); - if (nwid != NULL) return nwid; + if (nwid != nullptr) return nwid; } - return NULL; + return nullptr; } /** @@ -1540,7 +1580,7 @@ public: /** Container for the 'normal' main toolbar */ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { - /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const + const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override { static const uint SMALLEST_ARRANGEMENT = 14; static const uint BIGGEST_ARRANGEMENT = 20; @@ -1836,6 +1876,7 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { WID_TN_ZOOM_OUT, WID_TN_RAILS, WID_TN_ROADS, + WID_TN_TRAMS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, @@ -1865,13 +1906,13 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel) - void SetupSmallestSize(Window *w, bool init_array) + void SetupSmallestSize(Window *w, bool init_array) override { this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array); /* Find the size of panel_widths */ uint i = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue; assert(i < lengthof(this->panel_widths)); @@ -1880,7 +1921,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { } } - /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const + const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override { static const byte arrange_all[] = { WID_TE_PAUSE, @@ -1896,6 +1937,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_TOWN_GENERATE, WID_TE_INDUSTRY, WID_TE_ROADS, + WID_TE_TRAMS, WID_TE_WATER, WID_TE_TREES, WID_TE_SIGNS, @@ -1915,6 +1957,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_TOWN_GENERATE, WID_TE_INDUSTRY, WID_TE_ROADS, + WID_TE_TRAMS, WID_TE_WATER, WID_TE_TREES, WID_TE_SIGNS, @@ -1928,6 +1971,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_TOWN_GENERATE, WID_TE_INDUSTRY, WID_TE_ROADS, + WID_TE_TRAMS, WID_TE_WATER, WID_TE_TREES, WID_TE_SIGNS, @@ -1938,10 +1982,12 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { WID_TE_SETTINGS, WID_TE_SAVE, WID_TE_DATE_PANEL, + WID_TE_SMALL_MAP, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT, WID_TE_MUSIC_SOUND, - WID_TE_HELP, WID_TE_SWITCH_BAR, + WID_TE_HELP, + WID_TE_SWITCH_BAR, }; /* If we can place all buttons *and* the panels, show them. */ @@ -2003,6 +2049,7 @@ static ToolbarButtonProc * const _toolbar_button_procs[] = { ToolbarZoomOutClick, ToolbarBuildRailClick, ToolbarBuildRoadClick, + ToolbarBuildTramClick, ToolbarBuildWaterClick, ToolbarBuildAirClick, ToolbarForestClick, @@ -2037,6 +2084,7 @@ enum MainToolbarHotkeys { MTHK_ZOOM_OUT, MTHK_BUILD_RAIL, MTHK_BUILD_ROAD, + MTHK_BUILD_TRAM, MTHK_BUILD_DOCKS, MTHK_BUILD_AIRPORT, MTHK_BUILD_TREES, @@ -2080,17 +2128,17 @@ struct MainToolbarWindow : Window { this->timer.SetInterval(MILLISECONDS_PER_TICK); } - virtual void FindWindowPlacementAndResize(int def_width, int def_height) + void FindWindowPlacementAndResize(int def_width, int def_height) override { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } - virtual void OnPaint() + void OnPaint() override { /* If spectator, disable all construction buttons * ie : Build road, rail, ships, airports and landscaping * Since enabled state is the default, just disable when needed */ - this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); + this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_TRAMS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); /* disable company list drop downs, if there are no companies */ this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_CARGOS, WID_TN_WATCH, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFT, WIDGET_LIST_END); @@ -2098,12 +2146,14 @@ struct MainToolbarWindow : Window { this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0); this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN)); + this->SetWidgetDisabledState(WID_TN_ROADS, !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_ROAD)); + this->SetWidgetDisabledState(WID_TN_TRAMS, !CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM)); this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)); this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const { + void DrawWidget(const Rect &r, int widget) const override { if (widget == WID_TN_WATCH) { Dimension d = GetSpriteSize(SPR_CENTRE_VIEW_VEHICLE); uint offset = this->IsWidgetLowered(WID_TN_WATCH) ? 1 : 0; @@ -2111,18 +2161,18 @@ struct MainToolbarWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this); } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { CallBackFunction cbf = _menu_clicked_procs[widget](index); if (cbf != CBF_NONE) _last_started_action = cbf; } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { switch (hotkey) { case MTHK_PAUSE: ToolbarPauseClick(this); break; @@ -2149,6 +2199,7 @@ struct MainToolbarWindow : Window { case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break; case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break; + case MTHK_BUILD_TRAM: if (CanBuildVehicleInfrastructure(VEH_ROAD, RTT_TRAM)) ShowBuildRoadToolbar(_last_built_tramtype); break; case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break; case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break; case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break; @@ -2161,10 +2212,8 @@ struct MainToolbarWindow : Window { case MTHK_CHEATS: ShowCheatWindow(); break; case MTHK_TERRAFORM: ShowTerraformToolbar(); break; case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; -#ifdef ENABLE_NETWORK case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break; case MTHK_COMMANDS_GUI: extern bool _novahost; if (_networking && _novahost){ ShowCommandsToolbar(); } break; -#endif case MTHK_BUILD_HQ: if(_current_company != COMPANY_SPECTATOR){ _last_started_action = BuildCompanyHQ(); } break; case MTHK_CARGOTABLE: if(_current_company != COMPANY_SPECTATOR){ ShowCompanyCargos(_current_company); } break; case MTHK_TREES: if(_current_company != COMPANY_SPECTATOR){ BuildTreesWindow(); } break; @@ -2197,7 +2246,7 @@ struct MainToolbarWindow : Window { w->OnClick(Point(), WID_BT_TYPE_RANDOM, 1);*/ } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { switch (_last_started_action) { case CBF_PLACE_SIGN: @@ -2219,18 +2268,18 @@ struct MainToolbarWindow : Window { } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { _last_started_action = CBF_NONE; } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (!this->timer.Elapsed(delta_ms)) return; this->timer.SetInterval(MILLISECONDS_PER_TICK); @@ -2246,7 +2295,7 @@ struct MainToolbarWindow : Window { } } - virtual void OnTimeout() + void OnTimeout() override { /* We do not want to automatically raise the pause, fast forward and * switchbar buttons; they have to stay down when pressed etc. */ @@ -2263,10 +2312,10 @@ struct MainToolbarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; - if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT); + if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT); } static HotkeyList hotkeys; @@ -2302,6 +2351,7 @@ static Hotkey maintoolbar_hotkeys[] = { Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT), Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL), Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD), + Hotkey((uint16)0, "build_tram", MTHK_BUILD_TRAM), Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS), Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT), Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES), @@ -2314,11 +2364,9 @@ static Hotkey maintoolbar_hotkeys[] = { Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS), Hotkey('L', "terraform", MTHK_TERRAFORM), Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT), -#ifdef ENABLE_NETWORK Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST), Hotkey('N', "nova_commands", MTHK_COMMANDS_GUI), Hotkey(WKC_CTRL | WKC_F2, "cargo_table", MTHK_CARGOTABLE), -#endif Hotkey(WKC_CTRL | 'H', "build_hq", MTHK_BUILD_HQ), Hotkey('I', "trees", MTHK_TREES), Hotkey((uint16)0, "zoning", MTHK_ZONING), @@ -2360,6 +2408,7 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT SPR_IMG_BUILDRAIL, // WID_TN_RAILS SPR_IMG_BUILDROAD, // WID_TN_ROADS + SPR_IMG_BUILDTRAMS, // WID_TN_TRAMS SPR_IMG_BUILDWATER, // WID_TN_WATER SPR_IMG_BUILDAIR, // WID_TN_AIR SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE @@ -2393,7 +2442,7 @@ static const NWidgetPart _nested_toolbar_normal_widgets[] = { }; static WindowDesc _toolb_normal_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS, _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets), @@ -2403,6 +2452,32 @@ static WindowDesc _toolb_normal_desc( /* --- Toolbar handling for the scenario editor */ +static MenuClickedProc * const _scen_toolbar_dropdown_procs[] = { + nullptr, // 0 + nullptr, // 1 + MenuClickSettings, // 2 + MenuClickSaveLoad, // 3 + nullptr, // 4 + nullptr, // 5 + nullptr, // 6 + nullptr, // 7 + MenuClickMap, // 8 + nullptr, // 9 + nullptr, // 10 + nullptr, // 11 + nullptr, // 12 + nullptr, // 13 + ToolbarScenBuildRoad, // 14 + ToolbarScenBuildTram, // 15 + nullptr, // 16 + nullptr, // 17 + nullptr, // 18 + nullptr, // 19 + MenuClickMusicWindow, // 20 + MenuClickHelp, // 21 + nullptr, // 22 +}; + static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { ToolbarPauseClick, ToolbarFastForwardClick, @@ -2418,20 +2493,13 @@ static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { ToolbarScenGenLand, ToolbarScenGenTown, ToolbarScenGenIndustry, - ToolbarScenBuildRoad, + ToolbarScenBuildRoadClick, + ToolbarScenBuildTramClick, ToolbarScenBuildDocks, ToolbarScenPlantTrees, ToolbarScenPlaceSign, ToolbarBtn_NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, ToolbarMusicClick, - NULL, ToolbarHelpClick, ToolbarSwitchClick, }; @@ -2445,6 +2513,7 @@ enum MainToolbarEditorHotkeys { MTEHK_GENTOWN, MTEHK_GENINDUSTRY, MTEHK_BUILD_ROAD, + MTEHK_BUILD_TRAM, MTEHK_BUILD_DOCKS, MTEHK_BUILD_TREES, MTEHK_SIGN, @@ -2476,20 +2545,22 @@ struct ScenarioEditorToolbarWindow : Window { this->timer.SetInterval(MILLISECONDS_PER_TICK); } - virtual void FindWindowPlacementAndResize(int def_width, int def_height) + void FindWindowPlacementAndResize(int def_width, int def_height) override { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } - virtual void OnPaint() + void OnPaint() override { this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR); + this->SetWidgetDisabledState(WID_TE_ROADS, (GetRoadTypes(true) & ~_roadtypes_type) == ROADTYPES_NONE); + this->SetWidgetDisabledState(WID_TE_TRAMS, (GetRoadTypes(true) & _roadtypes_type) == ROADTYPES_NONE); this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_TE_DATE: @@ -2510,7 +2581,7 @@ struct ScenarioEditorToolbarWindow : Window { } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_TE_SPACER: @@ -2525,24 +2596,21 @@ struct ScenarioEditorToolbarWindow : Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (_game_mode == GM_MENU) return; CallBackFunction cbf = _scen_toolbar_button_procs[widget](this); if (cbf != CBF_NONE) _last_started_action = cbf; } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { - /* The map button is in a different location on the scenario - * editor toolbar, so we need to adjust for it. */ - if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP; - CallBackFunction cbf = _menu_clicked_procs[widget](index); + CallBackFunction cbf = _scen_toolbar_dropdown_procs[widget](index); if (cbf != CBF_NONE) _last_started_action = cbf; if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } - virtual EventState OnHotkey(int hotkey) + EventState OnHotkey(int hotkey) override { CallBackFunction cbf = CBF_NONE; switch (hotkey) { @@ -2553,7 +2621,8 @@ struct ScenarioEditorToolbarWindow : Window { case MTEHK_GENLAND: ToolbarScenGenLand(this); break; case MTEHK_GENTOWN: ToolbarScenGenTown(this); break; case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break; - case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break; + case MTEHK_BUILD_ROAD: ToolbarScenBuildRoadClick(this); break; + case MTEHK_BUILD_TRAM: ToolbarScenBuildTramClick(this); break; case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break; case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break; case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break; @@ -2574,7 +2643,7 @@ struct ScenarioEditorToolbarWindow : Window { return ES_HANDLED; } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { switch (_last_started_action) { case CBF_PLACE_SIGN: @@ -2589,19 +2658,19 @@ struct ScenarioEditorToolbarWindow : Window { } } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { _last_started_action = CBF_NONE; } - virtual void OnTimeout() + void OnTimeout() override { this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END); this->SetWidgetDirty(WID_TE_DATE_BACKWARD); this->SetWidgetDirty(WID_TE_DATE_FORWARD); } - virtual void OnRealtimeTick(uint delta_ms) + void OnRealtimeTick(uint delta_ms) override { if (!this->timer.Elapsed(delta_ms)) return; this->timer.SetInterval(MILLISECONDS_PER_TICK); @@ -2622,16 +2691,16 @@ struct ScenarioEditorToolbarWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; - if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT); + if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { /* Was 'cancel' pressed? */ - if (str == NULL) return; + if (str == nullptr) return; int32 value; if (!StrEmpty(str)) { @@ -2657,6 +2726,7 @@ static Hotkey scenedit_maintoolbar_hotkeys[] = { Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN), Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY), Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD), + Hotkey((uint16)0, "build_tram", MTEHK_BUILD_TRAM), Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS), Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES), Hotkey(WKC_F10, "build_sign", MTEHK_SIGN), @@ -2699,7 +2769,8 @@ static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), + NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_TRAMS), SetDataTip(SPR_IMG_BUILDTRAMS, STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), @@ -2719,7 +2790,7 @@ static const NWidgetPart _nested_toolb_scen_widgets[] = { }; static WindowDesc _toolb_scen_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS, _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets), @@ -2731,6 +2802,7 @@ void AllocateToolbar() { /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */ _last_built_roadtype = ROADTYPE_ROAD; + _last_built_tramtype = ROADTYPE_TRAM; if (_game_mode == GM_EDITOR) { new ScenarioEditorToolbarWindow(&_toolb_scen_desc); diff --git a/src/town.h b/src/town.h index 20832b71d8..775281710c 100644 --- a/src/town.h +++ b/src/town.h @@ -41,7 +41,7 @@ static const TownID INVALID_TOWN = 0xFFFF; static const uint TOWN_GROWTH_WINTER = 0xFFFFFFFE; ///< The town only needs this cargo in the winter (any amount) static const uint TOWN_GROWTH_DESERT = 0xFFFFFFFF; ///< The town needs the cargo for growth when on desert (any amount) static const uint16 TOWN_GROWTH_RATE_NONE = 0xFFFF; ///< Special value for Town::growth_rate to disable town growth. -static const uint16 MAX_TOWN_GROWTH_TICKS = 930; ///< Max amount of original town ticks that still fit into uint16, about equal to UINT16_MAX / TOWN_GROWTH_TICKS but sligtly less to simplify calculations +static const uint16 MAX_TOWN_GROWTH_TICKS = 930; ///< Max amount of original town ticks that still fit into uint16, about equal to UINT16_MAX / TOWN_GROWTH_TICKS but slightly less to simplify calculations typedef Pool TownPool; extern TownPool _town_pool; @@ -52,7 +52,7 @@ struct TownCache { uint32 population; ///< Current population of people uint32 potential_pop; ///< Potential population (if all houses are finished) ViewportSign sign; ///< Location of name sign, UpdateVirtCoord updates this - PartOfSubsidyByte part_of_subsidy; ///< Is this town a source/destination of a subsidy? + PartOfSubsidy part_of_subsidy; ///< Is this town a source/destination of a subsidy? uint32 squared_town_zone_radius[HZB_END]; ///< UpdateTownRadius updates this given the house count BuildingCounts building_counts; ///< The number of each type of building in the town }; @@ -67,7 +67,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { uint32 townnamegrfid; uint16 townnametype; uint32 townnameparts; - char *name; ///< Custom town name. If NULL, the town was not renamed and uses the generated name. + char *name; ///< Custom town name. If nullptr, the town was not renamed and uses the generated name. byte flags; ///< See #TownFlags. @@ -78,7 +78,7 @@ struct Town : TownPool::PoolItem<&_town_pool> { /* Company ratings. */ CompanyMask have_ratings; ///< which companies have a rating uint8 unwanted[MAX_COMPANIES]; ///< how many months companies aren't wanted by towns (bribe) - CompanyByte exclusivity; ///< which company has exclusivity + CompanyID exclusivity; ///< which company has exclusivity uint8 exclusive_counter; ///< months till the exclusivity expires int16 ratings[MAX_COMPANIES]; ///< ratings of each company for this town @@ -120,17 +120,20 @@ struct Town : TownPool::PoolItem<&_town_pool> { CargoTypes cargo_produced; ///< Bitmap of all cargoes produced by houses in this town. AcceptanceMatrix cargo_accepted; ///< Bitmap of cargoes accepted by houses for each 4*4 map square of the town. CargoTypes cargo_accepted_total; ///< NOSAVE: Bitmap of all cargoes accepted by houses in this town. + StationList stations_near; ///< NOSAVE: List of nearby stations. - uint16 time_until_rebuild; ///< time until we rebuild a house + uint16 time_until_rebuild; ///< time until we rebuild a house - uint16 grow_counter; ///< counter to count when to grow, value is smaller than or equal to growth_rate - uint16 growth_rate; ///< town growth rate + uint16 grow_counter; ///< counter to count when to grow, value is smaller than or equal to growth_rate + uint16 growth_rate; ///< town growth rate - byte fund_buildings_months; ///< fund buildings program in action? - byte road_build_months; ///< fund road reconstruction in action? + byte fund_buildings_months; ///< fund buildings program in action? + byte road_build_months; ///< fund road reconstruction in action? - bool larger_town; ///< if this is a larger town and should grow more quickly - TownLayoutByte layout; ///< town specific road layout + bool larger_town; ///< if this is a larger town and should grow more quickly + TownLayout layout; ///< town specific road layout + + bool show_zone; ///< NOSAVE: mark town to show the local authority zone in the viewports std::list psa_list; @@ -202,6 +205,9 @@ void UpdateAllTownVirtCoords(); void ShowTownViewWindow(TownID town); void ExpandTown(Town *t); +void RebuildTownKdtree(); + + /** * Action types that a company must ask permission for to a town authority. * @see CheckforTownRating @@ -212,6 +218,12 @@ enum TownRatingCheckType { TOWN_RATING_CHECK_TYPE_COUNT, ///< Number of town checking action types. }; +/** Special values for town list window for the data parameter of #InvalidateWindowData. */ +enum TownDirectoryInvalidateWindowData { + TDIWD_FORCE_REBUILD, + TDIWD_FILTER_CHANGES, ///< The filename filter has changed (via the editbox) +}; + /** * This enum is used in conjunction with town->flags. * IT simply states what bit is used for. @@ -318,7 +330,7 @@ template void MakeDefaultName(T *obj) { /* We only want to set names if it hasn't been set before, or when we're calling from afterload. */ - assert(obj->name == NULL || obj->town_cn == UINT16_MAX); + assert(obj->name == nullptr || obj->town_cn == UINT16_MAX); obj->town = ClosestTownFromTile(obj->xy, UINT_MAX); @@ -342,7 +354,7 @@ void MakeDefaultName(T *obj) T *lobj = T::GetIfValid(cid); /* check only valid waypoints... */ - if (lobj != NULL && obj != lobj) { + if (lobj != nullptr && obj != lobj) { /* only objects within the same city and with the same type */ if (lobj->town == obj->town && lobj->IsOfType(obj)) { /* if lobj->town_cn < next, uint will overflow to '+inf' */ @@ -384,4 +396,6 @@ static inline uint16 TownTicksToGameTicks(uint16 ticks) { extern CargoTypes _town_cargoes_accepted; +RoadType GetTownRoadType(const Town *t); + #endif /* TOWN_H */ diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 4d5959646c..d3f9cfd5b5 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -10,14 +10,17 @@ /** @file town_cmd.cpp Handling of town tiles. */ #include "stdafx.h" +#include "road.h" #include "road_internal.h" /* Cleaning up road bits */ #include "road_cmd.h" #include "landscape.h" #include "viewport_func.h" +#include "viewport_kdtree.h" #include "cmd_helper.h" #include "command_func.h" #include "industry.h" #include "station_base.h" +#include "station_kdtree.h" #include "company_base.h" #include "news_func.h" #include "error.h" @@ -38,6 +41,7 @@ #include "subsidy_func.h" #include "core/pool_func.hpp" #include "town.h" +#include "town_kdtree.h" #include "townname_func.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" @@ -71,6 +75,45 @@ CargoTypes _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses TownPool _town_pool("Town"); INSTANTIATE_POOL_METHODS(Town) + +TownKdtree _town_kdtree(&Kdtree_TownXYFunc); + +void RebuildTownKdtree() +{ + std::vector townids; + Town *town; + FOR_ALL_TOWNS(town) { + townids.push_back(town->index); + } + _town_kdtree.Build(townids.begin(), townids.end()); +} + + +/** + * Check if a town 'owns' a bridge. + * Bridges to not directly have an owner, so we check the tiles adjacent to the bridge ends. + * If either adjacent tile belongs to the town then it will be assumed that the town built + * the bridge. + * @param tile Bridge tile to test + * @param t Town we are interested in + * @return true if town 'owns' a bridge. + */ +static bool TestTownOwnsBridge(TileIndex tile, const Town *t) +{ + if (!IsTileOwner(tile, OWNER_TOWN)) return false; + + TileIndex adjacent = tile + TileOffsByDiagDir(ReverseDiagDir(GetTunnelBridgeDirection(tile))); + bool town_owned = IsTileType(adjacent, MP_ROAD) && IsTileOwner(adjacent, OWNER_TOWN) && GetTownIndex(adjacent) == t->index; + + if (!town_owned) { + /* Or other adjacent road */ + TileIndex adjacent = tile + TileOffsByDiagDir(ReverseDiagDir(GetTunnelBridgeDirection(GetOtherTunnelBridgeEnd(tile)))); + town_owned = IsTileType(adjacent, MP_ROAD) && IsTileOwner(adjacent, OWNER_TOWN) && GetTownIndex(adjacent) == t->index; + } + + return town_owned; +} + Town::~Town() { free(this->name); @@ -102,7 +145,7 @@ Town::~Town() break; case MP_TUNNELBRIDGE: - assert(!IsTileOwner(tile, OWNER_TOWN) || ClosestTownFromTile(tile, UINT_MAX) != this); + assert(!TestTownOwnsBridge(tile, this)); break; default: @@ -133,7 +176,7 @@ void Town::PostDestructor(size_t index) /* Give objects a new home! */ Object *o; FOR_ALL_OBJECTS(o) { - if (o->town == NULL) o->town = CalcClosestTownFromTile(o->location.tile, UINT_MAX); + if (o->town == nullptr) o->town = CalcClosestTownFromTile(o->location.tile, UINT_MAX); } } @@ -147,16 +190,16 @@ void Town::InitializeLayout(TownLayout layout) return; } - this->layout = TileHash(TileX(this->xy), TileY(this->xy)) % (NUM_TLS - 1); + this->layout = static_cast(TileHash(TileX(this->xy), TileY(this->xy)) % (NUM_TLS - 1)); } /** * Return a random valid town. - * @return random town, NULL if there are no towns + * @return random town, nullptr if there are no towns */ /* static */ Town *Town::GetRandom() { - if (Town::GetNumItems() == 0) return NULL; + if (Town::GetNumItems() == 0) return nullptr; int num = RandomRange((uint16)Town::GetNumItems()); size_t index = MAX_UVALUE(size_t); @@ -249,7 +292,7 @@ static void DrawTile_Town(TileInfo *ti) /* Houses don't necessarily need new graphics. If they don't have a * spritegroup associated with them, then the sprite for the substitute * house id is drawn instead. */ - if (HouseSpec::Get(house_id)->grf_prop.spritegroup[0] != NULL) { + if (HouseSpec::Get(house_id)->grf_prop.spritegroup[0] != nullptr) { DrawNewHouseTile(ti, house_id); return; } else { @@ -306,7 +349,7 @@ static Foundation GetFoundation_Town(TileIndex tile, Slope tileh) */ if (hid >= NEW_HOUSE_OFFSET) { const HouseSpec *hs = HouseSpec::Get(hid); - if (hs->grf_prop.spritegroup[0] != NULL && HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) { + if (hs->grf_prop.spritegroup[0] != nullptr && HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) { uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, hid, Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE; } @@ -373,30 +416,9 @@ static void AnimateTile_Town(TileIndex tile) */ static bool IsCloseToTown(TileIndex tile, uint dist) { - /* On a large map with many towns, it may be faster to check the surroundings of the tile. - * An iteration in TILE_AREA_LOOP() is generally 2 times faster than one in FOR_ALL_TOWNS(). */ - if (Town::GetNumItems() > (size_t) (dist * dist * 2)) { - const int tx = TileX(tile); - const int ty = TileY(tile); - TileArea tile_area = TileArea( - TileXY(max(0, tx - (int) dist), max(0, ty - (int) dist)), - TileXY(min(MapMaxX(), tx + (int) dist), min(MapMaxY(), ty + (int) dist)) - ); - TILE_AREA_LOOP(atile, tile_area) { - if (GetTileType(atile) == MP_HOUSE) { - Town *t = Town::GetByTile(atile); - if (DistanceManhattan(tile, t->xy) < dist) return true; - } - } - return false; - } - - const Town *t; - - FOR_ALL_TOWNS(t) { - if (DistanceManhattan(tile, t->xy) < dist) return true; - } - return false; + if (_town_kdtree.Count() == 0) return false; + Town *t = Town::Get(_town_kdtree.FindNearest(TileX(tile), TileY(tile))); + return DistanceManhattan(tile, t->xy) < dist; } /** @@ -438,7 +460,7 @@ static void ChangePopulation(Town *t, int mod) t->cache.population += mod; InvalidateWindowData(WC_TOWN_VIEW, t->index); // Cargo requirements may appear/vanish for small populations - t->UpdateVirtCoord(); + if (_settings_client.gui.population_in_label) t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1); } @@ -457,6 +479,22 @@ uint32 GetWorldPopulation() return pop; } +/** + * Remove stations from nearby station list if a town is no longer in the catchment area of each. + * @param t Town to work on + */ +static void RemoveNearbyStations(Town *t) +{ + for (StationList::iterator it = t->stations_near.begin(); it != t->stations_near.end(); /* incremented inside loop */) { + const Station *st = *it; + if (!st->CatchmentCoversTown(t->index)) { + it = t->stations_near.erase(it); + } else { + ++it; + } + } +} + /** * Helper function for house completion stages progression * @param tile TileIndex of the house (or parts of it) to "grow" @@ -552,24 +590,58 @@ static void TileLoop_Town(TileIndex tile) t->supplied[cs->Index()].new_act += moved; } } else { - if (GB(r, 0, 8) < hs->population) { - uint amt = GB(r, 0, 8) / 8 + 1; + switch (_settings_game.economy.town_cargogen_mode) { + case TCGM_ORIGINAL: + /* Original (quadratic) cargo generation algorithm */ + if (GB(r, 0, 8) < hs->population) { + uint amt = GB(r, 0, 8) / 8 + 1; - if (EconomyIsInRecession()) amt = (amt + 1) >> 1; - t->supplied[CT_PASSENGERS].new_max += amt; - t->supplied[CT_PASSENGERS].new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations()); - } + if (EconomyIsInRecession()) amt = (amt + 1) >> 1; + t->supplied[CT_PASSENGERS].new_max += amt; + t->supplied[CT_PASSENGERS].new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations()); + } - if (GB(r, 8, 8) < hs->mail_generation) { - uint amt = GB(r, 8, 8) / 8 + 1; + if (GB(r, 8, 8) < hs->mail_generation) { + uint amt = GB(r, 8, 8) / 8 + 1; - if (EconomyIsInRecession()) amt = (amt + 1) >> 1; - t->supplied[CT_MAIL].new_max += amt; - t->supplied[CT_MAIL].new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations()); + if (EconomyIsInRecession()) amt = (amt + 1) >> 1; + t->supplied[CT_MAIL].new_max += amt; + t->supplied[CT_MAIL].new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations()); + } + break; + + case TCGM_BITCOUNT: + /* Binomial distribution per tick, by a series of coin flips */ + /* Reduce generation rate to a 1/4, using tile bits to spread out distribution. + * As tick counter is incremented by 256 between each call, we ignore the lower 8 bits. */ + if (GB(_tick_counter, 8, 2) == GB(tile, 0, 2)) { + /* Make a bitmask with up to 32 bits set, one for each potential pax */ + int genmax = (hs->population + 7) / 8; + uint32 genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1); + /* Mask random value by potential pax and count number of actual pax */ + uint amt = CountBits(r & genmask); + /* Adjust and apply */ + if (EconomyIsInRecession()) amt = (amt + 1) >> 1; + t->supplied[CT_PASSENGERS].new_max += amt; + t->supplied[CT_PASSENGERS].new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations()); + + /* Do the same for mail, with a fresh random */ + r = Random(); + genmax = (hs->mail_generation + 7) / 8; + genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1); + amt = CountBits(r & genmask); + if (EconomyIsInRecession()) amt = (amt + 1) >> 1; + t->supplied[CT_MAIL].new_max += amt; + t->supplied[CT_MAIL].new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations()); + } + break; + + default: + NOT_REACHED(); } } - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); if ((hs->building_flags & BUILDING_HAS_1_TILE) && HasBit(t->flags, TOWN_IS_GROWING) && @@ -581,12 +653,15 @@ static void TileLoop_Town(TileIndex tile) ClearTownHouse(t, tile); /* Rebuild with another house? */ - if (GB(r, 24, 8) >= 12 && BuildTownHouse(t, tile)) { - t->houses_reconstruction++; - UpdateTownGrowthTile(tile, TGTS_RH_REBUILT); - } else { + if (GB(r, 24, 8) < 12 || !BuildTownHouse(t, tile)) + { + /* House wasn't replaced, so remove it */ + if (!_generating_world) RemoveNearbyStations(t); t->houses_demolished++; UpdateTownGrowthTile(tile, TGTS_RH_REMOVED); + } else { + t->houses_reconstruction++; + UpdateTownGrowthTile(tile, TGTS_RH_REBUILT); } } @@ -621,6 +696,7 @@ static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags) UpdateTownGrowthTile(tile, t->growing ? TGTS_CB_HOUSE_REMOVED: TGTS_CB_HOUSE_REMOVED_NOGROW); } ClearTownHouse(t, tile); + RemoveNearbyStations(t); } return cost; @@ -729,7 +805,7 @@ static void GetTileDesc_Town(TileIndex tile, TileDesc *td) td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION; } - if (hs->grf_prop.grffile != NULL) { + if (hs->grf_prop.grffile != nullptr) { const GRFConfig *gc = GetGRFConfig(hs->grf_prop.grffile->grfid); td->grf = gc->GetName(); } @@ -867,7 +943,7 @@ static void DoRegularFunding(Town *t) if (t->grow_counter != t->growth_rate && is_growing) return; } else return; - CompanyByte old = _current_company; + CompanyID old = _current_company; _current_company = _local_company; DoCommandP(t->xy, t->index, HK_FUND, CMD_DO_TOWN_ACTION | CMD_NO_ESTIMATE); _current_company = old; @@ -897,7 +973,7 @@ static void DoRegularAdvertising(Town *t) { if (t->ad_ref_goods_entry->rating >= t->ad_rating_goal) return; - CompanyByte old = _current_company; + CompanyID old = _current_company; _current_company = _local_company; DoCommandP(t->xy, t->index, HK_LADVERT, CMD_DO_TOWN_ACTION | CMD_NO_ESTIMATE); _current_company = old; @@ -950,7 +1026,38 @@ static RoadBits GetTownRoadBits(TileIndex tile) { if (IsRoadDepotTile(tile) || IsStandardRoadStopTile(tile)) return ROAD_NONE; - return GetAnyRoadBits(tile, ROADTYPE_ROAD, true); + return GetAnyRoadBits(tile, RTT_ROAD, true); +} + +RoadType GetTownRoadType(const Town *t) +{ + RoadType best_rt = ROADTYPE_ROAD; + const RoadTypeInfo *best = nullptr; + const uint16 assume_max_speed = 50; + + for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { + if (RoadTypeIsTram(rt)) continue; + + const RoadTypeInfo *rti = GetRoadTypeInfo(rt); + + /* Unused road type. */ + if (rti->label == 0) continue; + + /* Can town build this road. */ + if (!HasBit(rti->flags, ROTF_TOWN_BUILD)) continue; + + /* Not yet introduced at this date. */ + if (IsInsideMM(rti->introduction_date, 0, MAX_DAY) && rti->introduction_date > _date) continue; + + if (best != nullptr) { + if ((rti->max_speed == 0 ? assume_max_speed : rti->max_speed) < (best->max_speed == 0 ? assume_max_speed : best->max_speed)) continue; + } + + best_rt = rt; + best = rti; + } + + return best_rt; } /** @@ -1009,7 +1116,8 @@ static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir) /* No, try if we are able to build a road piece there. * If that fails clear the land, and if that fails exit. * This is to make sure that we can build a road here later. */ - if (DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_Y : ROAD_X), 0, DC_AUTO, CMD_BUILD_ROAD).Failed() && + RoadType rt = GetTownRoadType(t); + if (DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_Y : ROAD_X) | (rt << 4), 0, DC_AUTO, CMD_BUILD_ROAD).Failed() && DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR).Failed()) { return false; } @@ -1177,7 +1285,8 @@ static bool GrowTownWithExtraHouse(Town *t, TileIndex tile) */ static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd) { - if (DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded()) { + RoadType rt = GetTownRoadType(t); + if (DoCommand(tile, rcmd | (rt << 4), t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded()) { _grow_town_result = GROWTH_SUCCEED; return true; } @@ -1240,8 +1349,9 @@ static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDi byte bridge_type = RandomRange(MAX_BRIDGES - 1); /* Can we actually build the bridge? */ - if (DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE).Succeeded()) { - DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, DC_EXEC | CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE); + RoadType rt = GetTownRoadType(t); + if (DoCommand(tile, bridge_tile, bridge_type | rt << 8 | TRANSPORT_ROAD << 15, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE).Succeeded()) { + DoCommand(tile, bridge_tile, bridge_type | rt << 8 | TRANSPORT_ROAD << 15, DC_EXEC | CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE); _grow_town_result = GROWTH_SUCCEED; return true; } @@ -1250,6 +1360,37 @@ static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDi return false; } + +/** + * Checks whether at least one surrounding roads allows to build a house here + * + * @param t the tile where the house will be built + * @return true if at least one surrounding roadtype allows building houses here + */ +static inline bool RoadTypesAllowHouseHere(TileIndex t) +{ + static const TileIndexDiffC tiles[] = { {-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1} }; + bool allow = false; + + for (const TileIndexDiffC *ptr = tiles; ptr != endof(tiles); ++ptr) { + TileIndex cur_tile = t + ToTileIndexDiff(*ptr); + if (!IsValidTile(cur_tile)) continue; + + if (!(IsTileType(cur_tile, MP_ROAD) || IsTileType(cur_tile, MP_STATION))) continue; + allow = true; + + RoadType road_rt = GetRoadTypeRoad(cur_tile); + RoadType tram_rt = GetRoadTypeTram(cur_tile); + if (road_rt != INVALID_ROADTYPE && !HasBit(GetRoadTypeInfo(road_rt)->flags, ROTF_NO_HOUSES)) return true; + if (tram_rt != INVALID_ROADTYPE && !HasBit(GetRoadTypeInfo(tram_rt)->flags, ROTF_NO_HOUSES)) return true; + } + + /* If no road was found surrounding the tile we can allow building the house since there is + * nothing which forbids it, if a road was found but the execution reached this point, then + * all the found roads don't allow houses to be built */ + return !allow; +} + /** * Grows the given town. * There are at the moment 3 possible way's for @@ -1428,6 +1569,8 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t } } + allow_house &= RoadTypesAllowHouseHere(house_tile); + if (allow_house) { /* Build a house, but not if there already is a house there. */ if (!IsTileType(house_tile, MP_HOUSE)) { @@ -1568,14 +1711,14 @@ static bool GrowTownAtRoad(Town *t, TileIndex start_tile, TileIndex &tile) } tile = TileAddByDiagDir(tile, target_dir); - if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) { + if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, RTT_ROAD)) { /* Don't allow building over roads of other cities */ - if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { + if (IsRoadOwner(tile, RTT_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { return false; - } else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { + } else if (IsRoadOwner(tile, RTT_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { /* If we are in the SE, and this road-piece has no town owner yet, it just found an * owner :) (happy happy happy road now) */ - SetRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN); + SetRoadOwner(tile, RTT_ROAD, OWNER_TOWN); SetTownIndex(tile, t->index); } } @@ -1626,7 +1769,7 @@ static bool GrowTown(Town *t) }; /* Current "company" is a town */ - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); TileIndex tile = t->xy; // The tile we are working with ATM @@ -1655,7 +1798,8 @@ static bool GrowTown(Town *t) /* Only work with plain land that not already has a house */ if (!IsTileType(tile, MP_HOUSE) && IsTileFlat(tile)) { if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) { - DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); + RoadType rt = GetTownRoadType(t); + DoCommand(tile, GenRandomRoadBits() | (rt << 4), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); UpdateTownGrowthTile(tile, TGTS_HOUSE_SKIPPED); cur_company.Restore(); return true; @@ -1865,16 +2009,19 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize * similar towns they're unlikely to grow all in one tick */ t->grow_counter = t->index % TOWN_GROWTH_TICKS; t->growth_rate = TownTicksToGameTicks(250); + t->show_zone = false; + + _town_kdtree.Insert(t->index); /* Set the default cargo requirement for town growth */ switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: - if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER; + if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER; break; case LT_TROPIC: - if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT; - if (FindFirstCargoWithTownEffect(TE_WATER) != NULL) t->goal[TE_WATER] = TOWN_GROWTH_DESERT; + if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT; + if (FindFirstCargoWithTownEffect(TE_WATER) != nullptr) t->goal[TE_WATER] = TOWN_GROWTH_DESERT; break; } @@ -1918,6 +2065,7 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize t->town_label = 3; t->UpdateVirtCoord(); + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeTown(t->index)); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0); t->InitializeLayout(layout); @@ -1980,7 +2128,7 @@ static bool IsUniqueTownName(const char *name) const Town *t; FOR_ALL_TOWNS(t) { - if (t->name != NULL && strcmp(t->name, name) == 0) return false; + if (t->name != nullptr && strcmp(t->name, name) == 0) return false; } return true; @@ -2061,7 +2209,7 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 Town *t; if (random) { t = CreateRandomTown(20, townnameparts, size, city, layout); - if (t == NULL) { + if (t == nullptr) { cost = CommandCost(STR_ERROR_NO_SPACE_FOR_TOWN); } else { _new_town_id = t->index; @@ -2073,13 +2221,13 @@ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 UpdateNearestTownForRoadTiles(false); old_generating_world.Restore(); - if (t != NULL && !StrEmpty(text)) { + if (t != nullptr && !StrEmpty(text)) { t->name = stredup(text); t->UpdateVirtCoord(); } if (_game_mode != GM_EDITOR) { - /* 't' can't be NULL since 'random' is false outside scenedit */ + /* 't' can't be nullptr since 'random' is false outside scenedit */ assert(!random); if (_current_company == OWNER_DEITY) { @@ -2208,7 +2356,7 @@ static TileIndex FindNearestGoodCoastalTownSpot(TileIndex tile, TownLayout layou SpotData sp = { INVALID_TILE, 0, layout }; TileIndex coast = tile; - if (CircularTileSearch(&coast, 40, FindNearestEmptyLand, NULL)) { + if (CircularTileSearch(&coast, 40, FindNearestEmptyLand, nullptr)) { CircularTileSearch(&coast, 10, FindFurthestFromWater, &sp); return sp.tile; } @@ -2221,7 +2369,7 @@ static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size { assert(_game_mode == GM_EDITOR || _generating_world); // These are the preconditions for CMD_DELETE_TOWN - if (!Town::CanAllocateItem()) return NULL; + if (!Town::CanAllocateItem()) return nullptr; do { /* Generate a tile index not too close from the edge */ @@ -2246,7 +2394,7 @@ static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size * placement is so bad it couldn't grow at all */ if (t->cache.population > 0) return t; - Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); + Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); CommandCost rc = DoCommand(t->xy, t->index, 0, DC_EXEC, CMD_DELETE_TOWN); cur_company.Restore(); assert(rc.Succeeded()); @@ -2258,7 +2406,7 @@ static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size assert(Town::CanAllocateItem()); } while (--attempts != 0); - return NULL; + return nullptr; } static const byte _num_initial_towns[4] = {5, 11, 23, 46}; // very low, low, normal, high @@ -2290,17 +2438,20 @@ bool GenerateTowns(TownLayout layout) /* Get a unique name for the town. */ if (!GenerateTownName(&townnameparts, &town_names)) continue; /* try 20 times to create a random-sized town for the first loop. */ - if (CreateRandomTown(20, townnameparts, TSZ_RANDOM, city, layout) != NULL) current_number++; // If creation was successful, raise a flag. + if (CreateRandomTown(20, townnameparts, TSZ_RANDOM, city, layout) != nullptr) current_number++; // If creation was successful, raise a flag. } while (--total); town_names.clear(); + /* Build the town k-d tree again to make sure it's well balanced */ + RebuildTownKdtree(); + if (current_number != 0) return true; /* If current_number is still zero at this point, it means that not a single town has been created. * So give it a last try, but now more aggressive */ if (GenerateTownName(&townnameparts) && - CreateRandomTown(10000, townnameparts, TSZ_RANDOM, _settings_game.economy.larger_towns != 0, layout) != NULL) { + CreateRandomTown(10000, townnameparts, TSZ_RANDOM, _settings_game.economy.larger_towns != 0, layout) != nullptr) { return true; } @@ -2375,6 +2526,8 @@ static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, Hou if (size & BUILDING_2_TILES_Y) ClearMakeHouseTile(t + TileDiffXY(0, 1), town, counter, stage, ++type, random_bits); if (size & BUILDING_2_TILES_X) ClearMakeHouseTile(t + TileDiffXY(1, 0), town, counter, stage, ++type, random_bits); if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), town, counter, stage, ++type, random_bits); + + if (!_generating_world) FindStationsAroundTiles(TileArea(t, (size & BUILDING_2_TILES_X) ? 2 : 1, (size & BUILDING_2_TILES_Y) ? 2 : 1), &town->stations_near, false); } @@ -2391,6 +2544,9 @@ static inline bool CanBuildHouseHere(TileIndex tile, bool noslope) Slope slope = GetTileSlope(tile); if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false; + /* at least one RoadTypes allow building the house here? */ + if (!RoadTypesAllowHouseHere(tile)) return false; + /* building under a bridge? */ if (IsBridgeAbove(tile)) return false; @@ -2814,7 +2970,7 @@ void ClearTownHouse(Town *t, TileIndex tile) CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Town *t = Town::GetIfValid(p1); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; bool reset = StrEmpty(text); @@ -2825,7 +2981,7 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (flags & DC_EXEC) { free(t->name); - t->name = reset ? NULL : stredup(text); + t->name = reset ? nullptr : stredup(text); t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1); @@ -2845,7 +3001,7 @@ const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect) FOR_ALL_CARGOSPECS(cs) { if (cs->town_effect == effect) return cs; } - return NULL; + return nullptr; } /** @@ -2868,11 +3024,11 @@ CommandCost CmdTownCargoGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uin uint16 index = GB(p1, 0, 16); Town *t = Town::GetIfValid(index); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; /* Validate if there is a cargo which is the requested TownEffect */ const CargoSpec *cargo = FindFirstCargoWithTownEffect(te); - if (cargo == NULL) return CMD_ERROR; + if (cargo == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { t->goal[te] = p2; @@ -2896,11 +3052,11 @@ CommandCost CmdTownSetText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 { if (_current_company != OWNER_DEITY) return CMD_ERROR; Town *t = Town::GetIfValid(p1); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { free(t->text); - t->text = StrEmpty(text) ? NULL : stredup(text); + t->text = StrEmpty(text) ? nullptr : stredup(text); InvalidateWindowData(WC_TOWN_VIEW, p1); } @@ -2922,7 +3078,7 @@ CommandCost CmdTownGrowthRate(TileIndex tile, DoCommandFlag flags, uint32 p1, ui if (GB(p2, 16, 16) != 0) return CMD_ERROR; Town *t = Town::GetIfValid(p1); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { if (p2 == 0) { @@ -2961,7 +3117,7 @@ CommandCost CmdExpandTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 { if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY) return CMD_ERROR; Town *t = Town::GetIfValid(p1); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { /* The more houses, the faster we grow */ @@ -3001,7 +3157,7 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 { if (_game_mode != GM_EDITOR && !_generating_world) return CMD_ERROR; Town *t = Town::GetIfValid(p1); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; /* Stations refer to towns. */ const Station *st; @@ -3021,7 +3177,18 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (d->town == t) return CMD_ERROR; } - /* Check all tiles for town ownership. */ + /* Check all tiles for town ownership. First check for bridge tiles, as + * these do not directly have an owner so we need to check adjacent + * tiles. This won't work correctly in the same loop if the adjacent + * tile was already deleted earlier in the loop. */ + for (TileIndex tile = 0; tile < MapSize(); ++tile) { + if (IsTileType(tile, MP_TUNNELBRIDGE) && TestTownOwnsBridge(tile, t)) { + CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); + if (ret.Failed()) return ret; + } + } + + /* Check all remaining tiles for town ownership. */ for (TileIndex tile = 0; tile < MapSize(); ++tile) { bool try_clear = false; switch (GetTileType(tile)) { @@ -3029,10 +3196,6 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 try_clear = HasTownOwnedRoad(tile) && GetTownIndex(tile) == t->index; break; - case MP_TUNNELBRIDGE: - try_clear = IsTileOwner(tile, OWNER_TOWN) && ClosestTownFromTile(tile, UINT_MAX) == t; - break; - case MP_HOUSE: try_clear = GetTownIndex(tile) == t->index; break; @@ -3053,7 +3216,7 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 try_clear = true; } else { /* Tell to find a new town. */ - if (flags & DC_EXEC) o->town = NULL; + if (flags & DC_EXEC) o->town = nullptr; } } } @@ -3069,7 +3232,11 @@ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } /* The town destructor will delete the other things related to the town. */ - if (flags & DC_EXEC) delete t; + if (flags & DC_EXEC) { + _town_kdtree.Remove(t->index); + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeTown(t->index)); + delete t; + } return CommandCost(); } @@ -3136,7 +3303,7 @@ static CommandCost TownActionRoadRebuild(Town *t, DoCommandFlag flags) */ static bool TryClearTile(TileIndex tile) { - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); CommandCost r = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); return r.Succeeded(); @@ -3208,7 +3375,7 @@ static CommandCost TownActionBuildStatue(Town *t, DoCommandFlag flags) if (!CircularTileSearch(&tile, 9, SearchTileForStatue, &statue_data)) return_cmd_error(STR_ERROR_STATUE_NO_SUITABLE_PLACE); if (flags & DC_EXEC) { - Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); + Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); DoCommand(statue_data.best_position, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); BuildObject(OBJECT_STATUE, statue_data.best_position, _current_company, t); @@ -3322,7 +3489,7 @@ static TownActionProc * const _town_action_proc[] = { /** * Get a list of available actions to do at a town. - * @param nump if not NULL add put the number of available actions in it + * @param nump if not nullptr add put the number of available actions in it * @param cid the company that is querying the town * @param t the town that is queried * @return bitmasked value of enabled actions @@ -3365,7 +3532,7 @@ uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t) } } - if (nump != NULL) *nump = num; + if (nump != nullptr) *nump = num; return buttons; } @@ -3383,9 +3550,9 @@ uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t) CommandCost CmdDoTownAction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Town *t = Town::GetIfValid(p1); - if (t == NULL || p2 >= lengthof(_town_action_proc)) return CMD_ERROR; + if (t == nullptr || p2 >= lengthof(_town_action_proc)) return CMD_ERROR; - if (!HasBit(GetMaskOfTownActions(NULL, _current_company, t), p2)) return CMD_ERROR; + if (!HasBit(GetMaskOfTownActions(nullptr, _current_company, t), p2)) return CMD_ERROR; CommandCost cost(EXPENSES_OTHER, _price[PR_TOWN_ACTION] * _town_action_costs[p2] >> 8); @@ -3399,6 +3566,21 @@ CommandCost CmdDoTownAction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint return cost; } +template +static void ForAllStationsNearTown(Town *t, Func func) +{ + /* Ideally the search radius should be close to the actual town zone 0 radius. + * The true radius is not stored or calculated anywhere, only the squared radius. */ + /* The efficiency of this search might be improved for large towns and many stations on the map, + * by using an integer square root approximation giving a value not less than the true square root. */ + uint search_radius = t->cache.squared_town_zone_radius[0] / 2; + ForAllStationsRadius(t->xy, search_radius, [&](const Station * st) { + if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) { + func(st); + } + }); +} + static void UpdateTownRating(Town *t) { /* Increase company ratings if they're low */ @@ -3409,22 +3591,19 @@ static void UpdateTownRating(Town *t) } } - const Station *st; - FOR_ALL_STATIONS(st) { - if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) { - if (st->time_since_load <= 20 || st->time_since_unload <= 20) { - if (Company::IsValidID(st->owner)) { - int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP; - t->ratings[st->owner] = min(new_rating, INT16_MAX); // do not let it overflow - } - } else { - if (Company::IsValidID(st->owner)) { - int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP; - t->ratings[st->owner] = max(new_rating, INT16_MIN); - } + ForAllStationsNearTown(t, [&](const Station *st) { + if (st->time_since_load <= 20 || st->time_since_unload <= 20) { + if (Company::IsValidID(st->owner)) { + int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP; + t->ratings[st->owner] = min(new_rating, INT16_MAX); // do not let it overflow + } + } else { + if (Company::IsValidID(st->owner)) { + int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP; + t->ratings[st->owner] = max(new_rating, INT16_MIN); } } - } + }); /* clamp all ratings to valid values */ for (uint i = 0; i < MAX_COMPANIES; i++) { @@ -3460,14 +3639,11 @@ static void UpdateTownGrowCounter(Town *t, uint16 prev_growth_rate) static int CountActiveStations(Town *t) { int n = 0; - const Station *st; - FOR_ALL_STATIONS(st) { - if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) { - if (st->time_since_load <= 20 || st->time_since_unload <= 20) { - n++; - } + ForAllStationsNearTown(t, [&](const Station * st) { + if (st->time_since_load <= 20 || st->time_since_unload <= 20) { + n++; } - } + }); return n; } @@ -3587,7 +3763,7 @@ CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags if (!Company::IsValidID(_current_company) || (flags & DC_NO_TEST_TOWN_RATING)) return CommandCost(); Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); - if (t == NULL) return CommandCost(); + if (t == nullptr) return CommandCost(); if (t->ratings[_current_company] > RATING_VERYPOOR) return CommandCost(); @@ -3599,32 +3775,25 @@ CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags * Return the town closest to the given tile within \a threshold. * @param tile Starting point of the search. * @param threshold Biggest allowed distance to the town. - * @return Closest town to \a tile within \a threshold, or \c NULL if there is no such town. + * @return Closest town to \a tile within \a threshold, or \c nullptr if there is no such town. * * @note This function only uses distance, the #ClosestTownFromTile function also takes town ownership into account. */ Town *CalcClosestTownFromTile(TileIndex tile, uint threshold) { - Town *t; - uint best = threshold; - Town *best_town = NULL; + if (Town::GetNumItems() == 0) return nullptr; - FOR_ALL_TOWNS(t) { - uint dist = DistanceManhattan(tile, t->xy); - if (dist < best) { - best = dist; - best_town = t; - } - } - - return best_town; + TownID tid = _town_kdtree.FindNearest(TileX(tile), TileY(tile)); + Town *town = Town::Get(tid); + if (DistanceManhattan(tile, town->xy) < threshold) return town; + return nullptr; } /** * Return the town closest (in distance or ownership) to a given tile, within a given threshold. * @param tile Starting point of the search. * @param threshold Biggest allowed distance to the town. - * @return Closest town to \a tile within \a threshold, or \c NULL if there is no such town. + * @return Closest town to \a tile within \a threshold, or \c nullptr if there is no such town. * * @note If you only care about distance, you can use the #CalcClosestTownFromTile function. */ @@ -3641,13 +3810,13 @@ Town *ClosestTownFromTile(TileIndex tile, uint threshold) /* in the case we are generating "many random towns", this value may be INVALID_TOWN */ if (_generating_world) return CalcClosestTownFromTile(tile, threshold); assert(Town::GetNumItems() == 0); - return NULL; + return nullptr; } assert(Town::IsValidID(tid)); Town *town = Town::Get(tid); - if (DistanceManhattan(tile, town->xy) >= threshold) town = NULL; + if (DistanceManhattan(tile, town->xy) >= threshold) town = nullptr; return town; } @@ -3662,7 +3831,7 @@ Town *ClosestTownFromTile(TileIndex tile, uint threshold) } static bool _town_rating_test = false; ///< If \c true, town rating is in test-mode. -static SmallMap _town_test_ratings; ///< Map of towns to modified ratings, while in town rating test-mode. +static SmallMap _town_test_ratings; ///< Map of towns to modified ratings, while in town rating test-mode. /** * Switch the town rating to test-mode, to allow commands to be tested without affecting current ratings. @@ -3674,7 +3843,7 @@ void SetTownRatingTestMode(bool mode) static int ref_count = 0; // Number of times test-mode is switched on. if (mode) { if (ref_count == 0) { - _town_test_ratings.Clear(); + _town_test_ratings.clear(); } ref_count++; } else { @@ -3710,7 +3879,7 @@ static int GetRating(const Town *t) void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags) { /* if magic_bulldozer cheat is active, town doesn't penalize for removing stuff */ - if (t == NULL || (flags & DC_NO_MODIFY_TOWN_RATING) || + if (t == nullptr || (flags & DC_NO_MODIFY_TOWN_RATING) || !Company::IsValidID(_current_company) || (_cheats.magic_bulldozer.value && add < 0)) { return; @@ -3748,7 +3917,7 @@ void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags) CommandCost CheckforTownRating(DoCommandFlag flags, Town *t, TownRatingCheckType type) { /* if magic_bulldozer cheat is active, town doesn't restrict your destructive actions */ - if (t == NULL || !Company::IsValidID(_current_company) || + if (t == nullptr || !Company::IsValidID(_current_company) || _cheats.magic_bulldozer.value || (flags & DC_NO_TEST_TOWN_RATING)) { return CommandCost(); } @@ -3857,12 +4026,12 @@ extern const TileTypeProcs _tile_type_town_procs = { AddAcceptedCargo_Town, // add_accepted_cargo_proc GetTileDesc_Town, // get_tile_desc_proc GetTileTrackStatus_Town, // get_tile_track_status_proc - NULL, // click_tile_proc + nullptr, // click_tile_proc AnimateTile_Town, // animate_tile_proc TileLoop_Town, // tile_loop_proc ChangeTileOwner_Town, // change_tile_owner_proc AddProducedCargo_Town, // add_produced_cargo_proc - NULL, // vehicle_enter_tile_proc + nullptr, // vehicle_enter_tile_proc GetFoundation_Town, // get_foundation_proc TerraformTile_Town, // terraform_tile_proc }; diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 569f1607c9..206e791a8d 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -32,7 +32,9 @@ #include "townname_func.h" #include "core/geometry_func.hpp" #include "genworld.h" +#include "stringfilter_type.h" #include "widgets/dropdown_func.h" +#include "town_kdtree.h" #include "widgets/town_widget.h" @@ -58,12 +60,15 @@ bool TownExecuteAction(const Town *town, uint action){ return false; } +TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc); + typedef GUIList GUITownList; static const NWidgetPart _nested_town_authority_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TA_ZONE_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_LOCAL_AUTHORITY_ZONE, STR_LOCAL_AUTHORITY_ZONE_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), @@ -118,7 +123,7 @@ public: this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL); } - virtual void OnPaint() + void OnPaint() override { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); @@ -131,6 +136,7 @@ public: this->sel_index = -1; } + this->SetWidgetLoweredState(WID_TA_ZONE_BUTTON, this->town->show_zone); this->SetWidgetDisabledState(WID_TA_EXECUTE, this->sel_index == -1); this->DrawWidgets(); @@ -173,15 +179,14 @@ public: SetDParam(1, c->index); int r = this->town->ratings[c->index]; - StringID str; - (str = STR_CARGO_RATING_APPALLING, r <= RATING_APPALLING) || // Apalling - (str++, r <= RATING_VERYPOOR) || // Very Poor - (str++, r <= RATING_POOR) || // Poor - (str++, r <= RATING_MEDIOCRE) || // Mediocore - (str++, r <= RATING_GOOD) || // Good - (str++, r <= RATING_VERYGOOD) || // Very Good - (str++, r <= RATING_EXCELLENT) || // Excellent - (str++, true); // Outstanding + StringID str = STR_CARGO_RATING_APPALLING; + if (r > RATING_APPALLING) str++; + if (r > RATING_VERYPOOR) str++; + if (r > RATING_POOR) str++; + if (r > RATING_MEDIOCRE) str++; + if (r > RATING_GOOD) str++; + if (r > RATING_VERYGOOD) str++; + if (r > RATING_EXCELLENT) str++; SetDParam(2, str); SetDParam(3, this->town->ratings[c->index]); @@ -201,12 +206,12 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_TA_CAPTION) SetDParam(0, this->window_number); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_TA_ACTION_INFO: @@ -241,7 +246,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_TA_ACTION_INFO: { @@ -275,14 +280,26 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { + case WID_TA_ZONE_BUTTON: { + bool new_show_state = !this->town->show_zone; + TownID index = this->town->index; + + new_show_state ? _town_local_authority_kdtree.Insert(index) : _town_local_authority_kdtree.Remove(index); + + this->town->show_zone = new_show_state; + this->SetWidgetLoweredState(widget, new_show_state); + MarkWholeScreenDirty(); + break; + } + case WID_TA_COMMAND_LIST: { int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL); if (!IsInsideMM(y, 0, 5)) return; - y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); + y = GetNthSetBit(GetMaskOfTownActions(nullptr, _local_company, this->town), y + this->vscroll->GetPosition() - 1); if (y >= 0) { this->sel_index = y; this->SetDirty(); @@ -298,7 +315,7 @@ public: } } - virtual void OnHundredthTick() + void OnHundredthTick() override { this->SetDirty(); } @@ -369,7 +386,12 @@ public: this->SetWidgetDisabledState(WID_TV_CB, _game_mode == GM_EDITOR); } - virtual void SetStringParameters(int widget) const + ~TownViewWindow() + { + SetViewportCatchmentTown(Town::Get(this->window_number), false); + } + + void SetStringParameters(int widget) const override { if (widget == WID_TV_CAPTION){ SetDParam(0, this->town->index); @@ -385,7 +407,15 @@ public: this->SetDirty(); } - virtual void DrawWidget(const Rect &r, int widget) const + void OnPaint() override + { + extern const Town *_viewport_highlight_town; + this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town); + + this->DrawWidgets(); + } + + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_TV_INFO) return; @@ -423,7 +453,7 @@ public: uint cargo_text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? 20 : 0); const CargoSpec *cargo = FindFirstCargoWithTownEffect((TownEffect)i); - assert(cargo != NULL); + assert(cargo != nullptr); StringID string; @@ -467,13 +497,13 @@ public: DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN); } - if (this->town->text != NULL) { + if (this->town->text != nullptr) { SetDParamStr(0, this->town->text); DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_TV_CENTER_VIEW: // scroll to location @@ -493,6 +523,10 @@ public: ShowQueryString(STR_TOWN_NAME, STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; + case WID_TV_CATCHMENT: + SetViewportCatchmentTown(Town::Get(this->window_number), !this->IsWidgetLowered(WID_TV_CATCHMENT)); + break; + case WID_TV_EXPAND: { // expand town - only available on Scenario editor /* Warn the user if towns are not allowed to build roads, but do this only once per OpenTTD run. */ static bool _warn_town_no_roads = false; @@ -517,7 +551,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_TV_INFO: @@ -553,7 +587,7 @@ public: if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL; - if (this->town->text != NULL) { + if (this->town->text != nullptr) { SetDParamStr(0, this->town->text); aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT); } @@ -570,9 +604,9 @@ public: } } - virtual void OnResize() + void OnResize() override { - if (this->viewport != NULL) { + if (this->viewport != nullptr) { NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); nvp->UpdateViewportCoordinates(this); @@ -585,7 +619,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* Called when setting station noise or required cargoes have changed, in order to resize the window */ @@ -593,11 +627,11 @@ public: this->ResizeWindowAsNeeded(); } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; - DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str); + DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), nullptr, str); } virtual EventState OnHotkey(int hotkey) @@ -643,6 +677,7 @@ static const NWidgetPart _nested_town_game_view_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(60, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0), EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), }; @@ -677,6 +712,7 @@ static const NWidgetPart _nested_town_editor_view_widgets[] = { NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CB), SetMinimalSize(20, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_CB, 0), EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), }; @@ -710,7 +746,7 @@ static const NWidgetPart _nested_town_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), + NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_TD_FILTER), SetFill(35, 12), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetMinimalSize(196, 0), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP), SetFill(1, 0), SetResize(0, 10), SetScrollbar(WID_TD_SCROLLBAR), EndContainer(), @@ -736,6 +772,9 @@ private: static const StringID sorter_names[]; static GUITownList::SortFunction * const sorter_funcs[]; + StringFilter string_filter; ///< Filter for towns + QueryString townname_editbox; ///< Filter editbox + GUITownList towns; Scrollbar *vscroll; @@ -743,94 +782,95 @@ private: void BuildSortTownList() { if (this->towns.NeedRebuild()) { - this->towns.Clear(); + this->towns.clear(); const Town *t; FOR_ALL_TOWNS(t) { - *this->towns.Append() = t; + this->towns.push_back(t); } - this->towns.Compact(); + this->towns.shrink_to_fit(); this->towns.RebuildDone(); - this->vscroll->SetCount(this->towns.Length()); // Update scrollbar as well. + this->vscroll->SetCount((uint)this->towns.size()); // Update scrollbar as well. } /* Always sort the towns. */ - this->last_town = NULL; + this->last_town = nullptr; this->towns.Sort(); this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns. } /** Sort by town name */ - static int CDECL TownNameSorter(const Town * const *a, const Town * const *b) + static bool TownNameSorter(const Town * const &a, const Town * const &b) { - static char buf_cache[64]; - const Town *ta = *a; - const Town *tb = *b; - char buf[64]; + static char buf_cache[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH]; + char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH]; - SetDParam(0, ta->index); + SetDParam(0, a->index); GetString(buf, STR_TOWN_NAME, lastof(buf)); /* If 'b' is the same town as in the last round, use the cached value * We do this to speed stuff up ('b' is called with the same value a lot of * times after each other) */ - if (tb != last_town) { - last_town = tb; - SetDParam(0, tb->index); + if (b != last_town) { + last_town = b; + SetDParam(0, b->index); GetString(buf_cache, STR_TOWN_NAME, lastof(buf_cache)); } - return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). + return strnatcmp(buf, buf_cache) < 0; // Sort by name (natural sorting). } /** Sort by population (default descending, as big towns are of the most interest). */ - static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b) + static bool TownPopulationSorter(const Town * const &a, const Town * const &b) { - uint32 a_population = (*a)->cache.population; - uint32 b_population = (*b)->cache.population; + uint32 a_population = a->cache.population; + uint32 b_population = b->cache.population; if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b); - return (a_population < b_population) ? -1 : 1; + return a_population < b_population; } /** Sort by real population (default descending, as big towns are of the most interest). */ - static int CDECL TownRealPopulationSorter(const Town * const *a, const Town * const *b) + static bool TownRealPopulationSorter(const Town * const &a, const Town * const &b) { - uint32 a_population = (*a)->cache.potential_pop; - uint32 b_population = (*b)->cache.potential_pop; + uint32 a_population = a->cache.potential_pop; + uint32 b_population = b->cache.potential_pop; if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b); - return (a_population < b_population) ? -1 : 1; + return a_population < b_population; } /** Sort by number of houses (default descending, as big towns are of the most interest). */ - static int CDECL TownHousesSorter(const Town * const *a, const Town * const *b) + static bool TownHousesSorter(const Town * const &a, const Town * const &b) { - uint32 a_houses = (*a)->cache.num_houses; - uint32 b_houses = (*b)->cache.num_houses; + uint32 a_houses = a->cache.num_houses; + uint32 b_houses = b->cache.num_houses; if (a_houses == b_houses) return TownDirectoryWindow::TownPopulationSorter(a, b); - return (a_houses < b_houses) ? -1 : 1; + return a_houses < b_houses; } /** Sort by town rating */ - static int CDECL TownRatingSorter(const Town * const *a, const Town * const *b) + static bool TownRatingSorter(const Town * const &a, const Town * const &b) { - int before = TownDirectoryWindow::last_sorting.order ? 1 : -1; // Value to get 'a' before 'b'. + bool before = !TownDirectoryWindow::last_sorting.order; // Value to get 'a' before 'b'. /* Towns without rating are always after towns with rating. */ - if (HasBit((*a)->have_ratings, _local_company)) { - if (HasBit((*b)->have_ratings, _local_company)) { - int16 a_rating = (*a)->ratings[_local_company]; - int16 b_rating = (*b)->ratings[_local_company]; + if (HasBit(a->have_ratings, _local_company)) { + if (HasBit(b->have_ratings, _local_company)) { + int16 a_rating = a->ratings[_local_company]; + int16 b_rating = b->ratings[_local_company]; if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b); - return (a_rating < b_rating) ? -1 : 1; + return a_rating < b_rating; } return before; } - if (HasBit((*b)->have_ratings, _local_company)) return -before; - return -before * TownDirectoryWindow::TownNameSorter(a, b); // Sort unrated towns always on ascending town name. + if (HasBit(b->have_ratings, _local_company)) return !before; + + /* Sort unrated towns always on ascending town name. */ + if (before) return TownDirectoryWindow::TownNameSorter(a, b); + return !TownDirectoryWindow::TownNameSorter(a, b); } public: - TownDirectoryWindow(WindowDesc *desc) : Window(desc) + TownDirectoryWindow(WindowDesc *desc) : Window(desc), townname_editbox(MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_TOWN_NAME_CHARS) { this->CreateNestedTree(); @@ -842,9 +882,12 @@ public: this->BuildSortTownList(); this->FinishInitNested(0); + + this->querystrings[WID_TD_FILTER] = &this->townname_editbox; + this->townname_editbox.cancel_button = QueryString::ACTION_CLEAR; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_TD_WORLD_POPULATION: @@ -879,7 +922,7 @@ public: return t->larger_town ? STR_TOWN_DIRECTORY_CITY : STR_TOWN_DIRECTORY_TOWN; } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_TD_SORT_ORDER: @@ -889,7 +932,7 @@ public: case WID_TD_LIST: { int n = 0; int y = r.top + WD_FRAMERECT_TOP; - if (this->towns.Length() == 0) { // No towns available. + if (this->towns.size() == 0) { // No towns available. DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y, STR_TOWN_DIRECTORY_NONE); break; } @@ -901,7 +944,7 @@ public: int text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? icon_size.width + 2 : 0); int icon_x = rtl ? r.right - WD_FRAMERECT_RIGHT - icon_size.width : r.left + WD_FRAMERECT_LEFT; - for (uint i = this->vscroll->GetPosition(); i < this->towns.Length(); i++) { + for (uint i = this->vscroll->GetPosition(); i < this->towns.size(); i++) { const Town *t = this->towns[i]; assert(t->xy != INVALID_TILE); @@ -930,7 +973,7 @@ public: } } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_TD_SORT_ORDER: { @@ -952,10 +995,10 @@ public: } case WID_TD_LIST: { Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE); - for (uint i = 0; i < this->towns.Length(); i++) { + for (uint i = 0; i < this->towns.size(); i++) { const Town *t = this->towns[i]; - assert(t != NULL); + assert(t != nullptr); SetDParam(0, t->index); SetDParamMaxDigits(1, 8); @@ -983,7 +1026,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_TD_SORT_ORDER: // Click on sort order button @@ -1006,10 +1049,10 @@ public: case WID_TD_LIST: { // Click on Town Matrix uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_TD_LIST, WD_FRAMERECT_TOP); - if (id_v >= this->towns.Length()) return; // click out of town bounds + if (id_v >= this->towns.size()) return; // click out of town bounds const Town *t = this->towns[id_v]; - assert(t != NULL); + assert(t != nullptr); if (_ctrl_pressed) { ShowExtraViewPortWindow(t->xy); } else { @@ -1020,7 +1063,7 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { if (widget != WID_TD_SORT_CRITERIA) return; @@ -1031,41 +1074,79 @@ public: } } - virtual void OnPaint() + void OnPaint() override { if (this->towns.NeedRebuild()) this->BuildSortTownList(); this->DrawWidgets(); } - virtual void OnHundredthTick() + void OnHundredthTick() override { this->BuildSortTownList(); this->SetDirty(); } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST); } + void OnEditboxChanged(int wid) override + { + if (wid == WID_TD_FILTER) { + this->string_filter.SetFilterTerm(this->townname_editbox.text.buf); + this->InvalidateData(TDIWD_FILTER_CHANGES); + } + } + /** * 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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { - if (data == 0) { - /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ - this->towns.ForceRebuild(); - } else { - this->towns.ForceResort(); + char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH]; + + switch (data) { + case TDIWD_FORCE_REBUILD: + /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ + this->towns.ForceRebuild(); + break; + + case TDIWD_FILTER_CHANGES: + if (this->string_filter.IsEmpty()) { + this->towns.ForceRebuild(); + } else { + this->towns.clear(); + + const Town *t; + FOR_ALL_TOWNS(t) { + this->string_filter.ResetState(); + + SetDParam(0, t->index); + GetString(buf, STR_TOWN_NAME, lastof(buf)); + + this->string_filter.AddLine(buf); + if (this->string_filter.GetState()) this->towns.push_back(t); + } + + this->towns.SetListing(this->last_sorting); + this->towns.ForceResort(); + this->towns.Sort(); + this->towns.shrink_to_fit(); + this->towns.RebuildDone(); + this->vscroll->SetCount((int)this->towns.size()); // Update scrollbar as well. + } + break; + default: + this->towns.ForceResort(); } } }; Listing TownDirectoryWindow::last_sorting = {false, 0}; -const Town *TownDirectoryWindow::last_town = NULL; +const Town *TownDirectoryWindow::last_town = nullptr; /** Names of the sorting functions. */ const StringID TownDirectoryWindow::sorter_names[] = { @@ -1242,7 +1323,7 @@ public: void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc) { - const char *name = NULL; + const char *name = nullptr; if (!this->townnamevalid) { name = this->townname_editbox.text.buf; @@ -1260,7 +1341,7 @@ public: if (success && !_shift_pressed) this->RandomTownName(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_TF_NEW_TOWN: @@ -1305,12 +1386,12 @@ public: } } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->RaiseButtons(); this->UpdateButtons(false); @@ -1321,7 +1402,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; this->UpdateButtons(true); @@ -1341,6 +1422,11 @@ void ShowFoundTownWindow() AllocateWindowDescFront(&_found_town_desc, 0); } +void InitializeTownGui() +{ + _town_local_authority_kdtree.Clear(); +} + //CB static void DrawExtraTownInfo (const Rect &r, uint &y, Town *town, uint line, bool show_house_states_info) { //real pop and rating diff --git a/src/town_kdtree.h b/src/town_kdtree.h new file mode 100644 index 0000000000..9241655854 --- /dev/null +++ b/src/town_kdtree.h @@ -0,0 +1,22 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 town_kdtree.h Declarations for accessing the k-d tree of towns */ + +#ifndef TOWN_KDTREE_H +#define TOWN_KDTREE_H + +#include "core/kdtree.hpp" +#include "town.h" + +inline uint16 Kdtree_TownXYFunc(TownID tid, int dim) { return (dim == 0) ? TileX(Town::Get(tid)->xy) : TileY(Town::Get(tid)->xy); } +typedef Kdtree TownKdtree; + +extern TownKdtree _town_kdtree; +extern TownKdtree _town_local_authority_kdtree; + +#endif diff --git a/src/town_type.h b/src/town_type.h index 0c93c8df85..8204083608 100644 --- a/src/town_type.h +++ b/src/town_type.h @@ -76,10 +76,8 @@ enum Ratings { RATING_BRIBE_DOWN_TO = -50 // XXX SHOULD BE SOMETHING LOWER? }; -/** - * Town Layouts - */ -enum TownLayout { +/** Town Layouts. It needs to be 8bits, because we save and load it as such */ +enum TownLayout : byte { TL_BEGIN = 0, TL_ORIGINAL = 0, ///< Original algorithm (min. 1 distance between roads) TL_BETTER_ROADS, ///< Extended original algorithm (min. 2 distance between roads) @@ -91,19 +89,23 @@ enum TownLayout { NUM_TLS, ///< Number of town layouts }; template <> struct EnumPropsT : MakeEnumPropsT {}; -/** It needs to be 8bits, because we save and load it as such */ -typedef SimpleTinyEnumT TownLayoutByte; // typedefing-enumification of TownLayout -/** Town founding setting values */ -enum TownFounding { +/** Town founding setting values. It needs to be 8bits, because we save and load it as such */ +enum TownFounding : byte { TF_BEGIN = 0, ///< Used for iterations and limit testing TF_FORBIDDEN = 0, ///< Forbidden TF_ALLOWED, ///< Allowed TF_CUSTOM_LAYOUT, ///< Allowed, with custom town layout TF_END, ///< Used for iterations and limit testing }; -/** It needs to be 8bits, because we save and load it as such */ -typedef SimpleTinyEnumT TownFoundingByte; + +/** Town cargo generation modes */ +enum TownCargoGenMode : byte { + TCGM_BEGIN = 0, + TCGM_ORIGINAL = 0, ///< Original algorithm (quadratic cargo by population) + TCGM_BITCOUNT, ///< Bit-counted algorithm (normal distribution from individual house population) + TCGM_END, +}; static const uint MAX_LENGTH_TOWN_NAME_CHARS = 32; ///< The maximum length of a town name in characters including '\0' diff --git a/src/townname.cpp b/src/townname.cpp index b6d55f1ef4..6d30358868 100644 --- a/src/townname.cpp +++ b/src/townname.cpp @@ -31,7 +31,7 @@ TownNameParams::TownNameParams(const Town *t) : grfid(t->townnamegrfid), // by default, use supplied data type(t->townnametype) { - if (t->townnamegrfid != 0 && GetGRFTownName(t->townnamegrfid) == NULL) { + if (t->townnamegrfid != 0 && GetGRFTownName(t->townnamegrfid) == nullptr) { /* Fallback to english original */ this->grfid = 0; this->type = SPECSTR_TOWNNAME_ENGLISH; @@ -92,7 +92,7 @@ bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names) /* Check size and width */ if (Utf8StringLength(buf1) >= MAX_LENGTH_TOWN_NAME_CHARS) return false; - if (town_names != NULL) { + if (town_names != nullptr) { if (town_names->find(buf1) != town_names->end()) return false; town_names->insert(buf1); } else { @@ -101,7 +101,7 @@ bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names) /* We can't just compare the numbers since * several numbers may map to a single name. */ const char *buf = t->name; - if (buf == NULL) { + if (buf == nullptr) { GetTownName(buf2, t, lastof(buf2)); buf = buf2; } @@ -124,7 +124,7 @@ bool GenerateTownName(uint32 *townnameparts, TownNames *town_names) TownNameParams par(_settings_game.game_creation.town_name); /* This function is called very often without entering the gameloop - * inbetween. So reset layout cache to prevent it from growing too big. */ + * in between. So reset layout cache to prevent it from growing too big. */ Layouter::ReduceLineCache(); /* Do not set i too low, since when we run out of names, we loop @@ -504,8 +504,8 @@ static char *MakeFinnishTownName(char *buf, const char *last, uint32 seed) char *end = buf - 1; assert(end >= orig); if (*end == 'i') *end = 'e'; - if (strstr(orig, "a") != NULL || strstr(orig, "o") != NULL || strstr(orig, "u") != NULL || - strstr(orig, "A") != NULL || strstr(orig, "O") != NULL || strstr(orig, "U") != NULL) { + if (strstr(orig, "a") != nullptr || strstr(orig, "o") != nullptr || strstr(orig, "u") != nullptr || + strstr(orig, "A") != nullptr || strstr(orig, "O") != nullptr || strstr(orig, "U") != nullptr) { buf = strecpy(buf, "la", last); } else { buf = strecpy(buf, "l\xC3\xA4", last); diff --git a/src/townname_func.h b/src/townname_func.h index 409993e42a..b175f3daf2 100644 --- a/src/townname_func.h +++ b/src/townname_func.h @@ -17,7 +17,7 @@ char *GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed); char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last); char *GetTownName(char *buff, const Town *t, const char *last); -bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names = NULL); -bool GenerateTownName(uint32 *townnameparts, TownNames *town_names = NULL); +bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names = nullptr); +bool GenerateTownName(uint32 *townnameparts, TownNames *town_names = nullptr); #endif /* TOWNNAME_FUNC_H */ diff --git a/src/track_func.h b/src/track_func.h index a55d6d8f20..4171a808b3 100644 --- a/src/track_func.h +++ b/src/track_func.h @@ -19,7 +19,7 @@ /** * Iterate through each set Track in a TrackBits value. - * For more informations see FOR_EACH_SET_BIT_EX. + * For more information see FOR_EACH_SET_BIT_EX. * * @param var Loop index variable that stores fallowing set track. Must be of type Track. * @param track_bits The value to iterate through (any expression). @@ -127,7 +127,7 @@ static inline TrackdirBits TrackdirToTrackdirBits(Trackdir trackdir) /** * Removes first Track from TrackBits and returns it * - * This function searchs for the first bit in the TrackBits, + * This function searches for the first bit in the TrackBits, * remove this bit from the parameter and returns the found * bit as Track value. It returns INVALID_TRACK if the * parameter was TRACK_BIT_NONE or INVALID_TRACK_BIT. This @@ -647,7 +647,7 @@ static inline bool IsDiagonalTrackdir(Trackdir trackdir) /** * Checks if the given tracks overlap, ie form a crossing. Basically this - * means when there is more than one track on the tile, exept when there are + * means when there is more than one track on the tile, except when there are * two parallel tracks. * @param bits The tracks present. * @return Whether the tracks present overlap in any way. diff --git a/src/track_type.h b/src/track_type.h index 2982288bba..233376b006 100644 --- a/src/track_type.h +++ b/src/track_type.h @@ -18,7 +18,7 @@ * These are used to specify a single track. * Can be translated to a trackbit with TrackToTrackbit */ -enum Track { +enum Track : byte { TRACK_BEGIN = 0, ///< Used for iterations TRACK_X = 0, ///< Track along the x-axis (north-east to south-west) TRACK_Y = 1, ///< Track along the y-axis (north-west to south-east) @@ -34,11 +34,10 @@ enum Track { DECLARE_POSTFIX_INCREMENT(Track) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT TrackByte; /** Bitfield corresponding to Track */ -enum TrackBits { +enum TrackBits : byte { TRACK_BIT_NONE = 0U, ///< No track TRACK_BIT_X = 1U << TRACK_X, ///< X-axis track TRACK_BIT_Y = 1U << TRACK_Y, ///< Y-axis track @@ -60,7 +59,6 @@ enum TrackBits { INVALID_TRACK_BIT = 0xFF, ///< Flag for an invalid trackbits value }; DECLARE_ENUM_AS_BIT_SET(TrackBits) -typedef SimpleTinyEnumT TrackBitsByte; /** * Enumeration for tracks and directions. @@ -71,7 +69,7 @@ typedef SimpleTinyEnumT TrackBitsByte; * reversing track dirs are not considered to be 'valid' except in a small * corner in the road vehicle controller. */ -enum Trackdir { +enum Trackdir : byte { TRACKDIR_BEGIN = 0, ///< Used for iterations TRACKDIR_X_NE = 0, ///< X-axis and direction to north-east TRACKDIR_Y_SE = 1, ///< Y-axis and direction to south-east @@ -95,7 +93,6 @@ enum Trackdir { /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; -typedef TinyEnumT TrackdirByte; /** * Enumeration of bitmasks for the TrackDirs @@ -103,7 +100,7 @@ typedef TinyEnumT TrackdirByte; * These are a combination of tracks and directions. Values are 0-5 in one * direction (corresponding to the Track enum) and 8-13 in the other direction. */ -enum TrackdirBits { +enum TrackdirBits : uint16 { TRACKDIR_BIT_NONE = 0U, ///< No track build TRACKDIR_BIT_X_NE = 1U << TRACKDIR_X_NE, ///< Track x-axis, direction north-east TRACKDIR_BIT_Y_SE = 1U << TRACKDIR_Y_SE, ///< Track y-axis, direction south-east @@ -122,7 +119,6 @@ enum TrackdirBits { INVALID_TRACKDIR_BIT = 0xFFFF, ///< Flag for an invalid trackdirbit value }; DECLARE_ENUM_AS_BIT_SET(TrackdirBits) -typedef SimpleTinyEnumT TrackdirBitsShort; typedef uint32 TrackStatus; diff --git a/src/train.h b/src/train.h index 5958cde1a0..e122fcf2f9 100644 --- a/src/train.h +++ b/src/train.h @@ -36,12 +36,11 @@ enum VehicleRailFlags { }; /** Modes for ignoring signals. */ -enum TrainForceProceeding { +enum TrainForceProceeding : byte { TFP_NONE = 0, ///< Normal operation. TFP_STUCK = 1, ///< Proceed till next signal, but ignore being stuck till then. This includes force leaving depots. TFP_SIGNAL = 2, ///< Ignore next signal, after the signal ignore being stuck. }; -typedef SimpleTinyEnumT TrainForceProceedingByte; /** Flags for Train::ConsistChanged */ enum ConsistChangeFlags { @@ -94,9 +93,9 @@ struct Train FINAL : public GroundVehicle { uint16 crash_anim_pos; ///< Crash animation counter. uint16 flags; - TrackBitsByte track; - TrainForceProceedingByte force_proceed; - RailTypeByte railtype; + TrackBits track; + TrainForceProceeding force_proceed; + RailType railtype; RailTypes compatible_railtypes; /** Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through signals. */ @@ -118,7 +117,7 @@ struct Train FINAL : public GroundVehicle { int GetDisplaySpeed() const { return this->gcache.last_speed; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } Money GetRunningCost() const; - int GetDisplayImageWidth(Point *offset = NULL) const; + int GetDisplayImageWidth(Point *offset = nullptr) const; bool IsInDepot() const { return this->track == TRACK_BIT_DEPOT; } bool Tick(); void OnNewDay(); @@ -146,7 +145,7 @@ struct Train FINAL : public GroundVehicle { inline Train *GetNextUnit() const { Train *v = this->GetNextVehicle(); - if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle(); + if (v != nullptr && v->IsRearDualheaded()) v = v->GetNextVehicle(); return v; } @@ -158,7 +157,7 @@ struct Train FINAL : public GroundVehicle { inline Train *GetPrevUnit() { Train *v = this->GetPrevVehicle(); - if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle(); + if (v != nullptr && v->IsRearDualheaded()) v = v->GetPrevVehicle(); return v; } @@ -173,7 +172,7 @@ struct Train FINAL : public GroundVehicle { * longer than the part after the center. This means we have to round up the * length of the next vehicle but may not round the length of the current * vehicle. */ - return this->gcache.cached_veh_length / 2 + (this->Next() != NULL ? this->Next()->gcache.cached_veh_length + 1 : 0) / 2; + return this->gcache.cached_veh_length / 2 + (this->Next() != nullptr ? this->Next()->gcache.cached_veh_length + 1 : 0) / 2; } protected: // These functions should not be called outside acceleration code. diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 801e02a9df..1f510e0cd0 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -78,7 +78,7 @@ void CheckTrainsLengths() FOR_ALL_TRAINS(v) { if (v->First() == v && !(v->vehstatus & VS_CRASHED)) { - for (const Train *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) { + for (const Train *u = v, *w = v->Next(); w != nullptr; u = w, w = w->Next()) { if (u->track != TRACK_BIT_DEPOT) { if ((w->track != TRACK_BIT_DEPOT && max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) || @@ -119,7 +119,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) bool train_can_tilt = true; - for (Train *u = this; u != NULL; u = u->Next()) { + for (Train *u = this; u != nullptr; u = u->Next()) { const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); /* Check the this->first cache. */ @@ -137,20 +137,20 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) u->InvalidateNewGRFCache(); } - for (Train *u = this; u != NULL; u = u->Next()) { + for (Train *u = this; u != nullptr; u = u->Next()) { /* Update user defined data (must be done before other properties) */ u->tcache.user_def_data = GetVehicleProperty(u, PROP_TRAIN_USER_DATA, u->tcache.user_def_data); this->InvalidateNewGRFCache(); u->InvalidateNewGRFCache(); } - for (Train *u = this; u != NULL; u = u->Next()) { + for (Train *u = this; u != nullptr; u = u->Next()) { const Engine *e_u = u->GetEngine(); const RailVehicleInfo *rvi_u = &e_u->u.rail; if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false; - /* Cache wagon override sprite group. NULL is returned if there is none */ + /* Cache wagon override sprite group. nullptr is returned if there is none */ u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->gcache.first_engine); /* Reset colour map */ @@ -202,7 +202,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) /* check the vehicle length (callback) */ uint16 veh_len = CALLBACK_FAILED; - if (e_u->GetGRF() != NULL && e_u->GetGRF()->grf_version >= 8) { + if (e_u->GetGRF() != nullptr && e_u->GetGRF()->grf_version >= 8) { /* Use callback 36 */ veh_len = GetVehicleProperty(u, PROP_TRAIN_SHORTEN_FACTOR, CALLBACK_FAILED); @@ -316,7 +316,7 @@ int Train::GetCurveSpeedLimit() const int sum = 0; int pos = 0; int lastpos = -1; - for (const Vehicle *u = this; u->Next() != NULL; u = u->Next(), pos++) { + for (const Vehicle *u = this; u->Next() != nullptr; u = u->Next(), pos++) { Direction this_dir = u->direction; Direction next_dir = u->Next()->direction; @@ -400,7 +400,7 @@ int Train::GetCurrentMaxSpeed() const } } - for (const Train *u = this; u != NULL; u = u->Next()) { + for (const Train *u = this; u != nullptr; u = u->Next()) { if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && u->track == TRACK_BIT_DEPOT) { max_speed = min(max_speed, 61); break; @@ -429,7 +429,7 @@ void Train::UpdateAcceleration() /** * Get the width of a train vehicle image in the GUI. - * @param offset Additional offset for positioning the sprite; set to NULL if not needed + * @param offset Additional offset for positioning the sprite; set to nullptr if not needed * @return Width in pixels */ int Train::GetDisplayImageWidth(Point *offset) const @@ -438,12 +438,12 @@ int Train::GetDisplayImageWidth(Point *offset) const int vehicle_pitch = 0; const Engine *e = this->GetEngine(); - if (e->GetGRF() != NULL && is_custom_sprite(e->u.rail.image_index)) { + if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { reference_width = e->GetGRF()->traininfo_vehicle_width; vehicle_pitch = e->GetGRF()->traininfo_vehicle_pitch; } - if (offset != NULL) { + if (offset != nullptr) { offset->x = ScaleGUITrad(reference_width) / 2; offset->y = ScaleGUITrad(vehicle_pitch); } @@ -492,7 +492,7 @@ static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType if (is_custom_sprite(spritenum)) { GetCustomVehicleIcon(engine, dir, image_type, result); if (result->IsValid()) { - if (e->GetGRF() != NULL) { + if (e->GetGRF() != nullptr) { y += ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch); } return; @@ -805,16 +805,16 @@ static Train *FindGoodVehiclePos(const Train *src) Train *t = dst; while (t->engine_type == eng) { t = t->Next(); - if (t == NULL) return dst; + if (t == nullptr) return dst; } } } - return NULL; + return nullptr; } /** Helper type for lists/vectors of trains */ -typedef SmallVector TrainList; +typedef std::vector TrainList; /** * Make a backup of a train into a train list. @@ -823,7 +823,7 @@ typedef SmallVector TrainList; */ static void MakeTrainBackup(TrainList &list, Train *t) { - for (; t != NULL; t = t->Next()) *list.Append() = t; + for (; t != nullptr; t = t->Next()) list.push_back(t); } /** @@ -833,17 +833,16 @@ static void MakeTrainBackup(TrainList &list, Train *t) static void RestoreTrainBackup(TrainList &list) { /* No train, nothing to do. */ - if (list.Length() == 0) return; + if (list.size() == 0) return; - Train *prev = NULL; + Train *prev = nullptr; /* Iterate over the list and rebuild it. */ - for (Train **iter = list.Begin(); iter != list.End(); iter++) { - Train *t = *iter; - if (prev != NULL) { + for (Train *t : list) { + if (prev != nullptr) { prev->SetNext(t); - } else if (t->Previous() != NULL) { + } else if (t->Previous() != nullptr) { /* Make sure the head of the train is always the first in the chain. */ - t->Previous()->SetNext(NULL); + t->Previous()->SetNext(nullptr); } prev = t; } @@ -860,10 +859,10 @@ static void RemoveFromConsist(Train *part, bool chain = false) /* Unlink at the front, but make it point to the next * vehicle after the to be remove part. */ - if (part->Previous() != NULL) part->Previous()->SetNext(tail->Next()); + if (part->Previous() != nullptr) part->Previous()->SetNext(tail->Next()); /* Unlink at the back */ - tail->SetNext(NULL); + tail->SetNext(nullptr); } /** @@ -874,7 +873,7 @@ static void RemoveFromConsist(Train *part, bool chain = false) static void InsertInConsist(Train *dst, Train *chain) { /* We do not want to add something in the middle of an articulated part. */ - assert(dst != NULL && (dst->Next() == NULL || !dst->Next()->IsArticulatedPart())); + assert(dst != nullptr && (dst->Next() == nullptr || !dst->Next()->IsArticulatedPart())); chain->Last()->SetNext(dst->Next()); dst->SetNext(chain); @@ -887,12 +886,12 @@ static void InsertInConsist(Train *dst, Train *chain) */ static void NormaliseDualHeads(Train *t) { - for (; t != NULL; t = t->GetNextVehicle()) { + for (; t != nullptr; t = t->GetNextVehicle()) { if (!t->IsMultiheaded() || !t->IsEngine()) continue; /* Make sure that there are no free cars before next engine */ Train *u; - for (u = t; u->Next() != NULL && !u->Next()->IsEngine(); u = u->Next()) {} + for (u = t; u->Next() != nullptr && !u->Next()->IsEngine(); u = u->Next()) {} if (u == t->other_multiheaded_part) continue; @@ -910,10 +909,10 @@ static void NormaliseDualHeads(Train *t) static void NormaliseSubtypes(Train *chain) { /* Nothing to do */ - if (chain == NULL) return; + if (chain == nullptr) return; /* We must be the first in the chain. */ - assert(chain->Previous() == NULL); + assert(chain->Previous() == nullptr); /* Set the appropriate bits for the first in the chain. */ if (chain->IsWagon()) { @@ -924,7 +923,7 @@ static void NormaliseSubtypes(Train *chain) } /* Now clear the bits for the rest of the chain */ - for (Train *t = chain->Next(); t != NULL; t = t->Next()) { + for (Train *t = chain->Next(); t != nullptr; t = t->Next()) { t->ClearFreeWagon(); t->ClearFrontEngine(); } @@ -944,10 +943,10 @@ static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *origina /* Just add 'new' engines and subtract the original ones. * If that's less than or equal to 0 we can be sure we did * not add any engines (read: trains) along the way. */ - if ((src != NULL && src->IsEngine() ? 1 : 0) + - (dst != NULL && dst->IsEngine() ? 1 : 0) - - (original_src != NULL && original_src->IsEngine() ? 1 : 0) - - (original_dst != NULL && original_dst->IsEngine() ? 1 : 0) <= 0) { + if ((src != nullptr && src->IsEngine() ? 1 : 0) + + (dst != nullptr && dst->IsEngine() ? 1 : 0) - + (original_src != nullptr && original_src->IsEngine() ? 1 : 0) - + (original_dst != nullptr && original_dst->IsEngine() ? 1 : 0) <= 0) { return CommandCost(); } @@ -966,7 +965,7 @@ static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *origina static CommandCost CheckTrainAttachment(Train *t) { /* No multi-part train, no need to check. */ - if (t == NULL || t->Next() == NULL || !t->IsEngine()) return CommandCost(); + if (t == nullptr || t->Next() == nullptr || !t->IsEngine()) return CommandCost(); /* The maximum length for a train. For each part we decrease this by one * and if the result is negative the train is simply too long. */ @@ -977,19 +976,19 @@ static CommandCost CheckTrainAttachment(Train *t) /* Break the prev -> t link so it always holds within the loop. */ t = t->Next(); - prev->SetNext(NULL); + prev->SetNext(nullptr); /* Make sure the cache is cleared. */ head->InvalidateNewGRFCache(); - while (t != NULL) { + while (t != nullptr) { allowed_len -= t->gcache.cached_veh_length; Train *next = t->Next(); /* Unlink the to-be-added piece; it is already unlinked from the previous * part due to the fact that the prev -> t link is broken. */ - t->SetNext(NULL); + t->SetNext(nullptr); /* Don't check callback for articulated or rear dual headed parts */ if (!t->IsArticulatedPart() && !t->IsRearDualheaded()) { @@ -1085,8 +1084,8 @@ static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train if (*src_head == *dst_head) { /* If we aren't moving part(s) to a new train, we are just moving the * front back and there is not destination head. */ - *dst_head = NULL; - } else if (*dst_head == NULL) { + *dst_head = nullptr; + } else if (*dst_head == nullptr) { /* If we are moving to a new train the head of the move train would become * the head of the new vehicle. */ *dst_head = src; @@ -1099,7 +1098,7 @@ static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train * In case we are a multiheaded part we want the complete thing to come * with us, so src->GetNextUnit(), however... when we are e.g. a wagon * that is followed by a rear multihead we do not want to include that. */ - *src_head = move_chain ? NULL : + *src_head = move_chain ? nullptr : (src->IsMultiheaded() ? src->GetNextUnit() : src->GetNextVehicle()); } @@ -1123,7 +1122,7 @@ static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train static void NormaliseTrainHead(Train *head) { /* Not much to do! */ - if (head == NULL) return; + if (head == nullptr) return; /* Tell the 'world' the train changed. */ head->ConsistChanged(CCF_ARRANGE); @@ -1160,7 +1159,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u bool move_chain = HasBit(p1, 20); Train *src = Train::GetIfValid(s); - if (src == NULL) return CMD_ERROR; + if (src == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(src->owner); if (ret.Failed()) return ret; @@ -1171,10 +1170,10 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u /* if nothing is selected as destination, try and find a matching vehicle to drag to. */ Train *dst; if (d == INVALID_VEHICLE) { - dst = src->IsEngine() ? NULL : FindGoodVehiclePos(src); + dst = src->IsEngine() ? nullptr : FindGoodVehiclePos(src); } else { dst = Train::GetIfValid(d); - if (dst == NULL) return CMD_ERROR; + if (dst == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(dst->owner); if (ret.Failed()) return ret; @@ -1185,7 +1184,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u /* if an articulated part is being handled, deal with its parent vehicle */ src = src->GetFirstEnginePart(); - if (dst != NULL) { + if (dst != nullptr) { dst = dst->GetFirstEnginePart(); } @@ -1195,13 +1194,13 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u /* locate the head of the two chains */ Train *src_head = src->First(); Train *dst_head; - if (dst != NULL) { + if (dst != nullptr) { dst_head = dst->First(); if (dst_head->tile != src_head->tile) return CMD_ERROR; /* Now deal with articulated part of destination wagon */ dst = dst->GetLastEnginePart(); } else { - dst_head = NULL; + dst_head = nullptr; } if (src->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT); @@ -1210,13 +1209,13 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u if (move_chain && src_head == dst_head) return CommandCost(); /* When moving a multiheaded part to be place after itself, bail out. */ - if (!move_chain && dst != NULL && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost(); + if (!move_chain && dst != nullptr && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost(); /* Check if all vehicles in the source train are stopped inside a depot. */ if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); /* Check if all vehicles in the destination train are stopped inside a depot. */ - if (dst_head != NULL && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); + if (dst_head != nullptr && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); /* First make a backup of the order of the trains. That way we can do * whatever we want with the order and later on easily revert. */ @@ -1230,13 +1229,13 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u * For the destination head we do not care if it is the same as the source * head because in that case it's just a copy. */ Train *original_src_head = src_head; - Train *original_dst_head = (dst_head == src_head ? NULL : dst_head); + Train *original_dst_head = (dst_head == src_head ? nullptr : dst_head); /* We want this information from before the rearrangement, but execute this after the validation. - * original_src_head can't be NULL; src is by definition != NULL, so src_head can't be NULL as - * src->GetFirst() always yields non-NULL, so eventually original_src_head != NULL as well. */ + * original_src_head can't be nullptr; src is by definition != nullptr, so src_head can't be nullptr as + * src->GetFirst() always yields non-nullptr, so eventually original_src_head != nullptr as well. */ bool original_src_head_front_engine = original_src_head->IsFrontEngine(); - bool original_dst_head_front_engine = original_dst_head != NULL && original_dst_head->IsFrontEngine(); + bool original_dst_head_front_engine = original_dst_head != nullptr && original_dst_head->IsFrontEngine(); /* (Re)arrange the trains in the wanted arrangement. */ ArrangeTrains(&dst_head, dst, &src_head, src, move_chain); @@ -1281,7 +1280,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u * b) the 'next' part is an engine that becomes a front engine. * c) there is no 'next' part, nothing else happens * 5) non front engine gets moved and becomes a new train, nothing else happens - * 6) non front engine gets moved within a train / to another train, nothing hapens + * 6) non front engine gets moved within a train / to another train, nothing happens * 7) wagon gets moved, nothing happens */ if (src == original_src_head && src->IsEngine() && !src->IsFrontEngine()) { @@ -1309,8 +1308,8 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u } /* Add new heads to statistics */ - if (src_head != NULL && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1); - if (dst_head != NULL && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1); + if (src_head != nullptr && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1); + if (dst_head != nullptr && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1); /* Handle 'new engine' part of cases #1b, #2b, #3b, #4b and #5 in NormaliseTrainHead. */ NormaliseTrainHead(src_head); @@ -1321,8 +1320,8 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u CheckCargoCapacity(dst_head); } - if (src_head != NULL) src_head->First()->MarkDirty(); - if (dst_head != NULL) dst_head->First()->MarkDirty(); + if (src_head != nullptr) src_head->First()->MarkDirty(); + if (dst_head != nullptr) dst_head->First()->MarkDirty(); /* We are undoubtedly changing something in the depot and train list. */ InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); @@ -1364,34 +1363,34 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3 /* We need to keep track of the new head and the head of what we're going to sell. */ Train *new_head = first; - Train *sell_head = NULL; + Train *sell_head = nullptr; /* Split the train in the wanted way. */ - ArrangeTrains(&sell_head, NULL, &new_head, v, sell_chain); + ArrangeTrains(&sell_head, nullptr, &new_head, v, sell_chain); /* We don't need to validate the second train; it's going to be sold. */ - CommandCost ret = ValidateTrains(NULL, NULL, first, new_head, (flags & DC_AUTOREPLACE) == 0); + CommandCost ret = ValidateTrains(nullptr, nullptr, first, new_head, (flags & DC_AUTOREPLACE) == 0); if (ret.Failed()) { /* Restore the train we had. */ RestoreTrainBackup(original); return ret; } - if (first->orders.list == NULL && !OrderList::CanAllocateItem()) { + if (first->orders.list == nullptr && !OrderList::CanAllocateItem()) { /* Restore the train we had. */ RestoreTrainBackup(original); return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); } CommandCost cost(EXPENSES_NEW_VEHICLES); - for (Train *t = sell_head; t != NULL; t = t->Next()) cost.AddCost(-t->value); + for (Train *t = sell_head; t != nullptr; t = t->Next()) cost.AddCost(-t->value); /* do it? */ if (flags & DC_EXEC) { /* First normalise the sub types of the chain. */ NormaliseSubtypes(new_head); - if (v == first && v->IsEngine() && !sell_chain && new_head != NULL && new_head->IsFrontEngine()) { + if (v == first && v->IsEngine() && !sell_chain && new_head != nullptr && new_head->IsFrontEngine()) { /* We are selling the front engine. In this case we want to * 'give' the order, unit number and such to the new head. */ new_head->orders.list = first->orders.list; @@ -1619,11 +1618,11 @@ void ReverseTrainSwapVeh(Train *v, int l, int r) /** * Check if the vehicle is a train * @param v vehicle on tile - * @return v if it is a train, NULL otherwise + * @return v if it is a train, nullptr otherwise */ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) { - return (v->type == VEH_TRAIN) ? v : NULL; + return (v->type == VEH_TRAIN) ? v : nullptr; } @@ -1631,18 +1630,18 @@ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) * Checks if a train is approaching a rail-road crossing * @param v vehicle on tile * @param data tile with crossing we are testing - * @return v if it is approaching a crossing, NULL otherwise + * @return v if it is approaching a crossing, nullptr otherwise */ static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data) { - if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL; + if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr; Train *t = Train::From(v); - if (!t->IsFrontEngine()) return NULL; + if (!t->IsFrontEngine()) return nullptr; TileIndex tile = *(TileIndex *)data; - if (TrainApproachingCrossingTile(t) != tile) return NULL; + if (TrainApproachingCrossingTile(t) != tile) return nullptr; return t; } @@ -1681,7 +1680,7 @@ void UpdateLevelCrossing(TileIndex tile, bool sound) assert(IsLevelCrossingTile(tile)); /* reserved || train on crossing || train approaching crossing */ - bool new_state = HasCrossingReservation(tile) || HasVehicleOnPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile); + bool new_state = HasCrossingReservation(tile) || HasVehicleOnPos(tile, nullptr, &TrainOnTileEnum) || TrainApproachingCrossing(tile); if (new_state != IsCrossingBarred(tile)) { if (new_state && sound) { @@ -1745,23 +1744,23 @@ static void AdvanceWagonsAfterSwap(Train *v) { /* first of all, fix the situation when the train was entering a depot */ Train *dep = v; // last vehicle in front of just left depot - while (dep->Next() != NULL && (dep->track == TRACK_BIT_DEPOT || dep->Next()->track != TRACK_BIT_DEPOT)) { + while (dep->Next() != nullptr && (dep->track == TRACK_BIT_DEPOT || dep->Next()->track != TRACK_BIT_DEPOT)) { dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot } Train *leave = dep->Next(); // first vehicle in a depot we are leaving now - if (leave != NULL) { + if (leave != nullptr) { /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */ int d = TicksToLeaveDepot(dep); if (d <= 0) { leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot leave->track = TrackToTrackBits(GetRailDepotTrack(leave->tile)); - for (int i = 0; i >= d; i--) TrainController(leave, NULL); // maybe move it, and maybe let another wagon leave + for (int i = 0; i >= d; i--) TrainController(leave, nullptr); // maybe move it, and maybe let another wagon leave } } else { - dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot + dep = nullptr; // no vehicle in a depot, so no vehicle leaving a depot } Train *base = v; @@ -1771,7 +1770,7 @@ static void AdvanceWagonsAfterSwap(Train *v) /* We have to make sure all wagons that leave a depot because of train reversing are moved correctly * they have already correct spacing, so we have to make sure they are moved how they should */ - bool nomove = (dep == NULL); // If there is no vehicle leaving a depot, limit the number of wagons moved immediately. + bool nomove = (dep == nullptr); // If there is no vehicle leaving a depot, limit the number of wagons moved immediately. while (length > 2) { /* we reached vehicle (originally) in front of a depot, stop now @@ -1787,7 +1786,7 @@ static void AdvanceWagonsAfterSwap(Train *v) int differential = last->CalcNextVehicleOffset() - base->CalcNextVehicleOffset(); /* do not update images now */ - for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL)); + for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : nullptr)); base = first; // == base->Next() length -= 2; @@ -1835,7 +1834,7 @@ void ReverseTrainDirection(Train *v) v->ConsistChanged(CCF_TRACK); /* update all images */ - for (Train *u = v; u != NULL; u = u->Next()) u->UpdateViewport(false, false); + for (Train *u = v; u != nullptr; u = u->Next()) u->UpdateViewport(false, false); /* update crossing we were approaching */ if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); @@ -1894,7 +1893,7 @@ void ReverseTrainDirection(Train *v) CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Train *v = Train::GetIfValid(p1); - if (v == NULL) return CMD_ERROR; + if (v == nullptr) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1930,7 +1929,7 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 /* Properly leave the station if we are loading and won't be loading anymore */ if (v->current_order.IsType(OT_LOADING)) { const Vehicle *last = v; - while (last->Next() != NULL) last = last->Next(); + while (last->Next() != nullptr) last = last->Next(); /* not a station || different station --> leave the station */ if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) { @@ -1967,7 +1966,7 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Train *t = Train::GetIfValid(p1); - if (t == NULL) return CMD_ERROR; + if (t == nullptr) return CMD_ERROR; if (!t->IsPrimaryVehicle()) return CMD_ERROR; @@ -2014,9 +2013,9 @@ static FindDepotData FindClosestTrainDepot(Train *v, int max_distance) /** * Locate the closest depot for this consist, and return the information to the caller. - * @param[out] location If not \c NULL and a depot is found, store its location in the given address. - * @param[out] destination If not \c NULL and a depot is found, store its index in the given address. - * @param[out] reverse If not \c NULL and a depot is found, store reversal information in the given address. + * @param[out] location If not \c nullptr and a depot is found, store its location in the given address. + * @param[out] destination If not \c nullptr and a depot is found, store its index in the given address. + * @param[out] reverse If not \c nullptr and a depot is found, store reversal information in the given address. * @return A depot has been found. */ bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) @@ -2024,9 +2023,9 @@ bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bo FindDepotData tfdd = FindClosestTrainDepot(this, 0); if (tfdd.best_length == UINT_MAX) return false; - if (location != NULL) *location = tfdd.tile; - if (destination != NULL) *destination = GetDepotIndex(tfdd.tile); - if (reverse != NULL) *reverse = tfdd.reverse; + if (location != nullptr) *location = tfdd.tile; + if (destination != nullptr) *destination = GetDepotIndex(tfdd.tile); + if (reverse != nullptr) *reverse = tfdd.reverse; return true; } @@ -2100,10 +2099,10 @@ static void CheckNextTrainTile(Train *v) if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) { /* If the next tile is a PBS signal, try to make a reservation. */ TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); - if (_settings_game.pf.forbid_90_deg) { + if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile))) { tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.m_old_td)); } - ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false); + ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, nullptr, false); } } } @@ -2117,7 +2116,7 @@ static void CheckNextTrainTile(Train *v) static bool CheckTrainStayInDepot(Train *v) { /* bail out if not all wagons are in the same depot or not in a depot at all */ - for (const Train *u = v; u != NULL; u = u->Next()) { + for (const Train *u = v; u != nullptr; u = u->Next()) { if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; } @@ -2246,7 +2245,7 @@ void FreeTrainTrackReservation(const Train *v) if (IsRailDepotTile(tile) && TrackdirToExitdir(td) != GetRailDepotDirection(tile)) return; if (v->track == TRACK_BIT_DEPOT) { /* Front engine is in a depot. We enter if some part is not in the depot. */ - for (const Train *u = v; u != NULL; u = u->Next()) { + for (const Train *u = v; u != nullptr; u = u->Next()) { if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return; } } @@ -2339,7 +2338,7 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, if (HasOnewaySignalBlockingTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) break; } - if (_settings_game.pf.forbid_90_deg) { + if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile))) { ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td); if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) break; } @@ -2360,8 +2359,8 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, if (ft.m_tiles_skipped != 0) ft.m_new_tile -= TileOffsByDiagDir(ft.m_exitdir) * ft.m_tiles_skipped; /* Choice found, path valid but not okay. Save info about the choice tile as well. */ - if (new_tracks != NULL) *new_tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); - if (enterdir != NULL) *enterdir = ft.m_exitdir; + if (new_tracks != nullptr) *new_tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); + if (enterdir != nullptr) *enterdir = ft.m_exitdir; return PBSTileInfo(ft.m_new_tile, ft.m_old_td, false); } @@ -2391,7 +2390,7 @@ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, while (tile != stopped || cur_td != stopped_td) { if (!ft.Follow(tile, cur_td)) break; - if (_settings_game.pf.forbid_90_deg) { + if (Rail90DegTurnDisallowed(GetTileRailType(ft.m_old_tile), GetTileRailType(ft.m_new_tile))) { ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td); assert(ft.m_new_td_bits != TRACKDIR_BIT_NONE); } @@ -2474,7 +2473,7 @@ public: if (this->index >= this->v->GetNumOrders()) this->index = 0; Order *order = this->v->GetOrder(this->index); - assert(order != NULL); + assert(order != nullptr); switch (order->GetType()) { case OT_GOTO_DEPOT: @@ -2517,7 +2516,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, assert((tracks & ~TRACK_BIT_MASK) == 0); - if (got_reservation != NULL) *got_reservation = false; + if (got_reservation != nullptr) *got_reservation = false; /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */ TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir)); @@ -2550,7 +2549,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, } if (res_dest.okay) { /* Got a valid reservation that ends at a safe target, quick exit. */ - if (got_reservation != NULL) *got_reservation = true; + if (got_reservation != nullptr) *got_reservation = true; if (changed_signal) MarkTileDirtyByTile(tile); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); return best_track; @@ -2609,7 +2608,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir); best_track = FindFirstTrack(res); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); - if (got_reservation != NULL) *got_reservation = true; + if (got_reservation != nullptr) *got_reservation = true; if (changed_signal) MarkTileDirtyByTile(tile); } else { FreeTrainTrackReservation(v); @@ -2618,7 +2617,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, return best_track; } - if (got_reservation != NULL) *got_reservation = true; + if (got_reservation != nullptr) *got_reservation = true; /* Reservation target found and free, check if it is safe. */ while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) { @@ -2626,7 +2625,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir); TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir); TrackBits reachable = TrackdirBitsToTrackBits((TrackdirBits)(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0))) & DiagdirReachesTracks(exitdir); - if (_settings_game.pf.forbid_90_deg) { + if (Rail90DegTurnDisallowed(GetTileRailType(res_dest.tile), GetTileRailType(next_tile))) { reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir)); } @@ -2641,7 +2640,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, /* Path found, but could not be reserved. */ FreeTrainTrackReservation(v); if (mark_stuck) MarkTrainAsStuck(v); - if (got_reservation != NULL) *got_reservation = false; + if (got_reservation != nullptr) *got_reservation = false; changed_signal = false; break; } @@ -2650,7 +2649,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) { FreeTrainTrackReservation(v); if (mark_stuck) MarkTrainAsStuck(v); - if (got_reservation != NULL) *got_reservation = false; + if (got_reservation != nullptr) *got_reservation = false; changed_signal = false; } break; @@ -2689,14 +2688,14 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) } } - Vehicle *other_train = NULL; + Vehicle *other_train = nullptr; PBSTileInfo origin = FollowTrainReservation(v, &other_train); /* The path we are driving on is already blocked by some other train. * This can only happen in certain situations when mixing path and * block signals or when changing tracks and/or signals. * Exit here as doing any further reservations will probably just * make matters worse. */ - if (other_train != NULL && other_train->index != v->index) { + if (other_train != nullptr && other_train->index != v->index) { if (mark_as_stuck) MarkTrainAsStuck(v); return false; } @@ -2718,7 +2717,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir); TrackBits reachable = TrackdirBitsToTrackBits(TrackStatusToTrackdirBits(GetTileTrackStatus(new_tile, TRANSPORT_RAIL, 0)) & DiagdirReachesTrackdirs(exitdir)); - if (_settings_game.pf.forbid_90_deg) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir)); + if (Rail90DegTurnDisallowed(GetTileRailType(origin.tile), GetTileRailType(new_tile))) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir)); bool res_made = false; ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck); @@ -2782,7 +2781,7 @@ void Train::MarkDirty() do { v->colourmap = PAL_NONE; v->UpdateViewport(true, false); - } while ((v = v->Next()) != NULL); + } while ((v = v->Next()) != nullptr); /* need to update acceleration and cached values since the goods on the train changed. */ this->CargoChanged(); @@ -2900,7 +2899,7 @@ static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) /** Tries to reserve track under whole train consist. */ void Train::ReserveTrackUnderConsist() const { - for (const Train *u = this; u != NULL; u = u->Next()) { + for (const Train *u = this; u != nullptr; u = u->Next()) { switch (u->track) { case TRACK_BIT_WORMHOLE: TryReserveRailTrack(u->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(u->tile))); @@ -2929,7 +2928,7 @@ uint Train::Crash(bool flooded) /* Remove the reserved path in front of the train if it is not stuck. * Also clear all reserved tracks the train is currently on. */ if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this); - for (const Train *v = this; v != NULL; v = v->Next()) { + for (const Train *v = this; v != nullptr; v = v->Next()) { ClearPathReservation(v, v->tile, v->GetVehicleTrackdir()); if (IsTileType(v->tile, MP_TUNNELBRIDGE)) { /* ClearPathReservation will not free the wormhole exit @@ -2987,23 +2986,23 @@ struct TrainCollideChecker { * Collision test function. * @param v %Train vehicle to test collision with. * @param data %Train being examined. - * @return \c NULL (always continue search) + * @return \c nullptr (always continue search) */ static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) { TrainCollideChecker *tcc = (TrainCollideChecker*)data; /* not a train or in depot */ - if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL; + if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return nullptr; /* do not crash into trains of another company. */ - if (v->owner != tcc->v->owner) return NULL; + if (v->owner != tcc->v->owner) return nullptr; /* get first vehicle now to make most usual checks faster */ Train *coll = Train::From(v)->First(); /* can't collide with own wagons */ - if (coll == tcc->v) return NULL; + if (coll == tcc->v) return nullptr; int x_diff = v->x_pos - tcc->v->x_pos; int y_diff = v->y_pos - tcc->v->y_pos; @@ -3013,20 +3012,20 @@ static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15] * Differences are then ORed and then we check for any higher bits */ uint hash = (y_diff + 7) | (x_diff + 7); - if (hash & ~15) return NULL; + if (hash & ~15) return nullptr; /* Slower check using multiplication */ int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (tcc->v->gcache.cached_veh_length + 1) / 2 - 1; - if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return NULL; + if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return nullptr; /* Happens when there is a train under bridge next to bridge head */ - if (abs(v->z_pos - tcc->v->z_pos) > 5) return NULL; + if (abs(v->z_pos - tcc->v->z_pos) > 5) return nullptr; /* crash both trains */ tcc->num += TrainCrashed(tcc->v); tcc->num += TrainCrashed(coll); - return NULL; // continue searching + return nullptr; // continue searching } /** @@ -3068,15 +3067,15 @@ static bool CheckTrainCollision(Train *v) static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data) { - if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL; + if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return nullptr; Train *t = Train::From(v); DiagDirection exitdir = *(DiagDirection *)data; /* not front engine of a train, inside wormhole or depot, crashed */ - if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return NULL; + if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return nullptr; - if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return NULL; + if (t->cur_speed > 5 || VehicleExitDir(t->direction, t->track) != exitdir) return nullptr; return t; } @@ -3139,7 +3138,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs); TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); - if (_settings_game.pf.forbid_90_deg && prev == NULL) { + if (Rail90DegTurnDisallowed(GetTileRailType(gp.old_tile), GetTileRailType(gp.new_tile)) && prev == nullptr) { /* We allow wagons to make 90 deg turns, because forbid_90_deg * can be switched on halfway a turn */ bits &= ~TrackCrossesTracks(FindFirstTrack(v->track)); @@ -3152,10 +3151,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail; TrackBits chosen_track; - if (prev == NULL) { + if (prev == nullptr) { /* Currently the locomotive is active. Determine which one of the * available tracks to choose */ - chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true)); + chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, nullptr, true)); assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile))); if (v->force_proceed != TFP_NONE && IsPlainRailTile(gp.new_tile) && HasSignals(gp.new_tile)) { @@ -3275,7 +3274,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) } /* Clear any track reservation when the last vehicle leaves the tile */ - if (v->Next() == NULL) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir()); + if (v->Next() == nullptr) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir()); v->tile = gp.new_tile; @@ -3292,7 +3291,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) update_signals_crossing = true; if (chosen_dir != v->direction) { - if (prev == NULL && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { + if (prev == nullptr && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type]; DirDiff diff = DirDifference(v->direction, chosen_dir); v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8; @@ -3348,7 +3347,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) /* update the Z position of the vehicle */ int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false); - if (prev == NULL) { + if (prev == nullptr) { /* This is the first vehicle in the train */ AffectSpeedByZChange(v, old_z); } @@ -3374,7 +3373,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) /* Signals can only change when the first * (above) or the last vehicle moves. */ - if (v->Next() == NULL) { + if (v->Next() == nullptr) { TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile); } @@ -3390,7 +3389,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse) invalid_rail: /* We've reached end of line?? */ - if (prev != NULL) error("Disconnecting train"); + if (prev != nullptr) error("Disconnecting train"); reverse_train_direction: if (reverse) { @@ -3407,7 +3406,7 @@ reverse_train_direction: * Collect trackbits of all crashed train vehicles on a tile * @param v Vehicle passed from Find/HasVehicleOnPos() * @param data trackdirbits for the result - * @return NULL to iterate over all vehicles on the tile. + * @return nullptr to iterate over all vehicles on the tile. */ static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data) { @@ -3423,7 +3422,7 @@ static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data) } } - return NULL; + return nullptr; } /** @@ -3441,8 +3440,8 @@ static void DeleteLastWagon(Train *v) * *u is then the one-before-last wagon, and *v the last * one which will physically be removed */ Train *u = v; - for (; v->Next() != NULL; v = v->Next()) u = v; - u->SetNext(NULL); + for (; v->Next() != nullptr; v = v->Next()) u = v; + u->SetNext(nullptr); if (first != v) { /* Recalculate cached train properties */ @@ -3461,7 +3460,7 @@ static void DeleteLastWagon(Train *v) Owner owner = v->owner; delete v; - v = NULL; // make sure nobody will try to read 'v' anymore + v = nullptr; // make sure nobody will try to read 'v' anymore if (trackbits == TRACK_BIT_WORMHOLE) { /* Vehicle is inside a wormhole, v->track contains no useful value then. */ @@ -3517,7 +3516,7 @@ static void ChangeTrainDirRandomly(Train *v) v->UpdateViewport(false, true); } } - } while ((v = v->Next()) != NULL); + } while ((v = v->Next()) != nullptr); } /** @@ -3549,13 +3548,13 @@ static bool HandleCrashedTrain(Train *v) EV_EXPLOSION_SMALL); break; } - } while ((u = u->Next()) != NULL); + } while ((u = u->Next()) != nullptr); } if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v); if (state >= 4440 && !(v->tick_counter & 0x1F)) { - bool ret = v->Next() != NULL; + bool ret = v->Next() != nullptr; DeleteLastWagon(v); return ret; } @@ -3711,7 +3710,7 @@ static bool TrainCheckIfLineEnds(Train *v, bool reverse) /* mask unreachable track bits if we are forbidden to do 90deg turns */ TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); - if (_settings_game.pf.forbid_90_deg) { + if (Rail90DegTurnDisallowed(GetTileRailType(v->tile), GetTileRailType(tile))) { bits &= ~TrackCrossesTracks(FindFirstTrack(v->track)); } @@ -3838,7 +3837,7 @@ static bool TrainLocoHandler(Train *v, bool mode) /* Loop until the train has finished moving. */ for (;;) { j -= adv_spd; - TrainController(v, NULL); + TrainController(v, nullptr); /* Don't continue to move if the train crashed. */ if (CheckTrainCollision(v)) break; /* Determine distance to next map position */ @@ -3859,7 +3858,7 @@ static bool TrainLocoHandler(Train *v, bool mode) v->SetLastSpeed(); } - for (Train *u = v; u != NULL; u = u->Next()) { + for (Train *u = v; u != nullptr; u = u->Next()) { if ((u->vehstatus & VS_HIDDEN) != 0) continue; u->UpdateViewport(false, false); @@ -3890,7 +3889,7 @@ Money Train::GetRunningCost() const if (v->IsMultiheaded()) cost_factor /= 2; cost += GetPrice(e->u.rail.running_cost_class, cost_factor, e->GetGRF()); - } while ((v = v->GetNextVehicle()) != NULL); + } while ((v = v->GetNextVehicle()) != nullptr); return cost; } diff --git a/src/train_gui.cpp b/src/train_gui.cpp index e6a676b102..c0f976d6e1 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -34,17 +34,17 @@ void CcBuildWagon(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p if (result.Failed()) return; /* find a locomotive in the depot. */ - const Vehicle *found = NULL; + const Vehicle *found = nullptr; const Train *t; FOR_ALL_TRAINS(t) { if (t->IsFrontEngine() && t->tile == tile && t->IsStoppedInDepot()) { - if (found != NULL) return; // must be exactly one. + if (found != nullptr) return; // must be exactly one. found = t; } } /* if we found a loco, */ - if (found != NULL) { + if (found != nullptr) { found = found->Last(); /* put the new wagon at the end of the loco. */ DoCommandP(0, _new_vehicle_id, found->index, CMD_MOVE_RAIL_VEHICLE); @@ -66,8 +66,8 @@ static int HighlightDragPosition(int px, int max_width, VehicleID selection, boo assert(selection != INVALID_VEHICLE); int dragged_width = 0; - for (Train *t = Train::Get(selection); t != NULL; t = chain ? t->Next() : (t->HasArticulatedPart() ? t->GetNextArticulatedPart() : NULL)) { - dragged_width += t->GetDisplayImageWidth(NULL); + for (Train *t = Train::Get(selection); t != nullptr; t = chain ? t->Next() : (t->HasArticulatedPart() ? t->GetNextArticulatedPart() : nullptr)) { + dragged_width += t->GetDisplayImageWidth(nullptr); } int drag_hlight_left = rtl ? max(px - dragged_width + 1, 0) : px; @@ -113,7 +113,7 @@ void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID select bool sel_articulated = false; bool dragging = (drag_dest != INVALID_VEHICLE); bool drag_at_end_of_train = (drag_dest == v->index); // Head index is used to mark dragging at end of train. - for (; v != NULL && (rtl ? px > 0 : px < max_width); v = v->Next()) { + for (; v != nullptr && (rtl ? px > 0 : px < max_width); v = v->Next()) { if (dragging && !drag_at_end_of_train && drag_dest == v->index) { /* Highlight the drag-and-drop destination inside the train. */ int drag_hlight_width = HighlightDragPosition(px, max_width, selection, _cursor.vehchain); @@ -175,13 +175,19 @@ struct CargoSummaryItem { { return this->cargo != other.cargo || this->subtype != other.subtype; } + + /** Used by std::find() and similar functions */ + inline bool operator == (const CargoSummaryItem &other) const + { + return !(this->cargo != other.cargo); + } }; static const uint TRAIN_DETAILS_MIN_INDENT = 32; ///< Minimum indent level in the train details window static const uint TRAIN_DETAILS_MAX_INDENT = 72; ///< Maximum indent level in the train details window; wider than this and we start on a new line /** Container for the cargo summary information. */ -typedef SmallVector CargoSummary; +typedef std::vector CargoSummary; /** Reused container of cargo details */ static CargoSummary _cargo_summary; @@ -264,7 +270,7 @@ static void TrainDetailsCapacityTab(const CargoSummaryItem *item, int left, int */ static void GetCargoSummaryOfArticulatedVehicle(const Train *v, CargoSummary *summary) { - summary->Clear(); + summary->clear(); do { if (!v->GetEngine()->CanCarryCargo()) continue; @@ -273,9 +279,10 @@ static void GetCargoSummaryOfArticulatedVehicle(const Train *v, CargoSummary *su new_item.subtype = GetCargoSubtypeText(v); if (new_item.cargo == INVALID_CARGO && new_item.subtype == STR_EMPTY) continue; - CargoSummaryItem *item = summary->Find(new_item); - if (item == summary->End()) { - item = summary->Append(); + auto item = std::find(summary->begin(), summary->end(), new_item); + if (item == summary->end()) { + summary->emplace_back(); + item = summary->end() - 1; item->cargo = new_item.cargo; item->subtype = new_item.subtype; item->capacity = 0; @@ -286,7 +293,7 @@ static void GetCargoSummaryOfArticulatedVehicle(const Train *v, CargoSummary *su item->capacity += v->cargo_cap; item->amount += v->cargo.StoredCount(); if (item->source == INVALID_STATION) item->source = v->cargo.Source(); - } while ((v = v->Next()) != NULL && v->IsArticulatedPart()); + } while ((v = v->Next()) != nullptr && v->IsArticulatedPart()); } /** @@ -300,7 +307,7 @@ static uint GetLengthOfArticulatedVehicle(const Train *v) do { length += v->GetDisplayImageWidth(); - } while ((v = v->Next()) != NULL && v->IsArticulatedPart()); + } while ((v = v->Next()) != nullptr && v->IsArticulatedPart()); return length; } @@ -318,7 +325,7 @@ int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab) if (det_tab == TDW_TAB_TOTALS) { // Total cargo tab CargoArray act_cargo; CargoArray max_cargo; - for (const Vehicle *v = Vehicle::Get(veh_id); v != NULL; v = v->Next()) { + for (const Vehicle *v = Vehicle::Get(veh_id); v != nullptr; v = v->Next()) { act_cargo[v->cargo_type] += v->cargo.StoredCount(); max_cargo[v->cargo_type] += v->cargo_cap; } @@ -331,9 +338,9 @@ int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab) } num++; // needs one more because first line is description string } else { - for (const Train *v = Train::Get(veh_id); v != NULL; v = v->GetNextVehicle()) { + for (const Train *v = Train::Get(veh_id); v != nullptr; v = v->GetNextVehicle()) { GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary); - num += max(1u, _cargo_summary.Length()); + num += max(1u, (unsigned)_cargo_summary.size()); uint length = GetLengthOfArticulatedVehicle(v); if (length > TRAIN_DETAILS_MAX_INDENT) num++; @@ -369,7 +376,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po bool rtl = _current_text_dir == TD_RTL; Direction dir = rtl ? DIR_E : DIR_W; int x = rtl ? right : left; - for (; v != NULL && vscroll_pos > -vscroll_cap; v = v->GetNextVehicle()) { + for (; v != nullptr && vscroll_pos > -vscroll_cap; v = v->GetNextVehicle()) { GetCargoSummaryOfArticulatedVehicle(v, &_cargo_summary); /* Draw sprites */ @@ -382,7 +389,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po if (vscroll_pos <= 0 && vscroll_pos > -vscroll_cap) { int pitch = 0; const Engine *e = Engine::Get(v->engine_type); - if (e->GetGRF() != NULL) { + if (e->GetGRF() != nullptr) { pitch = ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch); } PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); @@ -393,7 +400,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po px += rtl ? -width : width; dx += width; u = u->Next(); - } while (u != NULL && u->IsArticulatedPart()); + } while (u != nullptr && u->IsArticulatedPart()); bool separate_sprite_row = (dx > (uint)ScaleGUITrad(TRAIN_DETAILS_MAX_INDENT)); if (separate_sprite_row) { @@ -401,7 +408,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po dx = 0; } - uint num_lines = max(1u, _cargo_summary.Length()); + uint num_lines = max(1u, (unsigned)_cargo_summary.size()); for (uint i = 0; i < num_lines; i++) { int sprite_width = max(dx, ScaleGUITrad(TRAIN_DETAILS_MIN_INDENT)) + 3; int data_left = left + (rtl ? 0 : sprite_width); @@ -413,7 +420,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po } switch (det_tab) { case TDW_TAB_CARGO: - if (i < _cargo_summary.Length()) { + if (i < _cargo_summary.size()) { TrainDetailsCargoTab(&_cargo_summary[i], data_left, data_right, py); } else { DrawString(data_left, data_right, py, STR_QUANTITY_N_A, TC_LIGHT_BLUE); @@ -425,7 +432,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po break; case TDW_TAB_CAPACITY: - if (i < _cargo_summary.Length()) { + if (i < _cargo_summary.size()) { TrainDetailsCapacityTab(&_cargo_summary[i], data_left, data_right, py); } else { SetDParam(0, STR_EMPTY); @@ -444,7 +451,7 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po CargoArray max_cargo; Money feeder_share = 0; - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { act_cargo[u->cargo_type] += u->cargo.StoredCount(); max_cargo[u->cargo_type] += u->cargo_cap; feeder_share += u->cargo.FeederShare(); diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp index 4bad2b0561..c396b52f5e 100644 --- a/src/transparency_gui.cpp +++ b/src/transparency_gui.cpp @@ -35,13 +35,13 @@ public: this->InitNested(window_number); } - virtual void OnPaint() + void OnPaint() override { this->OnInvalidateData(0); // Must be sure that the widgets show the transparency variable changes, also when we use shortcuts. this->DrawWidgets(); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_TT_SIGNS: @@ -69,7 +69,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { if (widget >= WID_TT_BEGIN && widget < WID_TT_END) { if (_ctrl_pressed) { @@ -104,7 +104,7 @@ public: } } - virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) + Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override { Point pt = GetToolbarAlignedWindowPosition(sm_width); pt.y += 2 * (sm_height - this->GetWidget(WID_TT_BUTTONS)->current_y); @@ -116,7 +116,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; for (uint i = WID_TT_BEGIN; i < WID_TT_END; i++) { diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index 7240cf86d3..e982abfb28 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -342,8 +342,8 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Check the tree type within the current climate */ if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[_settings_game.game_creation.landscape], _tree_count_by_landscape[_settings_game.game_creation.landscape])) return CMD_ERROR; - Company *c = (_game_mode != GM_EDITOR) ? Company::GetIfValid(_current_company) : NULL; - int limit = (c == NULL ? INT32_MAX : GB(c->tree_limit, 16, 16)); + Company *c = (_game_mode != GM_EDITOR) ? Company::GetIfValid(_current_company) : nullptr; + int limit = (c == nullptr ? INT32_MAX : GB(c->tree_limit, 16, 16)); TileArea ta(tile, p2); TILE_AREA_LOOP(tile, ta) { @@ -364,7 +364,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (flags & DC_EXEC) { AddTreeCount(tile, 1); MarkTileDirtyByTile(tile); - if (c != NULL) c->tree_limit -= 1 << 16; + if (c != nullptr) c->tree_limit -= 1 << 16; } /* 2x as expensive to add more trees to an existing tile */ cost.AddCost(_price[PR_BUILD_TREES] * 2); @@ -419,7 +419,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 if (_game_mode != GM_EDITOR && Company::IsValidID(_current_company)) { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); - if (t != NULL) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM, flags); + if (t != nullptr) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM, flags); } if (flags & DC_EXEC) { @@ -431,7 +431,7 @@ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Plant full grown trees in scenario editor */ PlantTreesOnTile(tile, treetype, 0, _game_mode == GM_EDITOR ? 3 : 0); MarkTileDirtyByTile(tile); - if (c != NULL) c->tree_limit -= 1 << 16; + if (c != nullptr) c->tree_limit -= 1 << 16; /* When planting rainforest-trees, set tropiczone to rainforest in editor. */ if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) { @@ -552,7 +552,7 @@ static CommandCost ClearTile_Trees(TileIndex tile, DoCommandFlag flags) if (Company::IsValidID(_current_company)) { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); - if (t != NULL) ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM, flags); + if (t != nullptr) ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM, flags); } num = GetTreeCount(tile); @@ -803,15 +803,15 @@ extern const TileTypeProcs _tile_type_trees_procs = { DrawTile_Trees, // draw_tile_proc GetSlopePixelZ_Trees, // get_slope_z_proc ClearTile_Trees, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_Trees, // get_tile_desc_proc GetTileTrackStatus_Trees, // get_tile_track_status_proc - NULL, // click_tile_proc - NULL, // animate_tile_proc + nullptr, // click_tile_proc + nullptr, // animate_tile_proc TileLoop_Trees, // tile_loop_proc ChangeTileOwner_Trees, // change_tile_owner_proc - NULL, // add_produced_cargo_proc - NULL, // vehicle_enter_tile_proc + nullptr, // add_produced_cargo_proc + nullptr, // vehicle_enter_tile_proc GetFoundation_Trees, // get_foundation_proc TerraformTile_Trees, // terraform_tile_proc }; diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index f21eeaef2e..1b1dce95ac 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -84,7 +84,7 @@ public: return size; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { if (widget >= WID_BT_TYPE_11 && widget <= WID_BT_TYPE_34) { Dimension d = GetMaxTreeSpriteSize(); @@ -102,7 +102,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget < WID_BT_TYPE_11 || widget > WID_BT_TYPE_34 || widget - WID_BT_TYPE_11 >= this->count) return; @@ -111,7 +111,7 @@ public: DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - 7); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_BT_TYPE_11: case WID_BT_TYPE_12: case WID_BT_TYPE_13: case WID_BT_TYPE_14: @@ -138,17 +138,17 @@ public: } } - virtual void OnPlaceObject(Point pt, TileIndex tile) + void OnPlaceObject(Point pt, TileIndex tile) override { VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); } - virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) + void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } - virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) + void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) { DoCommandP(end_tile, this->tree_to_plant, start_tile, @@ -159,13 +159,13 @@ public: /** * Initialize the window data */ - virtual void OnInit() + void OnInit() override { this->base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; this->count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; } - virtual void OnPlaceObjectAbort() + void OnPlaceObjectAbort() override { this->RaiseButtons(); } diff --git a/src/tree_map.h b/src/tree_map.h index bd1567b54c..f6315e9710 100644 --- a/src/tree_map.h +++ b/src/tree_map.h @@ -100,8 +100,8 @@ static inline TreeGround GetTreeGround(TileIndex t) * that this value doesn't count the number of trees on a tile, use * #GetTreeCount instead. This function instead returns some kind of * groundtype of the tile. As the map-array is finite in size and - * the informations about the trees must be saved somehow other - * informations about a tile must be saved somewhere encoded in the + * the information about the trees must be saved somehow other + * information about a tile must be saved somewhere encoded in the * tile. So this function returns the density of a tile for sub arctic * and sub tropical games. This means for sub arctic the type of snowline * (0 to 3 for all 4 types of snowtiles) and for sub tropical the value @@ -264,7 +264,7 @@ static inline void SetTreeCounter(TileIndex t, uint c) /** * Make a tree-tile. * - * This functions change the tile to a tile with trees and all informations which belongs to it. + * This functions change the tile to a tile with trees and all information which belongs to it. * * @param t The tile to make a tree-tile from * @param type The type of the tree diff --git a/src/tunnel_map.h b/src/tunnel_map.h index d6f475d05c..a1df77f3ce 100644 --- a/src/tunnel_map.h +++ b/src/tunnel_map.h @@ -48,7 +48,7 @@ bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir); * @param d the direction facing out of the tunnel * @param r the road type used in the tunnel */ -static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTypes r) +static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadType road_rt, RoadType tram_rt) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); @@ -59,9 +59,9 @@ static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTyp SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; _me[t].m8 = 0; - SetRoadOwner(t, ROADTYPE_ROAD, o); - if (o != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, o); - SetRoadTypes(t, r); + SetRoadOwner(t, RTT_ROAD, o); + if (o != OWNER_TOWN) SetRoadOwner(t, RTT_TRAM, o); + SetRoadTypes(t, road_rt, tram_rt); } /** diff --git a/src/tunnelbridge.h b/src/tunnelbridge.h index 0a2c2293d5..93603acb59 100644 --- a/src/tunnelbridge.h +++ b/src/tunnelbridge.h @@ -13,6 +13,7 @@ #define TUNNELBRIDGE_H #include "map_func.h" +#include "tile_map.h" void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height); void MarkBridgeDirty(TileIndex tile); @@ -33,6 +34,18 @@ static inline uint GetTunnelBridgeLength(TileIndex begin, TileIndex end) return abs(x2 + y2 - x1 - y1) - 1; } +/** + * Sets the ownership of the bridge/tunnel ramps + * @param begin The begin of the tunnel or bridge. + * @param end The end of the tunnel or bridge. + * @param owner The new owner to set + */ +static inline void SetTunnelBridgeOwner(TileIndex begin, TileIndex end, Owner owner) +{ + SetTileOwner(begin, owner); + SetTileOwner(end, owner); +} + extern TileIndex _build_tunnel_endtile; #endif /* TUNNELBRIDGE_H */ diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp index 06dc24e84f..db33680501 100644 --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -37,9 +37,11 @@ #include "pbs.h" #include "company_base.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "object_base.h" #include "water.h" #include "company_gui.h" +#include "station_func.h" #include "table/strings.h" #include "table/bridge_land.h" @@ -84,7 +86,7 @@ void ResetBridges() { /* First, free sprite table data */ for (BridgeType i = 0; i < MAX_BRIDGES; i++) { - if (_bridge[i].sprite_table != NULL) { + if (_bridge[i].sprite_table != nullptr) { for (BridgePieces j = BRIDGE_PIECE_NORTH; j < BRIDGE_PIECE_INVALID; j++) free(_bridge[i].sprite_table[j]); free(_bridge[i].sprite_table); } @@ -150,7 +152,7 @@ static inline const PalSpriteID *GetBridgeSpriteTable(int index, BridgePieces ta { const BridgeSpec *bridge = GetBridgeSpec(index); assert(table < BRIDGE_PIECE_INVALID); - if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) { + if (bridge->sprite_table == nullptr || bridge->sprite_table[table] == nullptr) { return _bridge_sprite_table[index][table]; } else { return bridge->sprite_table[table]; @@ -230,7 +232,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u CompanyID company = _current_company; RailType railtype = INVALID_RAILTYPE; - RoadTypes roadtypes = ROADTYPES_NONE; + RoadType roadtype = INVALID_ROADTYPE; /* unpack parameters */ BridgeType bridge_type = GB(p2, 0, 8); @@ -242,8 +244,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u /* type of bridge */ switch (transport_type) { case TRANSPORT_ROAD: - roadtypes = Extract(p2); - if (!HasExactlyOneBit(roadtypes) || !HasRoadTypesAvail(company, roadtypes)) return CMD_ERROR; + roadtype = Extract(p2); + if (!ValParamRoadType(roadtype)) return CMD_ERROR; break; case TRANSPORT_RAIL: @@ -268,7 +270,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u company = OWNER_TOWN; /* If we are not within a town, we are not owned by the town */ - if (town == NULL || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { + if (town == nullptr || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { company = OWNER_NONE; } } @@ -313,23 +315,48 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u CommandCost cost(EXPENSES_CONSTRUCTION); Owner owner; bool is_new_owner; + RoadType road_rt = INVALID_ROADTYPE; + RoadType tram_rt = INVALID_ROADTYPE; if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) && GetOtherBridgeEnd(tile_start) == tile_end && GetTunnelBridgeTransportType(tile_start) == transport_type) { /* Replace a current bridge. */ + switch (transport_type) { + case TRANSPORT_RAIL: + /* Keep the reservation, the path stays valid. */ + pbs_reservation = HasTunnelBridgeReservation(tile_start); + break; + + case TRANSPORT_ROAD: + /* Do not remove road types when upgrading a bridge */ + road_rt = GetRoadTypeRoad(tile_start); + tram_rt = GetRoadTypeTram(tile_start); + break; + + default: break; + } + /* If this is a railway bridge, make sure the railtypes match. */ if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } + /* If this is a road bridge, make sure the roadtype matches. */ + if (transport_type == TRANSPORT_ROAD) { + RoadType existing_rt = RoadTypeIsRoad(roadtype) ? road_rt : tram_rt; + if (existing_rt != roadtype && existing_rt != INVALID_ROADTYPE) { + return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); + } + } + /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */ if (!(flags & DC_QUERY_COST) && IsTileOwner(tile_start, OWNER_TOWN) && GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed && _game_mode != GM_EDITOR) { Town *t = ClosestTownFromTile(tile_start, UINT_MAX); - if (t == NULL) { + if (t == nullptr) { return CMD_ERROR; } else { SetDParam(0, t->index); @@ -338,7 +365,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u } /* Do not replace the bridge with the same bridge type. */ - if (!(flags & DC_QUERY_COST) && (bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || (roadtypes & ~GetRoadTypes(tile_start)) == 0)) { + if (!(flags & DC_QUERY_COST) && (bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || road_rt == roadtype || tram_rt == roadtype)) { return_cmd_error(STR_ERROR_ALREADY_BUILT); } @@ -353,20 +380,6 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u /* If bridge belonged to bankrupt company, it has a new owner now */ is_new_owner = (owner == OWNER_NONE); if (is_new_owner) owner = company; - - switch (transport_type) { - case TRANSPORT_RAIL: - /* Keep the reservation, the path stays valid. */ - pbs_reservation = HasTunnelBridgeReservation(tile_start); - break; - - case TRANSPORT_ROAD: - /* Do not remove road types when upgrading a bridge */ - roadtypes |= GetRoadTypes(tile_start); - break; - - default: break; - } } else { /* Build a new bridge. */ @@ -471,6 +484,13 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u is_new_owner = true; } + bool hasroad = road_rt != INVALID_ROADTYPE; + bool hastram = tram_rt != INVALID_ROADTYPE; + if (transport_type == TRANSPORT_ROAD) { + if (RoadTypeIsRoad(roadtype)) road_rt = roadtype; + if (RoadTypeIsTram(roadtype)) tram_rt = roadtype; + } + /* do the drill? */ if (flags & DC_EXEC) { DiagDirection dir = AxisToDiagDir(direction); @@ -479,7 +499,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u switch (transport_type) { case TRANSPORT_RAIL: /* Add to company infrastructure count if required. */ - if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; + if (is_new_owner && c != nullptr) c->infrastructure.rail[railtype] += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype); MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype); SetTunnelBridgeReservation(tile_start, pbs_reservation); @@ -487,31 +507,35 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u break; case TRANSPORT_ROAD: { - RoadTypes prev_roadtypes = IsBridgeTile(tile_start) ? GetRoadTypes(tile_start) : ROADTYPES_NONE; if (is_new_owner) { /* Also give unowned present roadtypes to new owner */ - if (HasBit(prev_roadtypes, ROADTYPE_ROAD) && GetRoadOwner(tile_start, ROADTYPE_ROAD) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_ROAD); - if (HasBit(prev_roadtypes, ROADTYPE_TRAM) && GetRoadOwner(tile_start, ROADTYPE_TRAM) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_TRAM); + if (hasroad && GetRoadOwner(tile_start, RTT_ROAD) == OWNER_NONE) hasroad = false; + if (hastram && GetRoadOwner(tile_start, RTT_TRAM) == OWNER_NONE) hastram = false; } - if (c != NULL) { + if (c != nullptr) { /* Add all new road types to the company infrastructure counter. */ - RoadType new_rt; - FOR_EACH_SET_ROADTYPE(new_rt, roadtypes ^ prev_roadtypes) { + if (!hasroad && road_rt != INVALID_ROADTYPE) { /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[new_rt] += (bridge_len + 2) * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; + c->infrastructure.road[road_rt] += (bridge_len + 2) * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; + } + if (!hastram && tram_rt != INVALID_ROADTYPE) { + /* A full diagonal road tile has two road bits. */ + c->infrastructure.road[tram_rt] += (bridge_len + 2) * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; } } - Owner owner_road = HasBit(prev_roadtypes, ROADTYPE_ROAD) ? GetRoadOwner(tile_start, ROADTYPE_ROAD) : company; - Owner owner_tram = HasBit(prev_roadtypes, ROADTYPE_TRAM) ? GetRoadOwner(tile_start, ROADTYPE_TRAM) : company; - MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir, roadtypes); - MakeRoadBridgeRamp(tile_end, owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), roadtypes); + Owner owner_road = hasroad ? GetRoadOwner(tile_start, RTT_ROAD) : company; + Owner owner_tram = hastram ? GetRoadOwner(tile_start, RTT_TRAM) : company; + MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir, road_rt, tram_rt); + MakeRoadBridgeRamp(tile_end, owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), road_rt, tram_rt); break; } case TRANSPORT_WATER: - if (is_new_owner && c != NULL) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; + if (is_new_owner && c != nullptr) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; MakeAqueductBridgeRamp(tile_start, owner, dir); MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir)); + CheckForDockingTile(tile_start); + CheckForDockingTile(tile_end); break; default: @@ -534,16 +558,24 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated */ Company *c = Company::GetIfValid(company); - if (!(flags & DC_QUERY_COST) || (c != NULL && c->is_ai)) { + if (!(flags & DC_QUERY_COST) || (c != nullptr && c->is_ai)) { bridge_len += 2; // begin and end tiles/ramps switch (transport_type) { - case TRANSPORT_ROAD: cost.AddCost(bridge_len * _price[PR_BUILD_ROAD] * 2 * CountBits(roadtypes)); break; + case TRANSPORT_ROAD: + if (road_rt != INVALID_ROADTYPE) { + cost.AddCost(bridge_len * 2 * RoadBuildCost(road_rt)); + } + if (tram_rt != INVALID_ROADTYPE) { + cost.AddCost(bridge_len * 2 * RoadBuildCost(tram_rt)); + } + break; + case TRANSPORT_RAIL: cost.AddCost(bridge_len * RailBuildCost(railtype)); break; default: break; } - if (c != NULL) bridge_len = CalcBridgeLenCostFactor(bridge_len); + if (c != nullptr) bridge_len = CalcBridgeLenCostFactor(bridge_len); if (transport_type != TRANSPORT_WATER) { cost.AddCost((int64)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8); @@ -562,7 +594,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u * Build Tunnel. * @param start_tile start tile of tunnel * @param flags type of operation - * @param p1 bit 0-5 railtype or roadtypes + * @param p1 bit 0-5 railtype or roadtype * bit 8-9 transport type * @param p2 unused * @param text unused @@ -573,9 +605,8 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, CompanyID company = _current_company; TransportType transport_type = Extract(p1); - RailType railtype = INVALID_RAILTYPE; - RoadTypes rts = ROADTYPES_NONE; + RoadType roadtype = INVALID_ROADTYPE; _build_tunnel_endtile = 0; switch (transport_type) { case TRANSPORT_RAIL: @@ -584,8 +615,8 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, break; case TRANSPORT_ROAD: - rts = Extract(p1); - if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(company, rts)) return CMD_ERROR; + roadtype = Extract(p1); + if (!ValParamRoadType(roadtype)) return CMD_ERROR; break; default: return CMD_ERROR; @@ -598,7 +629,7 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, company = OWNER_TOWN; /* If we are not within a town, we are not owned by the town */ - if (town == NULL || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { + if (town == nullptr || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { company = OWNER_NONE; } } @@ -680,10 +711,9 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, /* Mark the tile as already cleared for the terraform command. * Do this for all tiles (like trees), not only objects. */ ClearedObjectArea *coa = FindClearedObject(end_tile); - if (coa == NULL) { - coa = _cleared_object_areas.Append(); - coa->first_tile = end_tile; - coa->area = TileArea(end_tile, 1, 1); + if (coa == nullptr) { + /*C++17: coa = &*/ _cleared_object_areas.push_back({end_tile, TileArea(end_tile, 1, 1)}); + coa = &_cleared_object_areas.back(); } /* Hide the tile from the terraforming command */ @@ -699,10 +729,11 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, * Deliberately clear the coa pointer to avoid leaving dangling pointers which could * inadvertently be dereferenced. */ - assert(coa >= _cleared_object_areas.Begin() && coa < _cleared_object_areas.End()); - size_t coa_index = coa - _cleared_object_areas.Begin(); + ClearedObjectArea *begin = _cleared_object_areas.data(); + assert(coa >= begin && coa < begin + _cleared_object_areas.size()); + size_t coa_index = coa - begin; assert(coa_index < UINT_MAX); // more than 2**32 cleared areas would be a bug in itself - coa = NULL; + coa = nullptr; ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND); _cleared_object_areas[(uint)coa_index].first_tile = old_first_tile; @@ -713,7 +744,7 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, /* Pay for the rail/road in the tunnel including entrances */ switch (transport_type) { - case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * _price[PR_BUILD_ROAD] * 2); break; + case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * RoadBuildCost(roadtype) * 2); break; case TRANSPORT_RAIL: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break; default: NOT_REACHED(); } @@ -722,20 +753,17 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, Company *c = Company::GetIfValid(company); uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; if (transport_type == TRANSPORT_RAIL) { - if (!IsTunnelTile(start_tile) && c != NULL) c->infrastructure.rail[railtype] += num_pieces; + if (c != nullptr) c->infrastructure.rail[railtype] += num_pieces; MakeRailTunnel(start_tile, company, direction, railtype); MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype); AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company); YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction)); } else { - if (c != NULL) { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, rts ^ (IsTunnelTile(start_tile) ? GetRoadTypes(start_tile) : ROADTYPES_NONE)) { - c->infrastructure.road[rt] += num_pieces * 2; // A full diagonal road has two road bits. - } - } - MakeRoadTunnel(start_tile, company, direction, rts); - MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), rts); + if (c != nullptr) c->infrastructure.road[roadtype] += num_pieces * 2; // A full diagonal road has two road bits. + RoadType road_rt = RoadTypeIsRoad(roadtype) ? roadtype : INVALID_ROADTYPE; + RoadType tram_rt = RoadTypeIsTram(roadtype) ? roadtype : INVALID_ROADTYPE; + MakeRoadTunnel(start_tile, company, direction, road_rt, tram_rt); + MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), road_rt, tram_rt); } DirtyCompanyInfrastructureWindows(company); } @@ -756,12 +784,13 @@ static inline CommandCost CheckAllowRemoveTunnelBridge(TileIndex tile) switch (GetTunnelBridgeTransportType(tile)) { case TRANSPORT_ROAD: { - RoadTypes rts = GetRoadTypes(tile); + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); Owner road_owner = _current_company; Owner tram_owner = _current_company; - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + if (road_rt != INVALID_ROADTYPE) road_owner = GetRoadOwner(tile, RTT_ROAD); + if (tram_rt != INVALID_ROADTYPE) tram_owner = GetRoadOwner(tile, RTT_TRAM); /* We can remove unowned road and if the town allows it */ if (road_owner == OWNER_TOWN && _current_company != OWNER_TOWN && !(_settings_game.construction.extra_dynamite || _cheats.magic_bulldozer.value)) { @@ -808,7 +837,7 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) _build_tunnel_endtile = endtile; - Town *t = NULL; + Town *t = nullptr; if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating @@ -833,10 +862,10 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) Track track = DiagDirToDiagTrack(dir); Owner owner = GetTileOwner(tile); - Train *v = NULL; + Train *v = nullptr; if (HasTunnelBridgeReservation(tile)) { v = GetTrainForReservation(tile, track); - if (v != NULL) FreeTrainTrackReservation(v); + if (v != nullptr) FreeTrainTrackReservation(v); } if (Company::IsValidID(owner)) { @@ -854,17 +883,11 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); - if (v != NULL) TryPathReserve(v); + if (v != nullptr) TryPathReserve(v); } else { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - /* A full diagonal road tile has two road bits. */ - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; - DirtyCompanyInfrastructureWindows(c->index); - } - } + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); + UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); DoClearSquare(tile); DoClearSquare(endtile); @@ -893,7 +916,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) DiagDirection direction = GetTunnelBridgeDirection(tile); TileIndexDiff delta = TileOffsByDiagDir(direction); - Town *t = NULL; + Town *t = nullptr; if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating @@ -917,33 +940,35 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL; Owner owner = GetTileOwner(tile); int height = GetBridgeHeight(tile); - Train *v = NULL; + Train *v = nullptr; if (rail && HasTunnelBridgeReservation(tile)) { v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction)); - if (v != NULL) FreeTrainTrackReservation(v); + if (v != nullptr) FreeTrainTrackReservation(v); } + bool removetile = false; + bool removeendtile = false; + /* Update company infrastructure counts. */ if (rail) { if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; } else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) { - RoadType rt; - FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { - Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); - if (c != NULL) { - /* A full diagonal road tile has two road bits. */ - c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; - DirtyCompanyInfrastructureWindows(c->index); - } - } + /* A full diagonal road tile has two road bits. */ + UpdateCompanyRoadInfrastructure(GetRoadTypeRoad(tile), GetRoadOwner(tile, RTT_ROAD), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); + UpdateCompanyRoadInfrastructure(GetRoadTypeTram(tile), GetRoadOwner(tile, RTT_TRAM), -(int)(len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR)); } else { // Aqueduct if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; + removetile = IsDockingTile(tile); + removeendtile = IsDockingTile(endtile); } DirtyCompanyInfrastructureWindows(owner); DoClearSquare(tile); DoClearSquare(endtile); + + if (removetile) RemoveDockingTile(tile); + if (removeendtile) RemoveDockingTile(endtile); for (TileIndex c = tile + delta; c != endtile; c += delta) { /* do not let trees appear from 'nowhere' after removing bridge */ if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) { @@ -963,7 +988,7 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); - if (v != NULL) TryPathReserve(v, true); + if (v != nullptr) TryPathReserve(v, true); } } @@ -1018,7 +1043,7 @@ static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, in { int cur_z; for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) { - DrawPillar(psid, x, y, cur_z, w, h, NULL); + DrawPillar(psid, x, y, cur_z, w, h, nullptr); } return cur_z; } @@ -1082,19 +1107,90 @@ static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis } /** - * Draws the trambits over an already drawn (lower end) of a bridge. - * @param x the x of the bridge - * @param y the y of the bridge - * @param z the z of the bridge - * @param offset number representing whether to level or sloped and the direction - * @param overlay do we want to still see the road? - * @param head are we drawing bridge head? + * Draws the road and trambits over an already drawn (lower end) of a bridge. + * @param head_tile bridge head tile with roadtype information + * @param x the x of the bridge + * @param y the y of the bridge + * @param z the z of the bridge + * @param offset sprite offset identifying flat to sloped bridge tiles + * @param head are we drawing bridge head? */ -static void DrawBridgeTramBits(int x, int y, int z, int offset, bool overlay, bool head) +static void DrawBridgeRoadBits(TileIndex head_tile, int x, int y, int z, int offset, bool head) { - static const SpriteID tram_offsets[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } }; - static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 }; - static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 }; + RoadType road_rt = GetRoadTypeRoad(head_tile); + RoadType tram_rt = GetRoadTypeTram(head_tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + + SpriteID seq_back[4] = { 0 }; + bool trans_back[4] = { false }; + SpriteID seq_front[4] = { 0 }; + bool trans_front[4] = { false }; + + static const SpriteID overlay_offsets[6] = { 0, 1, 11, 12, 13, 14 }; + static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 }; + static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 }; + + if (head || !IsInvisibilitySet(TO_BRIDGES)) { + /* Road underlay takes precedence over tram */ + trans_back[0] = !head && IsTransparencySet(TO_BRIDGES); + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + seq_back[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset; + } + } else if (tram_rti != nullptr) { + if (tram_rti->UsesOverlay()) { + seq_back[0] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_BRIDGE, head ? TCX_NORMAL : TCX_ON_BRIDGE) + offset; + } else { + seq_back[0] = SPR_TRAMWAY_BRIDGE + offset; + } + } + + /* Draw road overlay */ + trans_back[1] = !head && IsTransparencySet(TO_BRIDGES); + if (road_rti != nullptr) { + if (road_rti->UsesOverlay()) { + seq_back[1] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[1] != 0) seq_back[1] += overlay_offsets[offset]; + } + } + + /* Draw tram overlay */ + trans_back[2] = !head && IsTransparencySet(TO_BRIDGES); + if (tram_rti != nullptr) { + if (tram_rti->UsesOverlay()) { + seq_back[2] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_OVERLAY, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[2] != 0) seq_back[2] += overlay_offsets[offset]; + } else if (road_rti != nullptr) { + seq_back[2] = SPR_TRAMWAY_OVERLAY + overlay_offsets[offset]; + } + } + + /* Road catenary takes precedence over tram */ + trans_back[3] = IsTransparencySet(TO_CATENARY); + trans_front[0] = IsTransparencySet(TO_CATENARY); + if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) { + seq_back[3] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_CATENARY_BACK, head ? TCX_NORMAL : TCX_ON_BRIDGE); + seq_front[0] = GetCustomRoadSprite(road_rti, head_tile, ROTSG_CATENARY_FRONT, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[3] == 0 || seq_front[0] == 0) { + seq_back[3] = SPR_TRAMWAY_BASE + back_offsets[offset]; + seq_front[0] = SPR_TRAMWAY_BASE + front_offsets[offset]; + } else { + seq_back[3] += 23 + offset; + seq_front[0] += 23 + offset; + } + } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) { + seq_back[3] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_CATENARY_BACK, head ? TCX_NORMAL : TCX_ON_BRIDGE); + seq_front[0] = GetCustomRoadSprite(tram_rti, head_tile, ROTSG_CATENARY_FRONT, head ? TCX_NORMAL : TCX_ON_BRIDGE); + if (seq_back[3] == 0 || seq_front[0] == 0) { + seq_back[3] = SPR_TRAMWAY_BASE + back_offsets[offset]; + seq_front[0] = SPR_TRAMWAY_BASE + front_offsets[offset]; + } else { + seq_back[3] += 23 + offset; + seq_front[0] += 23 + offset; + } + } + } static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 }; static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 }; @@ -1103,28 +1199,25 @@ static void DrawBridgeTramBits(int x, int y, int z, int offset, bool overlay, bo /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called * The bounding boxes here are the same as for bridge front/roof */ - if (head || !IsInvisibilitySet(TO_BRIDGES)) { - AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE, - x, y, size_x[offset], size_y[offset], 0x28, z, - !head && IsTransparencySet(TO_BRIDGES)); - } - - /* Do not draw catenary if it is set invisible */ - if (!IsInvisibilitySet(TO_CATENARY)) { - AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + back_offsets[offset], PAL_NONE, - x, y, size_x[offset], size_y[offset], 0x28, z, - IsTransparencySet(TO_CATENARY)); + for (uint i = 0; i < lengthof(seq_back); ++i) { + if (seq_back[i] != 0) { + AddSortableSpriteToDraw(seq_back[i], PAL_NONE, + x, y, size_x[offset], size_y[offset], 0x28, z, + trans_back[i]); + } } /* Start a new SpriteCombine for the front part */ EndSpriteCombine(); StartSpriteCombine(); - /* For sloped sprites the bounding box needs to be higher, as the pylons stop on a higher point */ - if (!IsInvisibilitySet(TO_CATENARY)) { - AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + front_offsets[offset], PAL_NONE, - x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, - IsTransparencySet(TO_CATENARY), front_bb_offset_x[offset], front_bb_offset_y[offset]); + for (uint i = 0; i < lengthof(seq_front); ++i) { + if (seq_front[i] != 0) { + AddSortableSpriteToDraw(seq_front[i], PAL_NONE, + x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, + trans_front[i], + front_bb_offset_x[offset], front_bb_offset_y[offset]); + } } } @@ -1188,19 +1281,36 @@ static void DrawTile_TunnelBridge(TileInfo *ti) DrawGroundSprite(image, PAL_NONE); if (transport_type == TRANSPORT_ROAD) { - RoadTypes rts = GetRoadTypes(ti->tile); + RoadType road_rt = GetRoadTypeRoad(ti->tile); + RoadType tram_rt = GetRoadTypeTram(ti->tile); + const RoadTypeInfo *road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt); + const RoadTypeInfo *tram_rti = tram_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(tram_rt); + uint sprite_offset = DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? 1 : 0; - if (HasBit(rts, ROADTYPE_TRAM)) { - static const SpriteID tunnel_sprites[2][4] = { { 28, 78, 79, 27 }, { 5, 76, 77, 4 } }; + DrawRoadOverlays(ti, PAL_NONE, road_rti, tram_rti, sprite_offset, sprite_offset); - DrawGroundSprite(SPR_TRAMWAY_BASE + tunnel_sprites[rts - ROADTYPES_TRAM][tunnelbridge_direction], PAL_NONE); - - /* Do not draw wires if they are invisible */ - if (!IsInvisibilitySet(TO_CATENARY)) { - catenary = true; - StartSpriteCombine(); - AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR); + /* Road catenary takes precedence over tram */ + SpriteID catenary_sprite_base = 0; + if (road_rti != nullptr && HasRoadCatenaryDrawn(road_rt)) { + catenary_sprite_base = GetCustomRoadSprite(road_rti, ti->tile, ROTSG_CATENARY_FRONT); + if (catenary_sprite_base == 0) { + catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES; + } else { + catenary_sprite_base += 19; } + } else if (tram_rti != nullptr && HasRoadCatenaryDrawn(tram_rt)) { + catenary_sprite_base = GetCustomRoadSprite(tram_rti, ti->tile, ROTSG_CATENARY_FRONT); + if (catenary_sprite_base == 0) { + catenary_sprite_base = SPR_TRAMWAY_TUNNEL_WIRES; + } else { + catenary_sprite_base += 19; + } + } + + if (catenary_sprite_base != 0) { + catenary = true; + StartSpriteCombine(); + AddSortableSpriteToDraw(catenary_sprite_base + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR); } } else { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); @@ -1294,20 +1404,18 @@ static void DrawTile_TunnelBridge(TileInfo *ti) AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z); if (transport_type == TRANSPORT_ROAD) { - RoadTypes rts = GetRoadTypes(ti->tile); - - if (HasBit(rts, ROADTYPE_TRAM)) { - uint offset = tunnelbridge_direction; - int z = ti->z; - if (ti->tileh != SLOPE_FLAT) { - offset = (offset + 1) & 1; - z += TILE_HEIGHT; - } else { - offset += 2; - } - /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */ - DrawBridgeTramBits(ti->x, ti->y, z, offset, HasBit(rts, ROADTYPE_ROAD), true); + uint offset = tunnelbridge_direction; + int z = ti->z; + if (ti->tileh != SLOPE_FLAT) { + offset = (offset + 1) & 1; + z += TILE_HEIGHT; + } else { + offset += 2; } + + /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */ + DrawBridgeRoadBits(ti->tile, ti->x, ti->y, z, offset, true); + EndSpriteCombine(); } else if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); @@ -1465,15 +1573,8 @@ void DrawBridgeMiddle(const TileInfo *ti) psid++; if (transport_type == TRANSPORT_ROAD) { - RoadTypes rts = GetRoadTypes(rampsouth); - - if (HasBit(rts, ROADTYPE_TRAM)) { - /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */ - DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HasBit(rts, ROADTYPE_ROAD), false); - } else { - EndSpriteCombine(); - StartSpriteCombine(); - } + /* DrawBridgeRoadBits() calls EndSpriteCombine() and StartSpriteCombine() */ + DrawBridgeRoadBits(rampsouth, x, y, bridge_z, axis ^ 1, false); } else if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth)); if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) { @@ -1593,9 +1694,20 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td) Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; - RoadTypes rts = GetRoadTypes(tile); - if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); - if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } /* Is there a mix of owners? */ if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || @@ -1624,7 +1736,9 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td) } } } else if (tt == TRANSPORT_ROAD && !IsTunnel(tile)) { - td->road_speed = GetBridgeSpec(GetBridgeType(tile))->speed; + uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed; + if (road_rt != INVALID_ROADTYPE && (td->road_speed == 0 || spd < td->road_speed)) td->road_speed = spd; + if (tram_rt != INVALID_ROADTYPE && (td->tram_speed == 0 || spd < td->tram_speed)) td->tram_speed = spd; } } @@ -1660,7 +1774,7 @@ static void TileLoop_TunnelBridge(TileIndex tile) static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { TransportType transport_type = GetTunnelBridgeTransportType(tile); - if (transport_type != mode || (transport_type == TRANSPORT_ROAD && (GetRoadTypes(tile) & sub_mode) == 0)) return 0; + if (transport_type != mode || (transport_type == TRANSPORT_ROAD && !HasTileRoadType(tile, (RoadTramType)sub_mode))) return 0; DiagDirection dir = GetTunnelBridgeDirection(tile); if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0; @@ -1674,17 +1788,18 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner * don't want to update the infrastructure counts twice. */ uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0; - for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { + FOR_ALL_ROADTRAMTYPES(rtt) { /* Update all roadtypes, no matter if they are present */ - if (GetRoadOwner(tile, rt) == old_owner) { - if (HasBit(GetRoadTypes(tile), rt)) { + if (GetRoadOwner(tile, rtt) == old_owner) { + RoadType rt = GetRoadType(tile, rtt); + if (rt != INVALID_ROADTYPE) { /* Update company infrastructure counts. A full diagonal road tile has two road bits. * No need to dirty windows here, we'll redraw the whole screen anyway. */ Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2; } - SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); + SetRoadOwner(tile, rtt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } @@ -1906,14 +2021,14 @@ extern const TileTypeProcs _tile_type_tunnelbridge_procs = { DrawTile_TunnelBridge, // draw_tile_proc GetSlopePixelZ_TunnelBridge, // get_slope_z_proc ClearTile_TunnelBridge, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_TunnelBridge, // get_tile_desc_proc GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc - NULL, // click_tile_proc - NULL, // animate_tile_proc + nullptr, // click_tile_proc + nullptr, // animate_tile_proc TileLoop_TunnelBridge, // tile_loop_proc ChangeTileOwner_TunnelBridge, // change_tile_owner_proc - NULL, // add_produced_cargo_proc + nullptr, // add_produced_cargo_proc VehicleEnter_TunnelBridge, // vehicle_enter_tile_proc GetFoundation_TunnelBridge, // get_foundation_proc TerraformTile_TunnelBridge, // terraform_tile_proc diff --git a/src/vehicle.cpp b/src/vehicle.cpp index f4dc0c4ddb..0bb4ed178d 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -163,7 +163,7 @@ bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const */ void VehicleServiceInDepot(Vehicle *v) { - assert(v != NULL); + assert(v != nullptr); SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated do { @@ -173,7 +173,7 @@ void VehicleServiceInDepot(Vehicle *v) /* Prevent vehicles from breaking down directly after exiting the depot. */ v->breakdown_chance /= 4; v = v->Next(); - } while (v != NULL && v->HasEngineType()); + } while (v != nullptr && v->HasEngineType()); } /** @@ -210,7 +210,7 @@ bool Vehicle::NeedsServicing() const Money needed_money = c->settings.engine_renew_money; if (needed_money > c->money) return false; - for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) { + for (const Vehicle *v = this; v != nullptr; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : nullptr) { bool replace_when_old = false; EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old); @@ -261,13 +261,13 @@ bool Vehicle::NeedsAutomaticServicing() const uint Vehicle::Crash(bool flooded) { assert((this->vehstatus & VS_CRASHED) == 0); - assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains + assert(this->Previous() == nullptr); // IsPrimaryVehicle fails for free-wagon-chains uint pass = 0; /* Stop the vehicle. */ if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED; /* crash all wagons, and count passengers */ - for (Vehicle *v = this; v != NULL; v = v->Next()) { + for (Vehicle *v = this; v != nullptr; v = v->Next()) { /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */ if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount(); v->vehstatus |= VS_CRASHED; @@ -281,7 +281,7 @@ uint Vehicle::Crash(bool flooded) SetWindowDirty(WC_VEHICLE_DEPOT, this->tile); delete this->cargo_payment; - assert(this->cargo_payment == NULL); // cleared by ~CargoPayment + assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment return RandomRange(pass + 1); // Randomise deceased passengers. } @@ -301,7 +301,7 @@ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRF GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID()); /* Missing GRF. Nothing useful can be done in this situation. */ - if (grfconfig == NULL) return; + if (grfconfig == nullptr) return; if (!HasBit(grfconfig->grf_bugs, bug_type)) { SetBit(grfconfig->grf_bugs, bug_type); @@ -384,16 +384,16 @@ static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) { for (int x = xl; ; x = (x + 1) & HASH_MASK) { Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; - for (; v != NULL; v = v->hash_tile_next) { + for (; v != nullptr; v = v->hash_tile_next) { Vehicle *a = proc(v, data); - if (find_first && a != NULL) return a; + if (find_first && a != nullptr) return a; } if (x == xu) break; } if (y == yu) break; } - return NULL; + return nullptr; } @@ -442,18 +442,18 @@ void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) /** * Checks whether a vehicle in on a specific location. It will call proc for - * vehicles until it returns non-NULL. + * vehicles until it returns non-nullptr. * @note Use FindVehicleOnPosXY when you have the intention that all vehicles * should be iterated over. * @param x The X location on the map * @param y The Y location on the map * @param data Arbitrary data passed to proc * @param proc The proc that determines whether a vehicle will be "found". - * @return True if proc returned non-NULL. + * @return True if proc returned non-nullptr. */ bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) { - return VehicleFromPosXY(x, y, data, proc, true) != NULL; + return VehicleFromPosXY(x, y, data, proc, true) != nullptr; } /** @@ -472,14 +472,14 @@ static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *p int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS; Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; - for (; v != NULL; v = v->hash_tile_next) { + for (; v != nullptr; v = v->hash_tile_next) { if (v->tile != tile) continue; Vehicle *a = proc(v, data); - if (find_first && a != NULL) return a; + if (find_first && a != nullptr) return a; } - return NULL; + return nullptr; } /** @@ -502,31 +502,31 @@ void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) /** * Checks whether a vehicle is on a specific location. It will call \a proc for - * vehicles until it returns non-NULL. + * vehicles until it returns non-nullptr. * @note Use #FindVehicleOnPos when you have the intention that all vehicles * should be iterated over. * @param tile The location on the map * @param data Arbitrary data passed to \a proc. * @param proc The \a proc that determines whether a vehicle will be "found". - * @return True if proc returned non-NULL. + * @return True if proc returned non-nullptr. */ bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) { - return VehicleFromPos(tile, data, proc, true) != NULL; + return VehicleFromPos(tile, data, proc, true) != nullptr; } /** * Callback that returns 'real' vehicles lower or at height \c *(int*)data . * @param v Vehicle to examine. * @param data Pointer to height data. - * @return \a v if conditions are met, else \c NULL. + * @return \a v if conditions are met, else \c nullptr. */ static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data) { int z = *(int*)data; - if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL; - if (v->z_pos > z) return NULL; + if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return nullptr; + if (v->z_pos > z) return nullptr; return v; } @@ -545,15 +545,15 @@ CommandCost EnsureNoVehicleOnGround(TileIndex tile) * Such a message does not affect MP synchronisation. */ Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true); - if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); + if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } /** Procedure called for every vehicle found in tunnel/bridge in the hash map */ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data) { - if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL; - if (v == (const Vehicle *)data) return NULL; + if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return nullptr; + if (v == (const Vehicle *)data) return nullptr; return v; } @@ -572,9 +572,9 @@ CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle * Such a message does not affect MP synchronisation. */ Vehicle *v = VehicleFromPos(tile, const_cast(ignore), &GetVehicleTunnelBridgeProc, true); - if (v == NULL) v = VehicleFromPos(endtile, const_cast(ignore), &GetVehicleTunnelBridgeProc, true); + if (v == nullptr) v = VehicleFromPos(endtile, const_cast(ignore), &GetVehicleTunnelBridgeProc, true); - if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); + if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } @@ -582,10 +582,10 @@ static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data) { TrackBits rail_bits = *(TrackBits *)data; - if (v->type != VEH_TRAIN) return NULL; + if (v->type != VEH_TRAIN) return nullptr; Train *t = Train::From(v); - if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL; + if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return nullptr; return v; } @@ -605,7 +605,7 @@ CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits) * Such a message does not affect MP synchronisation. */ Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true); - if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); + if (v != nullptr) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } @@ -615,7 +615,7 @@ static void UpdateVehicleTileHash(Vehicle *v, bool remove) Vehicle **new_hash; if (remove) { - new_hash = NULL; + new_hash = nullptr; } else { int x = GB(TileX(v->tile), HASH_RES, HASH_BITS); int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS; @@ -625,15 +625,15 @@ static void UpdateVehicleTileHash(Vehicle *v, bool remove) if (old_hash == new_hash) return; /* Remove from the old position in the hash table */ - if (old_hash != NULL) { - if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = v->hash_tile_prev; + if (old_hash != nullptr) { + if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = v->hash_tile_prev; *v->hash_tile_prev = v->hash_tile_next; } /* Insert vehicle at beginning of the new position in the hash table */ - if (new_hash != NULL) { + if (new_hash != nullptr) { v->hash_tile_next = *new_hash; - if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next; + if (v->hash_tile_next != nullptr) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next; v->hash_tile_prev = new_hash; *new_hash = v; } @@ -650,21 +650,21 @@ static void UpdateVehicleViewportHash(Vehicle *v, int x, int y) int old_x = v->coord.left; int old_y = v->coord.top; - new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)]; - old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)]; + new_hash = (x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GEN_HASH(x, y)]; + old_hash = (old_x == INVALID_COORD) ? nullptr : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)]; if (old_hash == new_hash) return; /* remove from hash table? */ - if (old_hash != NULL) { - if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev; + if (old_hash != nullptr) { + if (v->hash_viewport_next != nullptr) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev; *v->hash_viewport_prev = v->hash_viewport_next; } /* insert into hash table? */ - if (new_hash != NULL) { + if (new_hash != nullptr) { v->hash_viewport_next = *new_hash; - if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next; + if (v->hash_viewport_next != nullptr) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next; v->hash_viewport_prev = new_hash; *new_hash = v; } @@ -673,7 +673,7 @@ static void UpdateVehicleViewportHash(Vehicle *v, int x, int y) void ResetVehicleHash() { Vehicle *v; - FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; } + FOR_ALL_VEHICLES(v) { v->hash_tile_current = nullptr; } memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash)); memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash)); } @@ -688,19 +688,20 @@ void ResetVehicleColourMap() * List of vehicles that should check for autoreplace this tick. * Mapping of vehicle -> leave depot immediately after autoreplace. */ -typedef SmallMap AutoreplaceMap; +typedef SmallMap AutoreplaceMap; static AutoreplaceMap _vehicles_to_autoreplace; void InitializeVehicles() { - _vehicles_to_autoreplace.Reset(); + _vehicles_to_autoreplace.clear(); + _vehicles_to_autoreplace.shrink_to_fit(); ResetVehicleHash(); } uint CountVehiclesInChain(const Vehicle *v) { uint count = 0; - do count++; while ((v = v->Next()) != NULL); + do count++; while ((v = v->Next()) != nullptr); return count; } @@ -811,7 +812,7 @@ void Vehicle::PreDestructor() HideFillingPercent(&this->fill_percent_te_id); this->CancelReservation(INVALID_STATION, st); delete this->cargo_payment; - assert(this->cargo_payment == NULL); // cleared by ~CargoPayment + assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment } if (this->IsEngineCountable()) { @@ -826,7 +827,7 @@ void Vehicle::PreDestructor() if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) { Aircraft *a = Aircraft::From(this); Station *st = GetTargetAirportIfValid(a); - if (st != NULL) { + if (st != nullptr) { const AirportFTA *layout = st->airport.GetFTA()->layout; CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block); } @@ -841,7 +842,7 @@ void Vehicle::PreDestructor() } } - if (this->Previous() == NULL) { + if (this->Previous() == nullptr) { InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile); } @@ -878,7 +879,7 @@ Vehicle::~Vehicle() if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty(); Vehicle *v = this->Next(); - this->SetNext(NULL); + this->SetNext(nullptr); delete v; @@ -917,7 +918,7 @@ static void RunVehicleDayProc() /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */ for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) { Vehicle *v = Vehicle::Get(i); - if (v == NULL) continue; + if (v == nullptr) continue; /* Call the 32-day callback if needed */ if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) { @@ -942,7 +943,7 @@ static void RunVehicleDayProc() void CallVehicleTicks() { - _vehicles_to_autoreplace.Clear(); + _vehicles_to_autoreplace.clear(); RunVehicleDayProc(); @@ -960,7 +961,7 @@ void CallVehicleTicks() FOR_ALL_VEHICLES(v) { /* Vehicle could be deleted in this tick */ if (!v->Tick()) { - assert(Vehicle::Get(vehicle_index) == NULL); + assert(Vehicle::Get(vehicle_index) == nullptr); continue; } @@ -1026,16 +1027,16 @@ void CallVehicleTicks() } } - Backup cur_company(_current_company, FILE_LINE); - for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) { - v = it->first; + Backup cur_company(_current_company, FILE_LINE); + for (auto &it : _vehicles_to_autoreplace) { + v = it.first; /* Autoreplace needs the current company set as the vehicle owner */ cur_company.Change(v->owner); /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick() * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that * they are already leaving the depot again before being replaced. */ - if (it->second) v->vehstatus &= ~VS_STOPPED; + if (it.second) v->vehstatus &= ~VS_STOPPED; /* Store the position of the effect as the vehicle pointer will become invalid later */ int x = v->x_pos; @@ -1141,7 +1142,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi) for (int x = xl;; x = (x + GEN_HASHX_INC) & GEN_HASHX_MASK) { const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF - while (v != NULL) { + while (v != nullptr) { if (!(v->vehstatus & VS_HIDDEN) && l <= v->coord.right && t <= v->coord.bottom && @@ -1164,14 +1165,14 @@ void ViewportAddVehicles(DrawPixelInfo *dpi) * @param vp Viewport clicked in. * @param x X coordinate in the viewport. * @param y Y coordinate in the viewport. - * @return Closest vehicle, or \c NULL if none found. + * @return Closest vehicle, or \c nullptr if none found. */ Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y) { - Vehicle *found = NULL, *v; + Vehicle *found = nullptr, *v; uint dist, best_dist = UINT_MAX; - if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL; + if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return nullptr; x = ScaleByZoom(x, vp->zoom) + vp->virtual_left; y = ScaleByZoom(y, vp->zoom) + vp->virtual_top; @@ -1295,7 +1296,7 @@ bool Vehicle::HandleBreakdown() if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) { EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE); - if (u != NULL) u->animation_state = this->breakdown_delay * 2; + if (u != nullptr) u->animation_state = this->breakdown_delay * 2; } } @@ -1346,10 +1347,13 @@ void AgeVehicle(Vehicle *v) SetWindowDirty(WC_VEHICLE_DETAILS, v->index); /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */ - if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return; + if (v->Previous() != nullptr || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return; + const Company *c = Company::Get(v->owner); /* Don't warn if a renew is active */ - if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return; + if (c->settings.engine_renew && v->GetEngine()->company_avail != 0) return; + /* Don't warn if a replacement is active */ + if (EngineHasReplacementForCompany(c, v->engine_type, v->group_id)) return; StringID str; if (age == -DAYS_IN_LEAP_YEAR) { @@ -1385,18 +1389,18 @@ uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour) bool is_loading = front->current_order.IsType(OT_LOADING); - /* The station may be NULL when the (colour) string does not need to be set. */ + /* The station may be nullptr when the (colour) string does not need to be set. */ const Station *st = Station::GetIfValid(front->last_station_visited); - assert(colour == NULL || (st != NULL && is_loading)); + assert(colour == nullptr || (st != nullptr && is_loading)); bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD); bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD); /* Count up max and used */ - for (const Vehicle *v = front; v != NULL; v = v->Next()) { + for (const Vehicle *v = front; v != nullptr; v = v->Next()) { count += v->cargo.StoredCount(); max += v->cargo_cap; - if (v->cargo_cap != 0 && colour != NULL) { + if (v->cargo_cap != 0 && colour != nullptr) { unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0; loading |= !order_no_load && (order_full_load || st->goods[v->cargo_type].HasRating()) && @@ -1405,7 +1409,7 @@ uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour) } } - if (colour != NULL) { + if (colour != nullptr) { if (unloading == 0 && loading) { *colour = STR_PERCENT_UP; } else if (unloading == 0 && !loading) { @@ -1503,14 +1507,14 @@ void VehicleEnterDepot(Vehicle *v) /* Test whether we are heading for this depot. If not, do nothing. * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */ if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && - real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && + real_order != nullptr && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && (v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) { /* We are heading for another depot, keep driving. */ return; } if (v->current_order.IsRefit()) { - Backup cur_company(_current_company, v->owner, FILE_LINE); + Backup cur_company(_current_company, v->owner, FILE_LINE); CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v)); cur_company.Restore(); @@ -1684,7 +1688,7 @@ VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y * @param type type of vehicle * @param owner owner of vehicles */ -FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0) +FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(nullptr), maxid(0), curid(0) { /* Find maximum */ const Vehicle *v; @@ -1753,7 +1757,7 @@ UnitID GetFreeUnitNumber(VehicleType type) * @return true if there is any reason why you may build * the infrastructure for the given vehicle type */ -bool CanBuildVehicleInfrastructure(VehicleType type) +bool CanBuildVehicleInfrastructure(VehicleType type, byte subtype) { assert(IsCompanyBuildableVehicleType(type)); @@ -1766,7 +1770,10 @@ bool CanBuildVehicleInfrastructure(VehicleType type) if (!HasAnyRailtypesAvail(_local_company)) return false; max = _settings_game.vehicle.max_trains; break; - case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break; + case VEH_ROAD: + if (!HasAnyRoadTypesAvail(_local_company, (RoadTramType)subtype)) return false; + max = _settings_game.vehicle.max_roadveh; + break; case VEH_SHIP: max = _settings_game.vehicle.max_ships; break; case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break; default: NOT_REACHED(); @@ -1777,6 +1784,7 @@ bool CanBuildVehicleInfrastructure(VehicleType type) /* Can we actually build the vehicle type? */ const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, type) { + if (type == VEH_ROAD && GetRoadTramType(e->u.road.roadtype) != (RoadTramType)subtype) continue; if (HasBit(e->company_avail, _local_company)) return true; } return false; @@ -1785,6 +1793,7 @@ bool CanBuildVehicleInfrastructure(VehicleType type) /* We should be able to build infrastructure when we have the actual vehicle type */ const Vehicle *v; FOR_ALL_VEHICLES(v) { + if (type == VEH_ROAD && GetRoadTramType(RoadVehicle::From(v)->roadtype) != (RoadTramType)subtype) continue; if (v->owner == _local_company && v->type == type) return true; } @@ -1796,17 +1805,17 @@ bool CanBuildVehicleInfrastructure(VehicleType type) * Determines the #LiveryScheme for a vehicle. * @param engine_type Engine of the vehicle. * @param parent_engine_type Engine of the front vehicle, #INVALID_ENGINE if vehicle is at front itself. - * @param v the vehicle, \c NULL if in purchase list etc. + * @param v the vehicle, \c nullptr if in purchase list etc. * @return livery scheme to use. */ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v) { - CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type; + CargoID cargo_type = v == nullptr ? (CargoID)CT_INVALID : v->cargo_type; const Engine *e = Engine::Get(engine_type); switch (e->type) { default: NOT_REACHED(); case VEH_TRAIN: - if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) { + if (v != nullptr && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) { /* Wagonoverrides use the colour scheme of the front engine. * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */ engine_type = parent_engine_type; @@ -1849,7 +1858,7 @@ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_ case VEH_ROAD: /* Always use the livery of the front */ - if (v != NULL && parent_engine_type != INVALID_ENGINE) { + if (v != nullptr && parent_engine_type != INVALID_ENGINE) { engine_type = parent_engine_type; e = Engine::Get(engine_type); cargo_type = v->First()->cargo_type; @@ -1886,7 +1895,7 @@ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_ * @param engine_type EngineID of the vehicle * @param company Owner of the vehicle * @param parent_engine_type EngineID of the front vehicle. INVALID_VEHICLE if vehicle is at front itself. - * @param v the vehicle. NULL if in purchase list etc. + * @param v the vehicle. nullptr if in purchase list etc. * @param livery_setting The livery settings to use for acquiring the livery information. * @return livery to use */ @@ -1896,9 +1905,9 @@ const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID LiveryScheme scheme = LS_DEFAULT; if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) { - if (v != NULL) { + if (v != nullptr) { const Group *g = Group::GetIfValid(v->First()->group_id); - if (g != NULL) { + if (g != nullptr) { /* Traverse parents until we find a livery or reach the top */ while (g->livery.in_use == 0 && g->parent != INVALID_GROUP) { g = Group::Get(g->parent); @@ -1921,7 +1930,7 @@ const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v) { - PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE; + PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE; /* Return cached value if any */ if (map != PAL_NONE) return map; @@ -1939,7 +1948,7 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng * map else it's returned as-is. */ if (!HasBit(callback, 14)) { /* Update cache */ - if (v != NULL) const_cast(v)->colourmap = map; + if (v != nullptr) const_cast(v)->colourmap = map; return map; } } @@ -1958,7 +1967,7 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng if (twocc) map += livery->colour2 * 16; /* Update cache */ - if (v != NULL) const_cast(v)->colourmap = map; + if (v != nullptr) const_cast(v)->colourmap = map; return map; } @@ -1970,7 +1979,7 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng */ PaletteID GetEnginePalette(EngineID engine_type, CompanyID company) { - return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL); + return GetEngineColourMap(engine_type, company, INVALID_ENGINE, nullptr); } /** @@ -2004,7 +2013,7 @@ void Vehicle::DeleteUnreachedImplicitOrders() } const Order *order = this->GetOrder(this->cur_implicit_order_index); - while (order != NULL) { + while (order != nullptr) { if (this->cur_implicit_order_index == this->cur_real_order_index) break; if (order->IsType(OT_IMPLICIT)) { @@ -2018,7 +2027,7 @@ void Vehicle::DeleteUnreachedImplicitOrders() } /* Wrap around */ - if (order == NULL) { + if (order == nullptr) { order = this->GetOrder(0); this->cur_implicit_order_index = 0; } @@ -2055,12 +2064,12 @@ void Vehicle::BeginLoading() * the 'wrong' terminal when skipping orders etc. */ Order *in_list = this->GetOrder(this->cur_implicit_order_index); if (this->IsGroundVehicle() && - (in_list == NULL || !in_list->IsType(OT_IMPLICIT) || + (in_list == nullptr || !in_list->IsType(OT_IMPLICIT) || in_list->GetDestination() != this->last_station_visited)) { bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS); /* Do not create consecutive duplicates of implicit orders */ - Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL); - if (prev_order == NULL || + Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : nullptr); + if (prev_order == nullptr || (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) || prev_order->GetDestination() != this->last_station_visited) { @@ -2073,7 +2082,7 @@ void Vehicle::BeginLoading() bool found = false; while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) { const Order *order = this->GetOrder(target_index); - if (order == NULL) break; // No orders. + if (order == nullptr) break; // No orders. if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) { found = true; break; @@ -2109,15 +2118,15 @@ void Vehicle::BeginLoading() } /* Wrap around */ - if (order == NULL) { + if (order == nullptr) { order = this->GetOrder(0); this->cur_implicit_order_index = 0; } - assert(order != NULL); + assert(order != nullptr); } } } else if (!suppress_implicit_orders && - ((this->orders.list == NULL ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) && + ((this->orders.list == nullptr ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) && Order::CanAllocateItem()) { /* Insert new implicit order */ Order *implicit_order = new Order(); @@ -2161,7 +2170,7 @@ void Vehicle::BeginLoading() */ void Vehicle::CancelReservation(StationID next, Station *st) { - for (Vehicle *v = this; v != NULL; v = v->next) { + for (Vehicle *v = this; v != nullptr; v = v->next) { VehicleCargoList &cargo = v->cargo; if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { DEBUG(misc, 1, "cancelling cargo reservation"); @@ -2181,7 +2190,7 @@ void Vehicle::LeaveStation() assert(this->current_order.IsType(OT_LOADING)); delete this->cargo_payment; - assert(this->cargo_payment == NULL); // cleared by ~CargoPayment + assert(this->cargo_payment == nullptr); // cleared by ~CargoPayment /* Only update the timetable if the vehicle was supposed to stop here. */ if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false); @@ -2210,7 +2219,7 @@ void Vehicle::LeaveStation() st->loading_vehicles.remove(this); HideFillingPercent(&this->fill_percent_te_id); - trip_occupancy = CalcPercentVehicleFilled(this, NULL); + trip_occupancy = CalcPercentVehicleFilled(this, nullptr); if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) { /* Trigger station animation (trains only) */ @@ -2230,7 +2239,7 @@ void Vehicle::LeaveStation() */ void Vehicle::ResetRefitCaps() { - for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap; + for (Vehicle *v = this; v != nullptr; v = v->Next()) v->refit_cap = v->cargo_cap; } /** @@ -2253,7 +2262,7 @@ void Vehicle::HandleLoading(bool mode) /* Only advance to next order if we just loaded at the current one */ const Order *order = this->GetOrder(this->cur_implicit_order_index); - if (order == NULL || + if (order == nullptr || (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) || order->GetDestination() != this->last_station_visited) { return; @@ -2275,13 +2284,11 @@ void Vehicle::HandleLoading(bool mode) */ void Vehicle::GetConsistFreeCapacities(SmallMap &capacities) const { - for (const Vehicle *v = this; v != NULL; v = v->Next()) { + for (const Vehicle *v = this; v != nullptr; v = v->Next()) { if (v->cargo_cap == 0) continue; SmallPair *pair = capacities.Find(v->cargo_type); if (pair == capacities.End()) { - pair = capacities.Append(); - pair->first = v->cargo_type; - pair->second = v->cargo_cap - v->cargo.StoredCount(); + capacities.push_back({v->cargo_type, v->cargo_cap - v->cargo.StoredCount()}); } else { pair->second += v->cargo_cap - v->cargo.StoredCount(); } @@ -2291,7 +2298,7 @@ void Vehicle::GetConsistFreeCapacities(SmallMap &capacities) cons uint Vehicle::GetConsistTotalCapacity() const { uint result = 0; - for (const Vehicle *v = this; v != NULL; v = v->Next()) { + for (const Vehicle *v = this; v != nullptr; v = v->Next()) { result += v->cargo_cap; } return result; @@ -2325,7 +2332,7 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) return CommandCost(); } - if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders + if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancellation of depot orders if (flags & DC_EXEC) { /* If the orders to 'goto depot' are in the orders list (forced servicing), * then skip to the next order; effectively cancelling this forced service */ @@ -2648,34 +2655,34 @@ void Vehicle::ShowVisualEffect() const CreateEffectVehicleRel(v, x, y, 10, evt); } - } while ((v = v->Next()) != NULL); + } while ((v = v->Next()) != nullptr); if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT); } /** * Set the next vehicle of this vehicle. - * @param next the next vehicle. NULL removes the next vehicle. + * @param next the next vehicle. nullptr removes the next vehicle. */ void Vehicle::SetNext(Vehicle *next) { assert(this != next); - if (this->next != NULL) { + if (this->next != nullptr) { /* We had an old next vehicle. Update the first and previous pointers */ - for (Vehicle *v = this->next; v != NULL; v = v->Next()) { + for (Vehicle *v = this->next; v != nullptr; v = v->Next()) { v->first = this->next; } - this->next->previous = NULL; + this->next->previous = nullptr; } this->next = next; - if (this->next != NULL) { + if (this->next != nullptr) { /* A new next vehicle. Update the first and previous pointers */ - if (this->next->previous != NULL) this->next->previous->next = NULL; + if (this->next->previous != nullptr) this->next->previous->next = nullptr; this->next->previous = this; - for (Vehicle *v = this->next; v != NULL; v = v->Next()) { + for (Vehicle *v = this->next; v != nullptr; v = v->Next()) { v->first = this->first; } } @@ -2688,12 +2695,12 @@ void Vehicle::SetNext(Vehicle *next) */ void Vehicle::AddToShared(Vehicle *shared_chain) { - assert(this->previous_shared == NULL && this->next_shared == NULL); + assert(this->previous_shared == nullptr && this->next_shared == nullptr); - if (shared_chain->orders.list == NULL) { - assert(shared_chain->previous_shared == NULL); - assert(shared_chain->next_shared == NULL); - this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain); + if (shared_chain->orders.list == nullptr) { + assert(shared_chain->previous_shared == nullptr); + assert(shared_chain->next_shared == nullptr); + this->orders.list = shared_chain->orders.list = new OrderList(nullptr, shared_chain); } this->next_shared = shared_chain->next_shared; @@ -2701,7 +2708,7 @@ void Vehicle::AddToShared(Vehicle *shared_chain) shared_chain->next_shared = this; - if (this->next_shared != NULL) this->next_shared->previous_shared = this; + if (this->next_shared != nullptr) this->next_shared->previous_shared = this; shared_chain->orders.list->AddVehicle(this); } @@ -2723,7 +2730,7 @@ void Vehicle::RemoveFromShared() this->previous_shared->next_shared = this->NextShared(); } - if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared; + if (this->next_shared != nullptr) this->next_shared->previous_shared = this->previous_shared; if (this->orders.list->GetNumVehicles() == 1) { @@ -2736,8 +2743,8 @@ void Vehicle::RemoveFromShared() InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31)); } - this->next_shared = NULL; - this->previous_shared = NULL; + this->next_shared = nullptr; + this->previous_shared = nullptr; } void VehiclesYearlyLoop() @@ -2781,7 +2788,7 @@ void VehiclesYearlyLoop() bool CanVehicleUseStation(EngineID engine_type, const Station *st) { const Engine *e = Engine::GetIfValid(engine_type); - assert(e != NULL); + assert(e != nullptr); switch (e->type) { case VEH_TRAIN: @@ -2813,7 +2820,7 @@ bool CanVehicleUseStation(EngineID engine_type, const Station *st) */ bool CanVehicleUseStation(const Vehicle *v, const Station *st) { - if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL; + if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != nullptr; return CanVehicleUseStation(v->engine_type, st); } @@ -2894,16 +2901,16 @@ void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles) u = u->GetFirstEnginePart(); /* Include num_vehicles vehicles, not counting articulated parts */ - for (; u != NULL && num_vehicles > 0; num_vehicles--) { + for (; u != nullptr && num_vehicles > 0; num_vehicles--) { do { /* Include current vehicle in the selection. */ - set.Include(u->index); + include(set, u->index); /* If the vehicle is multiheaded, add the other part too. */ - if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index); + if (u->IsMultiheaded()) include(set, u->other_multiheaded_part->index); u = u->Next(); - } while (u != NULL && u->IsArticulatedPart()); + } while (u != nullptr && u->IsArticulatedPart()); } } } diff --git a/src/vehicle_base.h b/src/vehicle_base.h index d02d33e2cc..2b091c340f 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -268,9 +268,9 @@ public: int32 x_pos; ///< x coordinate. int32 y_pos; ///< y coordinate. int32 z_pos; ///< z coordinate. - DirectionByte direction; ///< facing + Direction direction; ///< facing - OwnerByte owner; ///< Which company owns the vehicle? + Owner owner; ///< Which company owns the vehicle? /** * currently displayed sprite index * 0xfd == custom sprite, 0xfe == custom second head sprite @@ -459,7 +459,7 @@ public: */ inline void InvalidateNewGRFCacheOfChain() { - for (Vehicle *u = this; u != NULL; u = u->Next()) { + for (Vehicle *u = this; u != nullptr; u = u->Next()) { u->InvalidateNewGRFCache(); } } @@ -576,14 +576,14 @@ public: /** * Get the next vehicle of this vehicle. * @note articulated parts are also counted as vehicles. - * @return the next vehicle or NULL when there isn't a next vehicle. + * @return the next vehicle or nullptr when there isn't a next vehicle. */ inline Vehicle *Next() const { return this->next; } /** * Get the previous vehicle of this vehicle. * @note articulated parts are also counted as vehicles. - * @return the previous vehicle or NULL when there isn't a previous vehicle. + * @return the previous vehicle or nullptr when there isn't a previous vehicle. */ inline Vehicle *Previous() const { return this->previous; } @@ -600,7 +600,7 @@ public: inline Vehicle *Last() { Vehicle *v = this; - while (v->Next() != NULL) v = v->Next(); + while (v->Next() != nullptr) v = v->Next(); return v; } @@ -611,22 +611,22 @@ public: inline const Vehicle *Last() const { const Vehicle *v = this; - while (v->Next() != NULL) v = v->Next(); + while (v->Next() != nullptr) v = v->Next(); return v; } /** * Get the vehicle at offset \a n of this vehicle chain. * @param n Offset from the current vehicle. - * @return The new vehicle or NULL if the offset is out-of-bounds. + * @return The new vehicle or nullptr if the offset is out-of-bounds. */ inline Vehicle *Move(int n) { Vehicle *v = this; if (n < 0) { - for (int i = 0; i != n && v != NULL; i--) v = v->Previous(); + for (int i = 0; i != n && v != nullptr; i--) v = v->Previous(); } else { - for (int i = 0; i != n && v != NULL; i++) v = v->Next(); + for (int i = 0; i != n && v != nullptr; i++) v = v->Next(); } return v; } @@ -634,15 +634,15 @@ public: /** * Get the vehicle at offset \a n of this vehicle chain. * @param n Offset from the current vehicle. - * @return The new vehicle or NULL if the offset is out-of-bounds. + * @return The new vehicle or nullptr if the offset is out-of-bounds. */ inline const Vehicle *Move(int n) const { const Vehicle *v = this; if (n < 0) { - for (int i = 0; i != n && v != NULL; i--) v = v->Previous(); + for (int i = 0; i != n && v != nullptr; i--) v = v->Previous(); } else { - for (int i = 0; i != n && v != NULL; i++) v = v->Next(); + for (int i = 0; i != n && v != nullptr; i++) v = v->Next(); } return v; } @@ -651,20 +651,20 @@ public: * Get the first order of the vehicles order list. * @return first order of order list. */ - inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); } + inline Order *GetFirstOrder() const { return (this->orders.list == nullptr) ? nullptr : this->orders.list->GetFirstOrder(); } void AddToShared(Vehicle *shared_chain); void RemoveFromShared(); /** * Get the next vehicle of the shared vehicle chain. - * @return the next shared vehicle or NULL when there isn't a next vehicle. + * @return the next shared vehicle or nullptr when there isn't a next vehicle. */ inline Vehicle *NextShared() const { return this->next_shared; } /** * Get the previous vehicle of the shared vehicle chain - * @return the previous shared vehicle or NULL when there isn't a previous vehicle. + * @return the previous shared vehicle or nullptr when there isn't a previous vehicle. */ inline Vehicle *PreviousShared() const { return this->previous_shared; } @@ -672,25 +672,25 @@ public: * Get the first vehicle of this vehicle chain. * @return the first vehicle of the chain. */ - inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); } + inline Vehicle *FirstShared() const { return (this->orders.list == nullptr) ? this->First() : this->orders.list->GetFirstSharedVehicle(); } /** * Check if we share our orders with another vehicle. * @return true if there are other vehicles sharing the same order */ - inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); } + inline bool IsOrderListShared() const { return this->orders.list != nullptr && this->orders.list->IsShared(); } /** * Get the number of orders this vehicle has. * @return the number of orders this vehicle has. */ - inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); } + inline VehicleOrderID GetNumOrders() const { return (this->orders.list == nullptr) ? 0 : this->orders.list->GetNumOrders(); } /** * Get the number of manually added orders this vehicle has. * @return the number of manually added orders this vehicle has. */ - inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); } + inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == nullptr) ? 0 : this->orders.list->GetNumManualOrders(); } /** * Get the next station the vehicle will stop at. @@ -698,7 +698,7 @@ public: */ inline StationIDStack GetNextStoppingStation() const { - return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this); + return (this->orders.list == nullptr) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this); } void ResetRefitCaps(); @@ -853,22 +853,22 @@ public: } /** - * Returns order 'index' of a vehicle or NULL when it doesn't exists + * Returns order 'index' of a vehicle or nullptr when it doesn't exists * @param index the order to fetch * @return the found (or not) order */ inline Order *GetOrder(int index) const { - return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index); + return (this->orders.list == nullptr) ? nullptr : this->orders.list->GetOrderAt(index); } /** - * Returns the last order of a vehicle, or NULL if it doesn't exists + * Returns the last order of a vehicle, or nullptr if it doesn't exists * @return last order of a vehicle, if available */ inline Order *GetLastOrder() const { - return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder(); + return (this->orders.list == nullptr) ? nullptr : this->orders.list->GetLastOrder(); } bool IsEngineCountable() const; @@ -900,7 +900,7 @@ public: */ inline bool HasArticulatedPart() const { - return this->Next() != NULL && this->Next()->IsArticulatedPart(); + return this->Next() != nullptr && this->Next()->IsArticulatedPart(); } /** @@ -967,7 +967,7 @@ public: inline Vehicle *GetPrevVehicle() const { Vehicle *v = this->Previous(); - while (v != NULL && v->IsArticulatedPart()) v = v->Previous(); + while (v != nullptr && v->IsArticulatedPart()) v = v->Previous(); return v; } @@ -1103,7 +1103,7 @@ struct SpecializedVehicle : public Vehicle { */ static inline T *GetIfValid(size_t index) { - return IsValidID(index) ? Get(index) : NULL; + return IsValidID(index) ? Get(index) : nullptr; } /** diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 8284511dd4..9a6e236d5a 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -31,6 +31,7 @@ #include "ship.h" #include "newgrf.h" #include "company_base.h" +#include "core/random_func.hpp" #include "table/strings.h" @@ -71,13 +72,16 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin CommandCost CmdBuildShip (TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v); CommandCost CmdBuildAircraft (TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v); +CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text); + /** * Build a vehicle. * @param tile tile of depot where the vehicle is built * @param flags for command * @param p1 various bitstuffed data * bits 0-15: vehicle type being built. - * bits 16-31: vehicle type specific bits passed on to the vehicle build functions. + * bits 16-23: vehicle type specific bits passed on to the vehicle build functions. + * bits 24-31: refit cargo type. * @param p2 User * @param text unused * @return the cost of this operation or an error @@ -93,11 +97,18 @@ CommandCost CmdBuildVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint EngineID eid = GB(p1, 0, 16); if (!IsEngineBuildable(eid, type, _current_company)) return_cmd_error(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type); + /* Validate the cargo type. */ + CargoID cargo = GB(p1, 24, 8); + if (cargo >= NUM_CARGO && cargo != CT_INVALID) return CMD_ERROR; + const Engine *e = Engine::Get(eid); CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost()); /* Engines without valid cargo should not be available */ - if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR; + CargoID default_cargo = e->GetDefaultCargoType(); + if (default_cargo == CT_INVALID) return CMD_ERROR; + + bool refitting = cargo != CT_INVALID && cargo != default_cargo; /* Check whether the number of vehicles we need to build can be built according to pool space. */ uint num_vehicles; @@ -116,35 +127,67 @@ CommandCost CmdBuildVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint UnitID unit_num = (flags & DC_AUTOREPLACE || (type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON)) ? 0 : GetFreeUnitNumber(type); if (unit_num == UINT16_MAX) return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); - Vehicle *v; + /* If we are refitting we need to temporarily purchase the vehicle to be able to + * test it. */ + DoCommandFlag subflags = flags; + if (refitting) subflags |= DC_EXEC; + + /* Vehicle construction needs random bits, so we have to save the random + * seeds to prevent desyncs. */ + SavedRandomSeeds saved_seeds; + SaveRandomSeeds(&saved_seeds); + + Vehicle *v = nullptr; switch (type) { - case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(tile, flags, e, GB(p1, 16, 16), &v)); break; - case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(tile, flags, e, GB(p1, 16, 16), &v)); break; - case VEH_SHIP: value.AddCost(CmdBuildShip (tile, flags, e, GB(p1, 16, 16), &v)); break; - case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (tile, flags, e, GB(p1, 16, 16), &v)); break; + case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(tile, subflags, e, GB(p1, 16, 8), &v)); break; + case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(tile, subflags, e, GB(p1, 16, 8), &v)); break; + case VEH_SHIP: value.AddCost(CmdBuildShip (tile, subflags, e, GB(p1, 16, 8), &v)); break; + case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (tile, subflags, e, GB(p1, 16, 8), &v)); break; default: NOT_REACHED(); // Safe due to IsDepotTile() } - if (value.Succeeded() && flags & DC_EXEC) { - v->unitnumber = unit_num; - v->value = value.GetCost(); - - InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); - InvalidateWindowClassesData(GetWindowClassForVehicleType(type), 0); - SetWindowDirty(WC_COMPANY, _current_company); - if (IsLocalCompany()) { - InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines) + if (value.Succeeded()) { + if (refitting || (flags & DC_EXEC)) { + v->unitnumber = unit_num; + v->value = value.GetCost(); } - GroupStatistics::CountEngine(v, 1); - GroupStatistics::UpdateAutoreplace(_current_company); + if (refitting) { + value.AddCost(CmdRefitVehicle(tile, flags, v->index, cargo, nullptr)); + } else { + /* Fill in non-refitted capacities */ + _returned_refit_capacity = e->GetDisplayDefaultCapacity(&_returned_mail_refit_capacity); + } - if (v->IsPrimaryVehicle()) { - GroupStatistics::CountVehicle(v, 1); - OrderBackup::Restore(v, p2); + if (flags & DC_EXEC) { + InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); + InvalidateWindowClassesData(GetWindowClassForVehicleType(type), 0); + SetWindowDirty(WC_COMPANY, _current_company); + if (IsLocalCompany()) { + InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines) + } + } + + if (refitting || (flags & DC_EXEC)) { + GroupStatistics::CountEngine(v, 1); + GroupStatistics::UpdateAutoreplace(_current_company); + + if (v->IsPrimaryVehicle()) { + GroupStatistics::CountVehicle(v, 1); + OrderBackup::Restore(v, p2); + } + } + + + /* If we are not in DC_EXEC undo everything */ + if (refitting && (flags & DC_EXEC) == 0) { + DoCommand(0, v->index, 0, DC_EXEC, GetCmdSellVeh(v)); } } + /* Only restore if we actually did some refitting */ + if (flags != subflags) RestoreRandomSeeds(saved_seeds); + return value; } @@ -165,7 +208,7 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data, uint3 CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); - if (v == NULL) return CMD_ERROR; + if (v == nullptr) return CMD_ERROR; Vehicle *front = v->First(); @@ -178,7 +221,7 @@ CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /* Can we actually make the order backup, i.e. are there enough orders? */ if (p1 & MAKE_ORDER_BACKUP_FLAG && - front->orders.list != NULL && + front->orders.list != nullptr && !front->orders.list->IsShared() && !Order::CanAllocateItem(front->orders.list->GetNumOrders())) { /* Only happens in exceptional cases when there aren't enough orders anyhow. @@ -202,7 +245,7 @@ CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 /** * Helper to run the refit cost callback. - * @param v The vehicle we are refitting, can be NULL. + * @param v The vehicle we are refitting, can be nullptr. * @param engine_type Which engine to refit * @param new_cid Cargo type we are refitting to. * @param new_subtype New cargo subtype. @@ -215,7 +258,7 @@ static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID ne const Engine *e = Engine::Get(engine_type); /* Is this vehicle a NewGRF vehicle? */ - if (e->GetGRF() != NULL) { + if (e->GetGRF() != nullptr) { const CargoSpec *cs = CargoSpec::Get(new_cid); uint32 param1 = (cs->classes << 16) | (new_subtype << 8) | e->GetGRF()->cargo_map[new_cid]; @@ -229,12 +272,12 @@ static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID ne } *auto_refit_allowed = e->info.refit_cost == 0; - return (v == NULL || v->cargo_type != new_cid) ? e->info.refit_cost : 0; + return (v == nullptr || v->cargo_type != new_cid) ? e->info.refit_cost : 0; } /** * Learn the price of refitting a certain engine - * @param v The vehicle we are refitting, can be NULL. + * @param v The vehicle we are refitting, can be nullptr. * @param engine_type Which engine to refit * @param new_cid Cargo type we are refitting to. * @param new_subtype New cargo subtype. @@ -312,16 +355,15 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, v = v->First(); } - static SmallVector refit_result; - refit_result.Clear(); + std::vector refit_result; v->InvalidateNewGRFCacheOfChain(); byte actual_subtype = new_subtype; - for (; v != NULL; v = (only_this ? NULL : v->Next())) { + for (; v != nullptr; v = (only_this ? nullptr : v->Next())) { /* Reset actual_subtype for every new vehicle */ if (!v->IsArticulatedPart()) actual_subtype = new_subtype; - if (v->type == VEH_TRAIN && !vehicles_to_refit.Contains(v->index) && !only_this) continue; + if (v->type == VEH_TRAIN && std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), v->index) == vehicles_to_refit.end() && !only_this) continue; const Engine *e = v->GetEngine(); if (!e->CanCarryCargo()) continue; @@ -383,32 +425,28 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, * - We have to call the refit cost callback with the pre-refit configuration of the chain because we want refit and * autorefit to behave the same, and we need its result for auto_refit_allowed. */ - RefitResult *result = refit_result.Append(); - result->v = v; - result->capacity = amount; - result->mail_capacity = mail_capacity; - result->subtype = actual_subtype; + refit_result.push_back({v, amount, mail_capacity, actual_subtype}); } if (flags & DC_EXEC) { /* Store the result */ - for (RefitResult *result = refit_result.Begin(); result != refit_result.End(); result++) { - Vehicle *u = result->v; - u->refit_cap = (u->cargo_type == new_cid) ? min(result->capacity, u->refit_cap) : 0; + for (RefitResult &result : refit_result) { + Vehicle *u = result.v; + u->refit_cap = (u->cargo_type == new_cid) ? min(result.capacity, u->refit_cap) : 0; if (u->cargo.TotalCount() > u->refit_cap) u->cargo.Truncate(u->cargo.TotalCount() - u->refit_cap); u->cargo_type = new_cid; - u->cargo_cap = result->capacity; - u->cargo_subtype = result->subtype; + u->cargo_cap = result.capacity; + u->cargo_subtype = result.subtype; if (u->type == VEH_AIRCRAFT) { Vehicle *w = u->Next(); - w->refit_cap = min(w->refit_cap, result->mail_capacity); - w->cargo_cap = result->mail_capacity; + w->refit_cap = min(w->refit_cap, result.mail_capacity); + w->cargo_cap = result.mail_capacity; if (w->cargo.TotalCount() > w->refit_cap) w->cargo.Truncate(w->cargo.TotalCount() - w->refit_cap); } } } - refit_result.Clear(); + refit_result.clear(); _returned_refit_capacity = total_capacity; _returned_mail_refit_capacity = total_mail_capacity; return cost; @@ -432,7 +470,7 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL) return CMD_ERROR; + if (v == nullptr) return CMD_ERROR; /* Don't allow disasters and sparks and such to be refitted. * We cannot check for IsPrimaryVehicle as autoreplace also refits in free wagon chains. */ @@ -523,7 +561,7 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, if ((flags & DC_AUTOREPLACE) == 0) SetBit(p2, 0); Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -615,10 +653,10 @@ CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR; } else { /* Get the list of vehicles in the depot */ - BuildDepotVehicleList(vli.vtype, tile, &list, NULL); + BuildDepotVehicleList(vli.vtype, tile, &list, nullptr); } - for (uint i = 0; i < list.Length(); i++) { + for (uint i = 0; i < list.size(); i++) { const Vehicle *v = list[i]; if (!!(v->vehstatus & VS_STOPPED) != do_start) continue; @@ -657,7 +695,7 @@ CommandCost CmdDepotSellAllVehicles(TileIndex tile, DoCommandFlag flags, uint32 CommandCost last_error = CMD_ERROR; bool had_success = false; - for (uint i = 0; i < list.Length(); i++) { + for (uint i = 0; i < list.size(); i++) { CommandCost ret = DoCommand(tile, list[i]->index | (1 << 20), 0, flags, sell_command); if (ret.Succeeded()) { cost.AddCost(ret); @@ -691,7 +729,7 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 /* Get the list of vehicles in the depot */ BuildDepotVehicleList(vehicle_type, tile, &list, &list, true); - for (uint i = 0; i < list.Length(); i++) { + for (uint i = 0; i < list.size(); i++) { const Vehicle *v = list[i]; /* Ensure that the vehicle completely in the depot */ @@ -714,7 +752,7 @@ static bool IsUniqueVehicleName(const char *name) const Vehicle *v; FOR_ALL_VEHICLES(v) { - if (v->name != NULL && strcmp(v->name, name) == 0) return false; + if (v->name != nullptr && strcmp(v->name, name) == 0) return false; } return true; @@ -784,11 +822,11 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint CommandCost total_cost(EXPENSES_NEW_VEHICLES); Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; Vehicle *v_front = v; - Vehicle *w = NULL; - Vehicle *w_front = NULL; - Vehicle *w_rear = NULL; + Vehicle *w = nullptr; + Vehicle *w_front = nullptr; + Vehicle *w_rear = nullptr; /* * v_front is the front engine in the original vehicle @@ -808,7 +846,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint int veh_counter = 0; do { veh_counter++; - } while ((v = v->Next()) != NULL); + } while ((v = v->Next()) != nullptr); if (!Vehicle::CanAllocateItem(veh_counter)) { return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); @@ -832,11 +870,11 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint DoCommandFlag build_flags = flags; if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE; - CommandCost cost = DoCommand(tile, v->engine_type | (1 << 16), 0, build_flags, GetCmdBuildVeh(v)); + CommandCost cost = DoCommand(tile, v->engine_type | (1 << 16) | (CT_INVALID << 24), 0, build_flags, GetCmdBuildVeh(v)); if (cost.Failed()) { /* Can't build a part, then sell the stuff we already made; clear up the mess */ - if (w_front != NULL) DoCommand(w_front->tile, w_front->index | (1 << 20), 0, flags, GetCmdSellVeh(w_front)); + if (w_front != nullptr) DoCommand(w_front->tile, w_front->index | (1 << 20), 0, flags, GetCmdSellVeh(w_front)); return cost; } @@ -869,7 +907,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint } w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop } - } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != NULL); + } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != nullptr); if ((flags & DC_EXEC) && v_front->type == VEH_TRAIN) { /* for trains this needs to be the front engine due to the callback function */ @@ -895,7 +933,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint do { do { if (flags & DC_EXEC) { - assert(w != NULL); + assert(w != nullptr); /* Find out what's the best sub type */ byte subtype = GetBestFittingSubType(v, w, v->cargo_type); @@ -915,7 +953,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) { bool dummy; - total_cost.AddCost(GetRefitCost(NULL, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy)); + total_cost.AddCost(GetRefitCost(nullptr, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy)); } } @@ -924,10 +962,10 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint } else { break; } - } while (v != NULL); + } while (v != nullptr); if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = w->GetNextVehicle(); - } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != NULL); + } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != nullptr); if (flags & DC_EXEC) { /* @@ -938,7 +976,7 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint DoCommand(0, w_front->index | (p2 & 1 ? CO_SHARE : CO_COPY) << 30, v_front->index, flags, CMD_CLONE_ORDER); /* Now clone the vehicle's name, if it has one. */ - if (v_front->name != NULL) CloneVehicleName(v_front, w_front); + if (v_front->name != nullptr) CloneVehicleName(v_front, w_front); } /* Since we can't estimate the cost of cloning a vehicle accurately we must @@ -969,7 +1007,7 @@ static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, bool service, con /* Send all the vehicles to a depot */ bool had_success = false; - for (uint i = 0; i < list.Length(); i++) { + for (uint i = 0; i < list.size(); i++) { const Vehicle *v = list[i]; CommandCost ret = DoCommand(v->tile, v->index | (service ? DEPOT_SERVICE : 0U) | DEPOT_DONT_CANCEL, 0, flags, GetCmdSendToDepot(vli.vtype)); @@ -1008,7 +1046,7 @@ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1 } Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); - if (v == NULL) return CMD_ERROR; + if (v == nullptr) return CMD_ERROR; if (!v->IsPrimaryVehicle()) return CMD_ERROR; return v->SendToDepot(flags, (DepotCommand)(p1 & DEPOT_COMMAND_MASK)); @@ -1026,7 +1064,7 @@ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1 CommandCost CmdRenameVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; @@ -1040,7 +1078,7 @@ CommandCost CmdRenameVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { free(v->name); - v->name = reset ? NULL : stredup(text); + v->name = reset ? nullptr : stredup(text); InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 1); MarkWholeScreenDirty(); } @@ -1064,7 +1102,7 @@ CommandCost CmdRenameVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uin CommandCost CmdChangeServiceInt(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; + if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 17ec9e28da..bdd961bef3 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -60,7 +60,7 @@ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_t void ViewportAddVehicles(DrawPixelInfo *dpi); void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical); -CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL); +CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore = nullptr); void DecreaseVehicleValue(Vehicle *v); void CheckVehicleBreakdown(Vehicle *v); @@ -71,7 +71,7 @@ UnitID GetFreeUnitNumber(VehicleType type); void VehicleEnterDepot(Vehicle *v); -bool CanBuildVehicleInfrastructure(VehicleType type); +bool CanBuildVehicleInfrastructure(VehicleType type, byte subtype = 0); /** Position information of a vehicle after it moved */ struct GetNewVehiclePosResult { @@ -175,7 +175,7 @@ bool CanVehicleUseStation(const Vehicle *v, const struct Station *st); void ReleaseDisastersTargetingVehicle(VehicleID vehicle); -typedef SmallVector VehicleSet; +typedef std::vector VehicleSet; void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles); void CheckCargoCapacity(Vehicle *v); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index c39b5ae8cc..f31a637cf0 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -107,8 +107,8 @@ const StringID BaseVehicleListWindow::vehicle_depot_name[] = { uint GetUnitNumberDigits(VehicleList &vehicles) { uint unitnumber = 0; - for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) { - unitnumber = max(unitnumber, (*v)->unitnumber); + for (const Vehicle *v : vehicles) { + unitnumber = max(unitnumber, v->unitnumber); } if (unitnumber >= 10000) return 5; @@ -134,7 +134,7 @@ void BaseVehicleListWindow::BuildVehicleList() this->unitnumber_digits = GetUnitNumberDigits(this->vehicles); this->vehicles.RebuildDone(); - this->vscroll->SetCount(this->vehicles.Length()); + this->vscroll->SetCount((uint)this->vehicles.size()); } /** @@ -165,37 +165,37 @@ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bo * @param show_group If true include group-related stuff. * @return Itemlist for dropdown */ -DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) +DropDownList BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) { - DropDownList *list = new DropDownList(); + DropDownList list; - if (show_autoreplace) *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false); - *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false); - *list->Append() = new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false); + if (show_autoreplace) list.emplace_back(new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false)); + list.emplace_back(new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false)); + list.emplace_back(new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false)); if (show_group) { - *list->Append() = new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED, false); - *list->Append() = new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false); + list.emplace_back(new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED, false)); + list.emplace_back(new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false)); } return list; } /* cached values for VehicleNameSorter to spare many GetString() calls */ -static const Vehicle *_last_vehicle[2] = { NULL, NULL }; +static const Vehicle *_last_vehicle[2] = { nullptr, nullptr }; void BaseVehicleListWindow::SortVehicleList() { if (this->vehicles.Sort()) return; /* invalidate cached values for name sorter - vehicle names could change */ - _last_vehicle[0] = _last_vehicle[1] = NULL; + _last_vehicle[0] = _last_vehicle[1] = nullptr; } void DepotSortList(VehicleList *list) { - if (list->Length() < 2) return; - QSortT(list->Begin(), list->Length(), &VehicleNumberSorter); + if (list->size() < 2) return; + std::sort(list->begin(), list->end(), &VehicleNumberSorter); } /** draw the vehicle profit button in the vehicle list window. */ @@ -234,19 +234,19 @@ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_t v_for = v_for->GetFirstEnginePart(); /* Create a list of subtypes used by the various parts of v_for */ - static SmallVector subtypes; - subtypes.Clear(); - for (; v_from != NULL; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : NULL) { + static std::vector subtypes; + subtypes.clear(); + for (; v_from != nullptr; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : nullptr) { const Engine *e_from = v_from->GetEngine(); if (!e_from->CanCarryCargo() || !HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; - subtypes.Include(GetCargoSubtypeText(v_from)); + include(subtypes, GetCargoSubtypeText(v_from)); } byte ret_refit_cyc = 0; bool success = false; - if (subtypes.Length() > 0) { + if (subtypes.size() > 0) { /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */ - for (Vehicle *v = v_for; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { + for (Vehicle *v = v_for; v != nullptr; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr) { const Engine *e = v->GetEngine(); if (!e->CanCarryCargo() || !HasBit(e->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; @@ -268,7 +268,7 @@ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_t StringID subtype = GetCargoSubtypeText(v); if (subtype == STR_EMPTY) break; - if (!subtypes.Contains(subtype)) continue; + if (std::find(subtypes.begin(), subtypes.end(), subtype) == subtypes.end()) continue; /* We found something matching. */ ret_refit_cyc = refit_cyc; @@ -318,7 +318,7 @@ struct RefitOption { } }; -typedef SmallVector SubtypeList; ///< List of refit subtypes associated to a cargo. +typedef std::vector SubtypeList; ///< List of refit subtypes associated to a cargo. /** * Draw the list of available refit options for a consist and highlight the selected refit option (if any). @@ -348,7 +348,7 @@ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int /* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */ for (uint i = 0; current < pos + rows && i < NUM_CARGO; i++) { - for (uint j = 0; current < pos + rows && j < list[i].Length(); j++) { + for (uint j = 0; current < pos + rows && j < list[i].size(); j++) { const RefitOption &refit = list[i][j]; /* Hide subtypes if sel[0] does not match */ @@ -360,11 +360,11 @@ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int continue; } - if (list[i].Length() > 1) { + if (list[i].size() > 1) { if (refit.subtype != 0xFF) { /* Draw tree lines */ int ycenter = y + FONT_HEIGHT_NORMAL / 2; - GfxDrawLine(iconcenter, y - WD_MATRIX_TOP, iconcenter, j == list[i].Length() - 1 ? ycenter : y - WD_MATRIX_TOP + delta - 1, linecolour); + GfxDrawLine(iconcenter, y - WD_MATRIX_TOP, iconcenter, j == list[i].size() - 1 ? ycenter : y - WD_MATRIX_TOP + delta - 1, linecolour); GfxDrawLine(iconcenter, ycenter, iconinner, ycenter, linecolour); } else { /* Draw expand/collapse icon */ @@ -407,7 +407,7 @@ struct RefitWindow : public Window { */ void BuildRefitList() { - for (uint i = 0; i < NUM_CARGO; i++) this->list[i].Clear(); + for (uint i = 0; i < NUM_CARGO; i++) this->list[i].clear(); Vehicle *v = Vehicle::Get(this->window_number); /* Check only the selected vehicles. */ @@ -415,7 +415,7 @@ struct RefitWindow : public Window { GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); do { - if (v->type == VEH_TRAIN && !vehicles_to_refit.Contains(v->index)) continue; + if (v->type == VEH_TRAIN && std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), v->index) == vehicles_to_refit.end()) continue; const Engine *e = v->GetEngine(); CargoTypes cmask = e->info.refit_mask; byte callback_mask = e->info.callback_mask; @@ -436,13 +436,10 @@ struct RefitWindow : public Window { continue; } - bool first_vehicle = this->list[current_index].Length() == 0; + bool first_vehicle = this->list[current_index].size() == 0; if (first_vehicle) { /* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */ - RefitOption *option = this->list[current_index].Append(); - option->cargo = cid; - option->subtype = 0xFF; - option->string = STR_EMPTY; + this->list[current_index].push_back({cid, 0xFF, STR_EMPTY}); } /* Check the vehicle's callback mask for cargo suffixes. @@ -474,16 +471,16 @@ struct RefitWindow : public Window { option.cargo = cid; option.subtype = refit_cyc; option.string = subtype; - this->list[current_index].Include(option); + include(this->list[current_index], option); } else { /* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */ if (subtype == STR_EMPTY) { /* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */ SubtypeList &l = this->list[current_index]; /* 0xFF item is in front, other subtypes are sorted. So just truncate the list in the right spot */ - for (uint i = 1; i < l.Length(); i++) { + for (uint i = 1; i < l.size(); i++) { if (l[i].subtype >= refit_cyc) { - l.Resize(i); + l.resize(i); break; } } @@ -492,10 +489,10 @@ struct RefitWindow : public Window { /* Check whether the subtype matches with the subtype of earlier vehicles. */ uint pos = 1; SubtypeList &l = this->list[current_index]; - while (pos < l.Length() && l[pos].subtype != refit_cyc) pos++; - if (pos < l.Length() && l[pos].string != subtype) { + while (pos < l.size() && l[pos].subtype != refit_cyc) pos++; + if (pos < l.size() && l[pos].string != subtype) { /* String mismatch, remove item keeping the order */ - l.ErasePreservingOrder(pos); + l.erase(l.begin() + pos); } } } @@ -511,7 +508,7 @@ struct RefitWindow : public Window { } current_index++; } - } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); + } while (v->IsGroundVehicle() && (v = v->Next()) != nullptr); } /** @@ -523,7 +520,7 @@ struct RefitWindow : public Window { uint row = 0; for (uint i = 0; i < NUM_CARGO; i++) { - for (uint j = 0; j < this->list[i].Length(); j++) { + for (uint j = 0; j < this->list[i].size(); j++) { const RefitOption &refit = this->list[i][j]; /* Hide subtypes if sel[0] does not match */ @@ -548,7 +545,7 @@ struct RefitWindow : public Window { uint row = 0; for (uint i = 0; i < NUM_CARGO; i++) { - for (uint j = 0; j < this->list[i].Length(); j++) { + for (uint j = 0; j < this->list[i].size(); j++) { const RefitOption &refit = this->list[i][j]; /* Hide subtypes if sel[0] does not match */ @@ -574,10 +571,10 @@ struct RefitWindow : public Window { */ RefitOption *GetRefitOption() { - if (this->sel[0] < 0) return NULL; + if (this->sel[0] < 0) return nullptr; SubtypeList &l = this->list[this->sel[0]]; - if ((uint)this->sel[1] >= l.Length()) return NULL; + if ((uint)this->sel[1] >= l.size()) return nullptr; return &l[this->sel[1]]; } @@ -591,7 +588,7 @@ struct RefitWindow : public Window { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_VR_SCROLLBAR); - this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : NULL); + this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : nullptr); this->GetWidget(WID_VR_SELECT_HEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; this->GetWidget(WID_VR_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; NWidgetCore *nwi = this->GetWidget(WID_VR_REFIT); @@ -606,9 +603,9 @@ struct RefitWindow : public Window { this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); } - virtual void OnInit() + void OnInit() override { - if (this->cargo != NULL) { + if (this->cargo != nullptr) { /* Store the RefitOption currently in use. */ RefitOption current_refit_option = *(this->cargo); @@ -616,9 +613,9 @@ struct RefitWindow : public Window { this->BuildRefitList(); this->sel[0] = -1; this->sel[1] = 0; - this->cargo = NULL; - for (uint i = 0; this->cargo == NULL && i < NUM_CARGO; i++) { - for (uint j = 0; j < list[i].Length(); j++) { + this->cargo = nullptr; + for (uint i = 0; this->cargo == nullptr && i < NUM_CARGO; i++) { + for (uint j = 0; j < list[i].size(); j++) { if (list[i][j] == current_refit_option) { this->sel[0] = i; this->sel[1] = j; @@ -636,10 +633,10 @@ struct RefitWindow : public Window { } } - virtual void OnPaint() + void OnPaint() override { /* Determine amount of items for scroller. */ - if (this->hscroll != NULL) this->hscroll->SetCount(this->vehicle_width); + if (this->hscroll != nullptr) this->hscroll->SetCount(this->vehicle_width); /* Calculate sprite position. */ NWidgetCore *vehicle_panel_display = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); @@ -657,7 +654,7 @@ struct RefitWindow : public Window { this->DrawWidgets(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_VR_MATRIX: @@ -675,7 +672,7 @@ struct RefitWindow : public Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); } @@ -727,13 +724,13 @@ struct RefitWindow : public Window { } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { Vehicle *v = Vehicle::Get(this->window_number); DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, - r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); + r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != nullptr ? this->hscroll->GetPosition() : 0); /* Highlight selected vehicles. */ if (this->order != INVALID_VEH_ORDER_ID) break; @@ -746,16 +743,17 @@ struct RefitWindow : public Window { int left = INT32_MIN; int width = 0; - for (Train *u = Train::From(v); u != NULL; u = u->Next()) { + for (Train *u = Train::From(v); u != nullptr; u = u->Next()) { /* Start checking. */ - if (vehicles_to_refit.Contains(u->index) && left == INT32_MIN) { + const bool contained = std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), u->index) != vehicles_to_refit.end(); + if (contained && left == INT32_MIN) { left = x - this->hscroll->GetPosition() + r.left + this->vehicle_margin; width = 0; } /* Draw a selection. */ - if ((!vehicles_to_refit.Contains(u->index) || u->Next() == NULL) && left != INT32_MIN) { - if (u->Next() == NULL && vehicles_to_refit.Contains(u->index)) { + if ((!contained || u->Next() == nullptr) && left != INT32_MIN) { + if (u->Next() == nullptr && contained) { int current_width = u->GetDisplayImageWidth(); width += current_width; x += current_width; @@ -793,7 +791,7 @@ struct RefitWindow : public Window { break; case WID_VR_INFO: - if (this->cargo != NULL) { + if (this->cargo != nullptr) { StringID string = this->GetCapacityString(this->cargo); if (string != INVALID_STRING_ID) { DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, @@ -809,7 +807,7 @@ struct RefitWindow : public Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { switch (data) { case VIWD_AUTOREPLACE: // Autoreplace replaced the vehicle; selected_vehicle became invalid. @@ -831,7 +829,7 @@ struct RefitWindow : public Window { /* Check the width of all cargo information strings. */ for (uint i = 0; i < NUM_CARGO; i++) { - for (uint j = 0; j < this->list[i].Length(); j++) { + for (uint j = 0; j < this->list[i].size(); j++) { StringID string = this->GetCapacityString(&list[i][j]); if (string != INVALID_STRING_ID) { Dimension dim = GetStringBoundingBox(string); @@ -860,7 +858,7 @@ struct RefitWindow : public Window { const NWidgetCore *matrix_widget = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); if (_current_text_dir == TD_RTL) click_x = matrix_widget->current_x - click_x; click_x -= this->vehicle_margin; - if (this->hscroll != NULL) click_x += this->hscroll->GetPosition(); + if (this->hscroll != nullptr) click_x += this->hscroll->GetPosition(); return click_x; } @@ -881,7 +879,7 @@ struct RefitWindow : public Window { if (left_x >= 0) { const Train *u = Train::From(v); bool start_counting = false; - for (; u != NULL; u = u->Next()) { + for (; u != nullptr; u = u->Next()) { int current_width = u->GetDisplayImageWidth(); left_x -= current_width; right_x -= current_width; @@ -917,7 +915,7 @@ struct RefitWindow : public Window { } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. @@ -945,7 +943,7 @@ struct RefitWindow : public Window { } case WID_VR_REFIT: // refit button - if (this->cargo != NULL) { + if (this->cargo != nullptr) { const Vehicle *v = Vehicle::Get(this->window_number); if (this->order == INVALID_VEH_ORDER_ID) { @@ -959,7 +957,7 @@ struct RefitWindow : public Window { } } - virtual void OnMouseDrag(Point pt, int widget) + void OnMouseDrag(Point pt, int widget) override { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. @@ -972,7 +970,7 @@ struct RefitWindow : public Window { } } - virtual void OnDragDrop(Point pt, int widget) + void OnDragDrop(Point pt, int widget) override { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. @@ -985,11 +983,11 @@ struct RefitWindow : public Window { } } - virtual void OnResize() + void OnResize() override { this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); this->vscroll->SetCapacityFromWidget(this, WID_VR_MATRIX); - if (this->hscroll != NULL) this->hscroll->SetCapacityFromWidget(this, WID_VR_VEHICLE_PANEL_DISPLAY); + if (this->hscroll != nullptr) this->hscroll->SetCapacityFromWidget(this, WID_VR_VEHICLE_PANEL_DISPLAY); } }; @@ -1086,62 +1084,62 @@ StringID GetCargoSubtypeText(const Vehicle *v) } /** Sort vehicles by their number */ -static int CDECL VehicleNumberSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleNumberSorter(const Vehicle * const &a, const Vehicle * const &b) { - return (*a)->unitnumber - (*b)->unitnumber; + return a->unitnumber < b->unitnumber; } /** Sort vehicles by their name */ -static int CDECL VehicleNameSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleNameSorter(const Vehicle * const &a, const Vehicle * const &b) { static char last_name[2][64]; - if (*a != _last_vehicle[0]) { - _last_vehicle[0] = *a; - SetDParam(0, (*a)->index); + if (a != _last_vehicle[0]) { + _last_vehicle[0] = a; + SetDParam(0, a->index); GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0])); } - if (*b != _last_vehicle[1]) { - _last_vehicle[1] = *b; - SetDParam(0, (*b)->index); + if (b != _last_vehicle[1]) { + _last_vehicle[1] = b; + SetDParam(0, b->index); GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1])); } int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). - return (r != 0) ? r : VehicleNumberSorter(a, b); + return (r != 0) ? r < 0: VehicleNumberSorter(a, b); } /** Sort vehicles by their age */ -static int CDECL VehicleAgeSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleAgeSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = (*a)->age - (*b)->age; - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = a->age - b->age; + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by this year profit */ -static int CDECL VehicleProfitThisYearSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleProfitThisYearSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = ClampToI32((*a)->GetDisplayProfitThisYear() - (*b)->GetDisplayProfitThisYear()); - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = ClampToI32(a->GetDisplayProfitThisYear() - b->GetDisplayProfitThisYear()); + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by last year profit */ -static int CDECL VehicleProfitLastYearSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleProfitLastYearSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = ClampToI32((*a)->GetDisplayProfitLastYear() - (*b)->GetDisplayProfitLastYear()); - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = ClampToI32(a->GetDisplayProfitLastYear() - b->GetDisplayProfitLastYear()); + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by their cargo */ -static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleCargoSorter(const Vehicle * const &a, const Vehicle * const &b) { const Vehicle *v; CargoArray diff; /* Append the cargo of the connected waggons */ - for (v = *a; v != NULL; v = v->Next()) diff[v->cargo_type] += v->cargo_cap; - for (v = *b; v != NULL; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap; + for (v = a; v != nullptr; v = v->Next()) diff[v->cargo_type] += v->cargo_cap; + for (v = b; v != nullptr; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap; int r = 0; for (CargoID i = 0; i < NUM_CARGO; i++) { @@ -1149,62 +1147,62 @@ static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * co if (r != 0) break; } - return (r != 0) ? r : VehicleNumberSorter(a, b); + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by their reliability */ -static int CDECL VehicleReliabilitySorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleReliabilitySorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = (*a)->reliability - (*b)->reliability; - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = a->reliability - b->reliability; + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by their max speed */ -static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleMaxSpeedSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = (*a)->vcache.cached_max_speed - (*b)->vcache.cached_max_speed; - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = a->vcache.cached_max_speed - b->vcache.cached_max_speed; + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by model */ -static int CDECL VehicleModelSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleModelSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = (*a)->engine_type - (*b)->engine_type; - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = a->engine_type - b->engine_type; + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by their value */ -static int CDECL VehicleValueSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleValueSorter(const Vehicle * const &a, const Vehicle * const &b) { const Vehicle *u; Money diff = 0; - for (u = *a; u != NULL; u = u->Next()) diff += u->value; - for (u = *b; u != NULL; u = u->Next()) diff -= u->value; + for (u = a; u != nullptr; u = u->Next()) diff += u->value; + for (u = b; u != nullptr; u = u->Next()) diff -= u->value; int r = ClampToI32(diff); - return (r != 0) ? r : VehicleNumberSorter(a, b); + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by their length */ -static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleLengthSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = (*a)->GetGroundVehicleCache()->cached_total_length - (*b)->GetGroundVehicleCache()->cached_total_length; - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = a->GetGroundVehicleCache()->cached_total_length - b->GetGroundVehicleCache()->cached_total_length; + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by the time they can still live */ -static int CDECL VehicleTimeToLiveSorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleTimeToLiveSorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = ClampToI32(((*a)->max_age - (*a)->age) - ((*b)->max_age - (*b)->age)); - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = ClampToI32((a->max_age - a->age) - (b->max_age - b->age)); + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } /** Sort vehicles by the timetable delay */ -static int CDECL VehicleTimetableDelaySorter(const Vehicle * const *a, const Vehicle * const *b) +static bool VehicleTimetableDelaySorter(const Vehicle * const &a, const Vehicle * const &b) { - int r = (*a)->lateness_counter - (*b)->lateness_counter; - return (r != 0) ? r : VehicleNumberSorter(a, b); + int r = a->lateness_counter - b->lateness_counter; + return (r != 0) ? r < 0 : VehicleNumberSorter(a, b); } void InitializeGUI() @@ -1221,10 +1219,10 @@ void InitializeGUI() static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index) { Window *w = FindWindowById(window_class, from_index); - if (w != NULL) { + if (w != nullptr) { /* Update window_number */ w->window_number = to_index; - if (w->viewport != NULL) w->viewport->follow_vehicle = to_index; + if (w->viewport != nullptr) w->viewport->follow_vehicle = to_index; /* Update vehicle drag data */ if (_thd.window_class == window_class && _thd.window_number == (WindowNumber)from_index) { @@ -1294,7 +1292,7 @@ static const NWidgetPart _nested_vehicle_list[] = { static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, VehicleOrderID start = 0) { const Order *order = v->GetOrder(start); - if (order == NULL) return; + if (order == nullptr) return; bool rtl = _current_text_dir == TD_RTL; int l_offset = rtl ? 0 : ScaleGUITrad(6); @@ -1315,7 +1313,7 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, Veh oid++; order = order->next; - if (order == NULL) { + if (order == nullptr) { order = v->orders.list->GetFirstOrder(); oid = 0; } @@ -1389,7 +1387,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int int vehicle_button_x = rtl ? right - GetSpriteSize(SPR_PROFIT_LOT).width : left; int y = r.top; - uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length()); + uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (uint)this->vehicles.size()); for (uint i = this->vscroll->GetPosition(); i < max; ++i) { const Vehicle *v = this->vehicles[i]; StringID str; @@ -1400,7 +1398,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0); DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); - if (v->name != NULL) { + if (v->name != nullptr) { /* The vehicle got a name so we will print it */ SetDParam(0, v->index); DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE); @@ -1486,7 +1484,7 @@ public: *this->sorting = this->vehicles.GetListing(); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_VL_LIST: @@ -1523,7 +1521,7 @@ public: } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_VL_AVAILABLE_VEHICLES: @@ -1533,7 +1531,7 @@ public: case WID_VL_CAPTION: { switch (this->vli.type) { case VL_SHARED_ORDERS: // Shared Orders - if (this->vehicles.Length() == 0) { + if (this->vehicles.size() == 0) { /* We can't open this window without vehicles using this order * and we should close the window when deleting the order. */ NOT_REACHED(); @@ -1566,7 +1564,7 @@ public: } } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_VL_SORT_ORDER: @@ -1580,12 +1578,12 @@ public: } } - virtual void OnPaint() + void OnPaint() override { this->BuildVehicleList(); this->SortVehicleList(); - if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_VL_MANAGE_VEHICLES_DROPDOWN)) { + if (this->vehicles.size() == 0 && this->IsWidgetLowered(WID_VL_MANAGE_VEHICLES_DROPDOWN)) { HideDropDownMenu(this); } @@ -1599,7 +1597,7 @@ public: } if (this->owner == _local_company) { this->SetWidgetDisabledState(WID_VL_AVAILABLE_VEHICLES, this->vli.type != VL_STANDARD); - this->SetWidgetsDisabledState(this->vehicles.Length() == 0, + this->SetWidgetsDisabledState(this->vehicles.size() == 0, WID_VL_MANAGE_VEHICLES_DROPDOWN, WID_VL_STOP_ALL, WID_VL_START_ALL, @@ -1612,7 +1610,7 @@ public: this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_VL_SORT_ORDER: // Flip sorting method ascending/descending @@ -1627,7 +1625,7 @@ public: case WID_VL_LIST: { // Matrix to show vehicles uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST); - if (id_v >= this->vehicles.Length()) return; // click out of list bound + if (id_v >= this->vehicles.size()) return; // click out of list bound const Vehicle *v = this->vehicles[id_v]; if (!VehicleClicked(v)) ShowVehicleViewWindow(v); @@ -1639,8 +1637,7 @@ public: break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: { - DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier::UnPack(this->window_number).type == VL_STANDARD, false); - ShowDropDownList(this, list, 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); + ShowDropDownList(this, this->BuildActionDropdownList(VehicleListIdentifier::UnPack(this->window_number).type == VL_STANDARD, false), 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); break; } @@ -1651,14 +1648,14 @@ public: } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_VL_SORT_BY_PULLDOWN: this->vehicles.SetSortType(index); break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: - assert(this->vehicles.Length() != 0); + assert(this->vehicles.size() != 0); switch (index) { case ADI_REPLACE: // Replace window @@ -1677,7 +1674,7 @@ public: this->SetDirty(); } - virtual void OnGameTick() + void OnGameTick() override { if (this->vehicles.NeedResort()) { StationID station = (this->vli.type == VL_STATION_LIST) ? this->vli.index : INVALID_STATION; @@ -1687,7 +1684,7 @@ public: } } - virtual void OnResize() + void OnResize() override { this->vscroll->SetCapacityFromWidget(this, WID_VL_LIST); } @@ -1697,7 +1694,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope && HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) { /* Needs to be done in command-scope, so everything stays valid */ @@ -1873,7 +1870,7 @@ struct VehicleDetailsWindow : Window { const Vehicle *v = Vehicle::Get(window_number); this->CreateNestedTree(); - this->vscroll = (v->type == VEH_TRAIN ? this->GetScrollbar(WID_VD_SCROLLBAR) : NULL); + this->vscroll = (v->type == VEH_TRAIN ? this->GetScrollbar(WID_VD_SCROLLBAR) : nullptr); this->FinishInitNested(window_number); this->GetWidget(WID_VD_RENAME_VEHICLE)->tool_tip = STR_VEHICLE_DETAILS_TRAIN_RENAME + v->type; @@ -1887,7 +1884,7 @@ struct VehicleDetailsWindow : Window { * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == VIWD_AUTOREPLACE) { /* Autoreplace replaced the vehicle. @@ -1918,7 +1915,7 @@ struct VehicleDetailsWindow : Window { /* An articulated RV has its text drawn under the sprite instead of after it, hence 15 pixels extra. */ desired_height = WD_FRAMERECT_TOP + ScaleGUITrad(15) + 3 * FONT_HEIGHT_NORMAL + 2 + WD_FRAMERECT_BOTTOM; /* Add space for the cargo amount for each part. */ - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { if (u->cargo_cap != 0) desired_height += FONT_HEIGHT_NORMAL + 1; } } else { @@ -1927,7 +1924,7 @@ struct VehicleDetailsWindow : Window { return desired_height; } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_VD_TOP_DETAILS: { @@ -2031,12 +2028,12 @@ struct VehicleDetailsWindow : Window { } } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_VD_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { const Vehicle *v = Vehicle::Get(this->window_number); @@ -2134,7 +2131,7 @@ struct VehicleDetailsWindow : Window { } /** Repaint vehicle details window. */ - virtual void OnPaint() + void OnPaint() override { const Vehicle *v = Vehicle::Get(this->window_number); @@ -2159,7 +2156,7 @@ struct VehicleDetailsWindow : Window { this->DrawWidgets(); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_VD_RENAME_VEHICLE: { // rename @@ -2207,7 +2204,7 @@ struct VehicleDetailsWindow : Window { } } - virtual void OnDropdownSelect(int widget, int index) + void OnDropdownSelect(int widget, int index) override { switch (widget) { case WID_VD_SERVICE_INTERVAL_DROPDOWN: { @@ -2221,17 +2218,17 @@ struct VehicleDetailsWindow : Window { } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; - DoCommandP(0, this->window_number, 0, CMD_RENAME_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type), NULL, str); + DoCommandP(0, this->window_number, 0, CMD_RENAME_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type), nullptr, str); } - virtual void OnResize() + void OnResize() override { NWidgetCore *nwi = this->GetWidget(WID_VD_MATRIX); - if (nwi != NULL) { + if (nwi != nullptr) { this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX); } } @@ -2369,7 +2366,7 @@ void CcStartStopVehicle(const CommandCost &result, TileIndex tile, uint32 p1, ui if (result.Failed()) return; const Vehicle *v = Vehicle::GetIfValid(p1); - if (v == NULL || !v->IsPrimaryVehicle() || v->owner != _local_company) return; + if (v == nullptr || !v->IsPrimaryVehicle() || v->owner != _local_company) return; StringID msg = (v->vehstatus & VS_STOPPED) ? STR_VEHICLE_COMMAND_STOPPED : STR_VEHICLE_COMMAND_STARTED; Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos); @@ -2384,7 +2381,7 @@ void CcStartStopVehicle(const CommandCost &result, TileIndex tile, uint32 p1, ui void StartStopVehicle(const Vehicle *v, bool texteffect) { assert(v->IsPrimaryVehicle()); - DoCommandP(v->tile, v->index, 0, _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : NULL); + DoCommandP(v->tile, v->index, 0, _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : nullptr); } /** Checks whether the vehicle may be refitted at the moment.*/ @@ -2394,7 +2391,7 @@ static bool IsVehicleRefitable(const Vehicle *v) do { if (IsEngineRefittable(v->engine_type)) return true; - } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); + } while (v->IsGroundVehicle() && (v = v->Next()) != nullptr); return false; } @@ -2499,7 +2496,7 @@ public: DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false); } - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { const Vehicle *v = Vehicle::Get(this->window_number); switch (widget) { @@ -2521,7 +2518,7 @@ public: } } - virtual void OnPaint() + void OnPaint() override { const Vehicle *v = Vehicle::Get(this->window_number); bool is_localcompany = v->owner == _local_company; @@ -2540,7 +2537,7 @@ public: this->DrawWidgets(); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget != WID_VV_CAPTION) return; @@ -2548,7 +2545,7 @@ public: SetDParam(0, v->index); } - virtual void DrawWidget(const Rect &r, int widget) const + void DrawWidget(const Rect &r, int widget) const override { if (widget != WID_VV_START_STOP) return; @@ -2647,7 +2644,7 @@ public: DrawString(text_left + lowered, text_right + lowered, r.top + WD_FRAMERECT_TOP + lowered, str, TC_FROMSTRING, SA_HOR_CENTER); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { const Vehicle *v = Vehicle::Get(this->window_number); @@ -2696,7 +2693,7 @@ public: * most likely already open, but is also visible in the vehicle viewport. */ DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type], - _ctrl_pressed ? NULL : CcCloneVehicle); + _ctrl_pressed ? nullptr : CcCloneVehicle); break; case WID_VV_TURN_AROUND: // turn around assert(v->IsGroundVehicle()); @@ -2710,9 +2707,9 @@ public: } } - virtual void OnResize() + void OnResize() override { - if (this->viewport != NULL) { + if (this->viewport != nullptr) { NWidgetViewport *nvp = this->GetWidget(WID_VV_VIEWPORT); nvp->UpdateViewportCoordinates(this); } @@ -2748,7 +2745,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (data == VIWD_AUTOREPLACE) { /* Autoreplace replaced the vehicle. @@ -2759,12 +2756,12 @@ public: this->UpdateButtonStatus(); } - virtual bool IsNewGRFInspectable() const + bool IsNewGRFInspectable() const override { return ::IsNewGRFInspectable(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); } - virtual void ShowNewGRFInspectWindow() const + void ShowNewGRFInspectWindow() const override { ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); } @@ -2821,7 +2818,7 @@ void ShowVehicleViewWindow(const Vehicle *v) */ bool VehicleClicked(const Vehicle *v) { - assert(v != NULL); + assert(v != nullptr); if (!(_thd.place_mode & HT_VEHICLE)) return false; v = v->First(); @@ -2833,7 +2830,7 @@ bool VehicleClicked(const Vehicle *v) void StopGlobalFollowVehicle(const Vehicle *v) { Window *w = FindWindowById(WC_MAIN_WINDOW, 0); - if (w != NULL && w->viewport->follow_vehicle == v->index) { + if (w != nullptr && w->viewport->follow_vehicle == v->index) { ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true); // lock the main view on the vehicle's last position w->viewport->follow_vehicle = INVALID_VEHICLE; } @@ -2889,7 +2886,7 @@ int GetVehicleWidth(const Vehicle *v, EngineImageType image_type) { if (v->type == VEH_TRAIN || v->type == VEH_ROAD) { int vehicle_width = 0; - for (const Vehicle *u = v; u != NULL; u = u->Next()) { + for (const Vehicle *u = v; u != nullptr; u = u->Next()) { vehicle_width += GetSingleVehicleWidth(u, image_type); } return vehicle_width; @@ -2909,7 +2906,7 @@ void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type) _cursor.sprite_count = 0; int total_width = 0; - for (; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { + for (; v != nullptr; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr) { if (total_width >= 2 * (int)VEHICLEINFO_FULL_VEHICLE_WIDTH) break; PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); diff --git a/src/vehicle_gui.h b/src/vehicle_gui.h index 92975425df..9eb688eee9 100644 --- a/src/vehicle_gui.h +++ b/src/vehicle_gui.h @@ -37,7 +37,15 @@ enum VehicleInvalidateWindowData { VIWD_AUTOREPLACE = -4, ///< Autoreplace replaced the vehicle. }; -int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number); +/** Extra information about refitted cargo and capacity */ +struct TestedEngineDetails { + Money cost; ///< Refit cost + CargoID cargo; ///< Cargo type + uint16 capacity; ///< Cargo capacity + uint16 mail_capacity; ///< Mail capacity if available +}; + +int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number, TestedEngineDetails &te); void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip, VehicleID drag_dest = INVALID_VEHICLE); void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip = 0); diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index 5755c7fa88..8e75278412 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -47,7 +47,7 @@ struct BaseVehicleListWindow : public Window { void SortVehicleList(); void BuildVehicleList(); Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group); - DropDownList *BuildActionDropdownList(bool show_autoreplace, bool show_group); + DropDownList BuildActionDropdownList(bool show_autoreplace, bool show_group); }; uint GetVehicleListHeight(VehicleType type, uint divisor = 1); diff --git a/src/vehicle_type.h b/src/vehicle_type.h index f3e7d535fd..29929fd8b0 100644 --- a/src/vehicle_type.h +++ b/src/vehicle_type.h @@ -19,8 +19,8 @@ typedef uint32 VehicleID; static const int GROUND_ACCELERATION = 9800; ///< Acceleration due to gravity, 9.8 m/s^2 -/** Available vehicle types. */ -enum VehicleType { +/** Available vehicle types. It needs to be 8bits, because we save and load it as such */ +enum VehicleType : byte { VEH_BEGIN, VEH_TRAIN = VEH_BEGIN, ///< %Train vehicle type. @@ -39,8 +39,6 @@ enum VehicleType { DECLARE_POSTFIX_INCREMENT(VehicleType) /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; -/** It needs to be 8bits, because we save and load it as such */ -typedef SimpleTinyEnumT VehicleTypeByte; struct Vehicle; struct Train; @@ -53,21 +51,21 @@ struct DisasterVehicle; /** Base vehicle class. */ struct BaseVehicle { - VehicleTypeByte type; ///< Type of vehicle + VehicleType type; ///< Type of vehicle }; static const VehicleID INVALID_VEHICLE = 0xFFFFF; ///< Constant representing a non-existing vehicle. /** Pathfinding option states */ enum VehiclePathFinders { - VPF_OPF = 0, ///< The Original PathFinder (only for ships) + // Original PathFinder (OPF) used to be 0 VPF_NPF = 1, ///< New PathFinder VPF_YAPF = 2, ///< Yet Another PathFinder }; /** Flags to add to p1 for goto depot commands. */ enum DepotCommand { - DEPOT_SERVICE = (1U << 28), ///< The vehicle will leave the depot right after arrival (serivce only) + DEPOT_SERVICE = (1U << 28), ///< The vehicle will leave the depot right after arrival (service only) DEPOT_MASS_SEND = (1U << 29), ///< Tells that it's a mass send to depot command (type in VLW flag) DEPOT_DONT_CANCEL = (1U << 30), ///< Don't cancel current goto depot command if any DEPOT_LOCATE_HANGAR = (1U << 31), ///< Find another airport if the target one lacks a hangar diff --git a/src/vehiclelist.cpp b/src/vehiclelist.cpp index bfe4e5ffd1..acb848982d 100644 --- a/src/vehiclelist.cpp +++ b/src/vehiclelist.cpp @@ -65,13 +65,13 @@ bool VehicleListIdentifier::UnpackIfValid(uint32 data) * @param type Type of vehicle * @param tile The tile the depot is located on * @param engines Pointer to list to add vehicles to - * @param wagons Pointer to list to add wagons to (can be NULL) + * @param wagons Pointer to list to add wagons to (can be nullptr) * @param individual_wagons If true add every wagon to \a wagons which is not attached to an engine. If false only add the first wagon of every row. */ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engines, VehicleList *wagons, bool individual_wagons) { - engines->Clear(); - if (wagons != NULL && wagons != engines) wagons->Clear(); + engines->clear(); + if (wagons != nullptr && wagons != engines) wagons->clear(); const Vehicle *v; FOR_ALL_VEHICLES(v) { @@ -84,8 +84,8 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine const Train *t = Train::From(v); if (t->IsArticulatedPart() || t->IsRearDualheaded()) continue; if (t->track != TRACK_BIT_DEPOT) continue; - if (wagons != NULL && t->First()->IsFreeWagon()) { - if (individual_wagons || t->IsFreeWagon()) *wagons->Append() = t; + if (wagons != nullptr && t->First()->IsFreeWagon()) { + if (individual_wagons || t->IsFreeWagon()) wagons->push_back(t); continue; } break; @@ -98,13 +98,13 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine if (!v->IsPrimaryVehicle()) continue; - *engines->Append() = v; + engines->push_back(v); } /* Ensure the lists are not wasting too much space. If the lists are fresh * (i.e. built within a command) then this will actually do nothing. */ - engines->Compact(); - if (wagons != NULL && wagons != engines) wagons->Compact(); + engines->shrink_to_fit(); + if (wagons != nullptr && wagons != engines) wagons->shrink_to_fit(); } /** @@ -115,7 +115,7 @@ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine */ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli) { - list->Clear(); + list->clear(); const Vehicle *v; @@ -128,7 +128,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli FOR_VEHICLE_ORDERS(v, order) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) && order->GetDestination() == vli.index) { - *list->Append() = v; + list->push_back(v); break; } } @@ -139,10 +139,10 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_SHARED_ORDERS: /* Add all vehicles from this vehicle's shared order list */ v = Vehicle::GetIfValid(vli.index); - if (v == NULL || v->type != vli.vtype || !v->IsPrimaryVehicle()) return false; + if (v == nullptr || v->type != vli.vtype || !v->IsPrimaryVehicle()) return false; - for (; v != NULL; v = v->NextShared()) { - *list->Append() = v; + for (; v != nullptr; v = v->NextShared()) { + list->push_back(v); } break; @@ -151,7 +151,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli FOR_ALL_VEHICLES(v) { if (v->type == vli.vtype && v->IsPrimaryVehicle() && v->owner == vli.company && GroupIsInGroup(v->group_id, vli.index)) { - *list->Append() = v; + list->push_back(v); } } break; @@ -161,7 +161,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli case VL_STANDARD: FOR_ALL_VEHICLES(v) { if (v->type == vli.vtype && v->owner == vli.company && v->IsPrimaryVehicle()) { - *list->Append() = v; + list->push_back(v); } } break; @@ -173,7 +173,7 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index) { - *list->Append() = v; + list->push_back(v); break; } } @@ -184,6 +184,6 @@ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli default: return false; } - list->Compact(); + list->shrink_to_fit(); return true; } diff --git a/src/vehiclelist.h b/src/vehiclelist.h index 996c8c007f..ed817b71c7 100644 --- a/src/vehiclelist.h +++ b/src/vehiclelist.h @@ -52,7 +52,7 @@ struct VehicleListIdentifier { }; /** A list of vehicles. */ -typedef SmallVector VehicleList; +typedef std::vector VehicleList; bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &identifier); void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine_list, VehicleList *wagon_list, bool individual_wagons = false); diff --git a/src/video/allegro_v.cpp b/src/video/allegro_v.cpp index 960d7fb7c8..3d4aea8f11 100644 --- a/src/video/allegro_v.cpp +++ b/src/video/allegro_v.cpp @@ -25,8 +25,10 @@ #include "../core/random_func.hpp" #include "../core/math_func.hpp" #include "../framerate_type.h" +#include "../thread.h" #include "allegro_v.h" #include +#include #include "../safeguards.h" @@ -138,34 +140,25 @@ static void GetVideoModes() * cards ourselves... and we need a card to get the modes. */ set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); + _resolutions.clear(); + GFX_MODE_LIST *mode_list = get_gfx_mode_list(gfx_driver->id); - if (mode_list == NULL) { - memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); - _num_resolutions = lengthof(default_resolutions); + if (mode_list == nullptr) { + _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions)); return; } GFX_MODE *modes = mode_list->mode; - int n = 0; for (int i = 0; modes[i].bpp != 0; i++) { uint w = modes[i].width; uint h = modes[i].height; - if (w >= 640 && h >= 480) { - int j; - for (j = 0; j < n; j++) { - if (_resolutions[j].width == w && _resolutions[j].height == h) break; - } - - if (j == n) { - _resolutions[j].width = w; - _resolutions[j].height = h; - if (++n == lengthof(_resolutions)) break; - } - } + if (w < 640 || h < 480) continue; + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(w, h)) != _resolutions.end()) continue; + _resolutions.emplace_back(w, h); } - _num_resolutions = n; - SortResolutions(_num_resolutions); + + SortResolutions(); destroy_gfx_mode_list(mode_list); } @@ -173,17 +166,15 @@ static void GetVideoModes() static void GetAvailableVideoMode(uint *w, uint *h) { /* No video modes, so just try it and see where it ends */ - if (_num_resolutions == 0) return; + if (_resolutions.empty()) return; /* is the wanted mode among the available modes? */ - for (int i = 0; i != _num_resolutions; i++) { - if (*w == _resolutions[i].width && *h == _resolutions[i].height) return; - } + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(*w, *h)) != _resolutions.end()) return; /* use the closest possible resolution */ - int best = 0; + uint best = 0; uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); - for (int i = 1; i != _num_resolutions; ++i) { + for (uint i = 1; i != _resolutions.size(); ++i) { uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); if (newdelta < delta) { best = i; @@ -242,7 +233,7 @@ static bool CreateMainSurface(uint w, uint h) bool VideoDriver_Allegro::ClaimMousePointer() { select_mouse_cursor(MOUSE_CURSOR_NONE); - show_mouse(NULL); + show_mouse(nullptr); disable_hardware_cursor(); return true; } @@ -423,7 +414,7 @@ int _allegro_instance_count = 0; const char *VideoDriver_Allegro::Start(const char * const *parm) { - if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, NULL)) { + if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, nullptr)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); return "Failed to set up Allegro"; } @@ -436,14 +427,8 @@ const char *VideoDriver_Allegro::Start(const char * const *parm) #if defined _DEBUG /* Allegro replaces SEGV/ABRT signals meaning that the debugger will never * be triggered, so rereplace the signals and make the debugger useful. */ - signal(SIGABRT, NULL); - signal(SIGSEGV, NULL); -#endif - -#if defined(DOS) - /* Force DOS builds to ALWAYS use full screen as - * it can't do windowed. */ - _fullscreen = true; + signal(SIGABRT, nullptr); + signal(SIGSEGV, nullptr); #endif GetVideoModes(); @@ -453,7 +438,7 @@ const char *VideoDriver_Allegro::Start(const char * const *parm) MarkWholeScreenDirty(); set_close_button_callback(HandleExitGameRequest); - return NULL; + return nullptr; } void VideoDriver_Allegro::Stop() @@ -461,14 +446,14 @@ void VideoDriver_Allegro::Stop() if (--_allegro_instance_count == 0) allegro_exit(); } -#if defined(UNIX) || defined(__OS2__) || defined(DOS) +#if defined(UNIX) || defined(__OS2__) # include /* gettimeofday */ static uint32 GetTime() { struct timeval tim; - gettimeofday(&tim, NULL); + gettimeofday(&tim, nullptr); return tim.tv_usec / 1000 + tim.tv_sec * 1000; } #else @@ -548,18 +533,14 @@ bool VideoDriver_Allegro::ChangeResolution(int w, int h) bool VideoDriver_Allegro::ToggleFullscreen(bool fullscreen) { -#ifdef DOS - return false; -#else _fullscreen = fullscreen; GetVideoModes(); // get the list of available video modes - if (_num_resolutions == 0 || !this->ChangeResolution(_cur_resolution.width, _cur_resolution.height)) { + if (_resolutions.empty() || !this->ChangeResolution(_cur_resolution.width, _cur_resolution.height)) { /* switching resolution failed, put back full_screen to original status */ _fullscreen ^= true; return false; } return true; -#endif } bool VideoDriver_Allegro::AfterBlitterChange() diff --git a/src/video/allegro_v.h b/src/video/allegro_v.h index a770635da0..f68ce5781d 100644 --- a/src/video/allegro_v.h +++ b/src/video/allegro_v.h @@ -17,30 +17,30 @@ /** The allegro video driver. */ class VideoDriver_Allegro : public VideoDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void MakeDirty(int left, int top, int width, int height); + void MakeDirty(int left, int top, int width, int height) override; - /* virtual */ void MainLoop(); + void MainLoop() override; - /* virtual */ bool ChangeResolution(int w, int h); + bool ChangeResolution(int w, int h) override; - /* virtual */ bool ToggleFullscreen(bool fullscreen); + bool ToggleFullscreen(bool fullscreen) override; - /* virtual */ bool AfterBlitterChange(); + bool AfterBlitterChange() override; - /* virtual */ bool ClaimMousePointer(); + bool ClaimMousePointer() override; - /* virtual */ const char *GetName() const { return "allegro"; } + const char *GetName() const override { return "allegro"; } }; /** Factory for the allegro video driver. */ class FVideoDriver_Allegro : public DriverFactoryBase { public: FVideoDriver_Allegro() : DriverFactoryBase(Driver::DT_VIDEO, 4, "allegro", "Allegro Video Driver") {} - /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Allegro(); } + Driver *CreateInstance() const override { return new VideoDriver_Allegro(); } }; #endif /* VIDEO_ALLEGRO_H */ diff --git a/src/video/cocoa/cocoa_keys.h b/src/video/cocoa/cocoa_keys.h index 426befd184..e2d5ee9fc0 100644 --- a/src/video/cocoa/cocoa_keys.h +++ b/src/video/cocoa/cocoa_keys.h @@ -126,7 +126,7 @@ #define QZ_KP0 0x52 #define QZ_KP_PERIOD 0x41 -/* Wierd, these keys are on my iBook under MacOS X */ +/* Weird, these keys are on my iBook under MacOS X */ #define QZ_IBOOK_ENTER 0x34 #define QZ_IBOOK_LEFT 0x3B #define QZ_IBOOK_RIGHT 0x3C diff --git a/src/video/cocoa/cocoa_v.h b/src/video/cocoa/cocoa_v.h index ecaba02bdc..dc0bbeecc4 100644 --- a/src/video/cocoa/cocoa_v.h +++ b/src/video/cocoa/cocoa_v.h @@ -16,10 +16,10 @@ class VideoDriver_Cocoa : public VideoDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; /** Stop the video driver */ - /* virtual */ void Stop(); + void Stop() override; /** Mark dirty a screen region * @param left x-coordinate of left border @@ -27,44 +27,44 @@ public: * @param width width or dirty rectangle * @param height height of dirty rectangle */ - /* virtual */ void MakeDirty(int left, int top, int width, int height); + void MakeDirty(int left, int top, int width, int height) override; /** Programme main loop */ - /* virtual */ void MainLoop(); + void MainLoop() override; /** Change window resolution * @param w New window width * @param h New window height * @return Whether change was successful */ - /* virtual */ bool ChangeResolution(int w, int h); + bool ChangeResolution(int w, int h) override; /** Set a new window mode * @param fullscreen Whether to set fullscreen mode or not * @return Whether changing the screen mode was successful */ - /* virtual */ bool ToggleFullscreen(bool fullscreen); + bool ToggleFullscreen(bool fullscreen) override; /** Callback invoked after the blitter was changed. * @return True if no error. */ - /* virtual */ bool AfterBlitterChange(); + bool AfterBlitterChange() override; /** * An edit box lost the input focus. Abort character compositing if necessary. */ - /* virtual */ void EditBoxLostFocus(); + void EditBoxLostFocus() override; /** Return driver name * @return driver name */ - /* virtual */ const char *GetName() const { return "cocoa"; } + const char *GetName() const override { return "cocoa"; } }; class FVideoDriver_Cocoa : public DriverFactoryBase { public: FVideoDriver_Cocoa() : DriverFactoryBase(Driver::DT_VIDEO, 10, "cocoa", "Cocoa Video Driver") {} - /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Cocoa(); } + Driver *CreateInstance() const override { return new VideoDriver_Cocoa(); } }; diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 52a25f94fb..afbca6501a 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -234,13 +234,13 @@ static void setupApplication() } -static int CDECL ModeSorter(const OTTD_Point *p1, const OTTD_Point *p2) +static bool ModeSorter(const OTTD_Point &p1, const OTTD_Point &p2) { - if (p1->x < p2->x) return -1; - if (p1->x > p2->x) return +1; - if (p1->y < p2->y) return -1; - if (p1->y > p2->y) return +1; - return 0; + if (p1.x < p2.x) return true; + if (p1.x > p2.x) return false; + if (p1.y < p2.y) return true; + if (p1.y > p2.y) return false; + return false; } static void QZ_GetDisplayModeInfo(CFArrayRef modes, CFIndex i, int &bpp, uint16 &width, uint16 &height) @@ -326,7 +326,7 @@ uint QZ_ListModes(OTTD_Point *modes, uint max_modes, CGDirectDisplayID display_i } /* Sort list smallest to largest */ - QSortT(modes, count, &ModeSorter); + std::sort(modes, modes + count, ModeSorter); #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) if (MacOSVersionIsAtLeast(10, 6, 0)) CFRelease(mode_list); @@ -363,12 +363,10 @@ static void QZ_UpdateVideoModes() OTTD_Point modes[32]; uint count = _cocoa_subdriver->ListModes(modes, lengthof(modes)); + _resolutions.clear(); for (uint i = 0; i < count; i++) { - _resolutions[i].width = modes[i].x; - _resolutions[i].height = modes[i].y; + _resolutions.emplace_back(modes[i].x, modes[i].y); } - - _num_resolutions = count; } /** diff --git a/src/video/cocoa/event.mm b/src/video/cocoa/event.mm index de812a70d6..a8108b561a 100644 --- a/src/video/cocoa/event.mm +++ b/src/video/cocoa/event.mm @@ -37,6 +37,7 @@ #include "../../core/math_func.hpp" #include "../../texteff.hpp" #include "../../window_func.h" +#include "../../thread.h" #import /* gettimeofday */ diff --git a/src/video/cocoa/fullscreen.mm b/src/video/cocoa/fullscreen.mm index 860866b336..3ce22133d2 100644 --- a/src/video/cocoa/fullscreen.mm +++ b/src/video/cocoa/fullscreen.mm @@ -30,6 +30,7 @@ #include "../../core/sort_func.hpp" #include "cocoa_v.h" #include "../../gfx_func.h" +#include "../../thread.h" #include "../../os/macosx/macos.h" /** @@ -174,7 +175,7 @@ class FullscreenSubdriver : public CocoaSubdriver { double adjustment = (target - position) / linesPerSecond; - CSleep((uint32)(adjustment * 1000)); + CSleep((uint32)adjustment * 1000); } diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index 47fa64231a..c29fd5fd1b 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -11,8 +11,6 @@ #include "../stdafx.h" -#ifdef ENABLE_NETWORK - #include "../gfx_func.h" #include "../network/network.h" #include "../network/network_internal.h" @@ -24,12 +22,9 @@ #include "../company_func.h" #include "../core/random_func.hpp" #include "../saveload/saveload.h" +#include "../thread.h" #include "dedicated_v.h" -#ifdef BEOS_NET_SERVER -#include -#endif - #ifdef __OS2__ # include /* gettimeofday */ # include @@ -79,6 +74,7 @@ static void DedicatedSignalHandler(int sig) # include # include # include "../os/windows/win32.h" + static HANDLE _hInputReady, _hWaitForInputHandling; static HANDLE _hThread; // Thread to close static char _win_console_thread_buffer[200]; @@ -86,12 +82,12 @@ static char _win_console_thread_buffer[200]; /* Windows Console thread. Just loop and signal when input has been received */ static void WINAPI CheckForConsoleInput() { - SetWin32ThreadName(-1, "ottd:win-console"); + SetCurrentThreadName("ottd:win-console"); DWORD nb; HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); for (;;) { - ReadFile(hStdin, _win_console_thread_buffer, lengthof(_win_console_thread_buffer), &nb, NULL); + ReadFile(hStdin, _win_console_thread_buffer, lengthof(_win_console_thread_buffer), &nb, nullptr); if (nb >= lengthof(_win_console_thread_buffer)) nb = lengthof(_win_console_thread_buffer) - 1; _win_console_thread_buffer[nb] = '\0'; @@ -106,12 +102,12 @@ static void CreateWindowsConsoleThread() { DWORD dwThreadId; /* Create event to signal when console input is ready */ - _hInputReady = CreateEvent(NULL, false, false, NULL); - _hWaitForInputHandling = CreateEvent(NULL, false, false, NULL); - if (_hInputReady == NULL || _hWaitForInputHandling == NULL) usererror("Cannot create console event!"); + _hInputReady = CreateEvent(nullptr, false, false, nullptr); + _hWaitForInputHandling = CreateEvent(nullptr, false, false, nullptr); + if (_hInputReady == nullptr || _hWaitForInputHandling == nullptr) usererror("Cannot create console event!"); - _hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, NULL, 0, &dwThreadId); - if (_hThread == NULL) usererror("Cannot create console thread!"); + _hThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, nullptr, 0, &dwThreadId); + if (_hThread == nullptr) usererror("Cannot create console thread!"); DEBUG(driver, 2, "Windows console thread started"); } @@ -134,7 +130,7 @@ static void *_dedicated_video_mem; /* Whether a fork has been done. */ bool _dedicated_forks; -extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL); +extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr); static FVideoDriver_Dedicated iFVideoDriver_Dedicated; @@ -142,7 +138,7 @@ static FVideoDriver_Dedicated iFVideoDriver_Dedicated; const char *VideoDriver_Dedicated::Start(const char * const *parm) { int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); - _dedicated_video_mem = (bpp == 0) ? NULL : MallocT(_cur_resolution.width * _cur_resolution.height * (bpp / 8)); + _dedicated_video_mem = (bpp == 0) ? nullptr : MallocT(_cur_resolution.width * _cur_resolution.height * (bpp / 8)); _screen.width = _screen.pitch = _cur_resolution.width; _screen.height = _cur_resolution.height; @@ -168,7 +164,7 @@ const char *VideoDriver_Dedicated::Start(const char * const *parm) #endif DEBUG(driver, 1, "Loading dedicated server"); - return NULL; + return nullptr; } void VideoDriver_Dedicated::Stop() @@ -196,14 +192,14 @@ static bool InputWaiting() FD_SET(STDIN, &readfds); /* don't care about writefds and exceptfds: */ - return select(STDIN + 1, &readfds, NULL, NULL, &tv) > 0; + return select(STDIN + 1, &readfds, nullptr, nullptr, &tv) > 0; } static uint32 GetTime() { struct timeval tim; - gettimeofday(&tim, NULL); + gettimeofday(&tim, nullptr); return tim.tv_usec / 1000 + tim.tv_sec * 1000; } @@ -230,7 +226,7 @@ static void DedicatedHandleKeyInput() if (_exit_game) return; #if defined(UNIX) || defined(__OS2__) - if (fgets(input_line, lengthof(input_line), stdin) == NULL) return; + if (fgets(input_line, lengthof(input_line), stdin) == nullptr) return; #else /* Handle console input, and signal console thread, it can accept input again */ assert_compile(lengthof(_win_console_thread_buffer) <= lengthof(input_line)); @@ -320,5 +316,3 @@ void VideoDriver_Dedicated::MainLoop() } } } - -#endif /* ENABLE_NETWORK */ diff --git a/src/video/dedicated_v.h b/src/video/dedicated_v.h index 0c1477d66d..bdf873c3d7 100644 --- a/src/video/dedicated_v.h +++ b/src/video/dedicated_v.h @@ -17,19 +17,19 @@ /** The dedicated server video driver. */ class VideoDriver_Dedicated : public VideoDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void MakeDirty(int left, int top, int width, int height); + void MakeDirty(int left, int top, int width, int height) override; - /* virtual */ void MainLoop(); + void MainLoop() override; - /* virtual */ bool ChangeResolution(int w, int h); + bool ChangeResolution(int w, int h) override; - /* virtual */ bool ToggleFullscreen(bool fullscreen); - /* virtual */ const char *GetName() const { return "dedicated"; } - /* virtual */ bool HasGUI() const { return false; } + bool ToggleFullscreen(bool fullscreen) override; + const char *GetName() const override { return "dedicated"; } + bool HasGUI() const override { return false; } }; /** Factory for the dedicated server video driver. */ @@ -43,7 +43,7 @@ public: static const int PRIORITY = 0; #endif FVideoDriver_Dedicated() : DriverFactoryBase(Driver::DT_VIDEO, PRIORITY, "dedicated", "Dedicated Video Driver") {} - /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Dedicated(); } + Driver *CreateInstance() const override { return new VideoDriver_Dedicated(); } }; #endif /* VIDEO_DEDICATED_H */ diff --git a/src/video/null_v.cpp b/src/video/null_v.cpp index 5037814e5b..4ee2d05ceb 100644 --- a/src/video/null_v.cpp +++ b/src/video/null_v.cpp @@ -29,13 +29,13 @@ const char *VideoDriver_Null::Start(const char * const *parm) this->ticks = GetDriverParamInt(parm, "ticks", 1000); _screen.width = _screen.pitch = _cur_resolution.width; _screen.height = _cur_resolution.height; - _screen.dst_ptr = NULL; + _screen.dst_ptr = nullptr; ScreenSizeChanged(); /* Do not render, nor blit */ DEBUG(misc, 1, "Forcing blitter 'null'..."); BlitterFactory::SelectBlitter("null"); - return NULL; + return nullptr; } void VideoDriver_Null::Stop() { } diff --git a/src/video/null_v.h b/src/video/null_v.h index 9e04e177ef..a3b2cb5a81 100644 --- a/src/video/null_v.h +++ b/src/video/null_v.h @@ -20,26 +20,26 @@ private: uint ticks; ///< Amount of ticks to run. public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void MakeDirty(int left, int top, int width, int height); + void MakeDirty(int left, int top, int width, int height) override; - /* virtual */ void MainLoop(); + void MainLoop() override; - /* virtual */ bool ChangeResolution(int w, int h); + bool ChangeResolution(int w, int h) override; - /* virtual */ bool ToggleFullscreen(bool fullscreen); - /* virtual */ const char *GetName() const { return "null"; } - /* virtual */ bool HasGUI() const { return false; } + bool ToggleFullscreen(bool fullscreen) override; + const char *GetName() const override { return "null"; } + bool HasGUI() const override { return false; } }; /** Factory the null video driver. */ class FVideoDriver_Null : public DriverFactoryBase { public: FVideoDriver_Null() : DriverFactoryBase(Driver::DT_VIDEO, 0, "null", "Null Video Driver") {} - /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Null(); } + Driver *CreateInstance() const override { return new VideoDriver_Null(); } }; #endif /* VIDEO_NULL_H */ diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp new file mode 100644 index 0000000000..03d05e2102 --- /dev/null +++ b/src/video/sdl2_v.cpp @@ -0,0 +1,830 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU 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 sdl2_v.cpp Implementation of the SDL2 video driver. */ + +#ifdef WITH_SDL2 + +#include "../stdafx.h" +#include "../openttd.h" +#include "../gfx_func.h" +#include "../rev.h" +#include "../blitter/factory.hpp" +#include "../network/network.h" +#include "../thread.h" +#include "../progress.h" +#include "../core/random_func.hpp" +#include "../core/math_func.hpp" +#include "../fileio_func.h" +#include "../framerate_type.h" +#include "sdl2_v.h" +#include +#include +#include +#include + +#include "../safeguards.h" + +static FVideoDriver_SDL iFVideoDriver_SDL; + +static SDL_Window *_sdl_window; +static SDL_Surface *_sdl_surface; +static SDL_Surface *_sdl_realscreen; + +/** Whether the drawing is/may be done in a separate thread. */ +static bool _draw_threaded; +/** Mutex to keep the access to the shared memory controlled. */ +static std::recursive_mutex *_draw_mutex = nullptr; +/** Signal to draw the next frame. */ +static std::condition_variable_any *_draw_signal = nullptr; +/** Should we keep continue drawing? */ +static volatile bool _draw_continue; +static Palette _local_palette; +static SDL_Palette *_sdl_palette; + +#define MAX_DIRTY_RECTS 100 +static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS]; +static int _num_dirty_rects; + +/* Size of window */ +static int _window_size_w; +static int _window_size_h; + +void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height) +{ + if (_num_dirty_rects < MAX_DIRTY_RECTS) { + _dirty_rects[_num_dirty_rects].x = left; + _dirty_rects[_num_dirty_rects].y = top; + _dirty_rects[_num_dirty_rects].w = width; + _dirty_rects[_num_dirty_rects].h = height; + } + _num_dirty_rects++; +} + +static void UpdatePalette(bool init = false) +{ + SDL_Color pal[256]; + + for (int i = 0; i != _local_palette.count_dirty; i++) { + pal[i].r = _local_palette.palette[_local_palette.first_dirty + i].r; + pal[i].g = _local_palette.palette[_local_palette.first_dirty + i].g; + pal[i].b = _local_palette.palette[_local_palette.first_dirty + i].b; + pal[i].a = 0; + } + + SDL_SetPaletteColors(_sdl_palette, pal, _local_palette.first_dirty, _local_palette.count_dirty); + SDL_SetSurfacePalette(_sdl_surface, _sdl_palette); + + if (_sdl_surface != _sdl_realscreen && init) { + /* When using a shadow surface, also set our palette on the real screen. This lets SDL + * allocate as many colors (or approximations) as + * possible, instead of using only the default SDL + * palette. This allows us to get more colors exactly + * right and might allow using better approximations for + * other colors. + * + * Note that colors allocations are tried in-order, so + * this favors colors further up into the palette. Also + * note that if two colors from the same animation + * sequence are approximated using the same color, that + * animation will stop working. + * + * Since changing the system palette causes the colours + * to change right away, and allocations might + * drastically change, we can't use this for animation, + * since that could cause weird coloring between the + * palette change and the blitting below, so we only set + * the real palette during initialisation. + */ + SDL_SetSurfacePalette(_sdl_realscreen, _sdl_palette); + } + + if (_sdl_surface != _sdl_realscreen && !init) { + /* We're not using real hardware palette, but are letting SDL + * approximate the palette during shadow -> screen copy. To + * change the palette, we need to recopy the entire screen. + * + * Note that this operation can slow down the rendering + * considerably, especially since changing the shadow + * palette will need the next blit to re-detect the + * best mapping of shadow palette colors to real palette + * colors from scratch. + */ + SDL_BlitSurface(_sdl_surface, nullptr, _sdl_realscreen, nullptr); + SDL_UpdateWindowSurface(_sdl_window); + } +} + +static void InitPalette() +{ + _local_palette = _cur_palette; + _local_palette.first_dirty = 0; + _local_palette.count_dirty = 256; + UpdatePalette(true); +} + +static void CheckPaletteAnim() +{ + if (_cur_palette.count_dirty != 0) { + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + + switch (blitter->UsePaletteAnimation()) { + case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: + UpdatePalette(); + break; + + case Blitter::PALETTE_ANIMATION_BLITTER: + blitter->PaletteAnimate(_local_palette); + break; + + case Blitter::PALETTE_ANIMATION_NONE: + break; + + default: + NOT_REACHED(); + } + _cur_palette.count_dirty = 0; + } +} + +static void DrawSurfaceToScreen() +{ + PerformanceMeasurer framerate(PFE_VIDEO); + + int n = _num_dirty_rects; + if (n == 0) return; + + _num_dirty_rects = 0; + + if (n > MAX_DIRTY_RECTS) { + if (_sdl_surface != _sdl_realscreen) { + SDL_BlitSurface(_sdl_surface, nullptr, _sdl_realscreen, nullptr); + } + + SDL_UpdateWindowSurface(_sdl_window); + } else { + if (_sdl_surface != _sdl_realscreen) { + for (int i = 0; i < n; i++) { + SDL_BlitSurface( + _sdl_surface, &_dirty_rects[i], + _sdl_realscreen, &_dirty_rects[i]); + } + } + + SDL_UpdateWindowSurfaceRects(_sdl_window, _dirty_rects, n); + } +} + +static void DrawSurfaceToScreenThread() +{ + /* First tell the main thread we're started */ + std::unique_lock lock(*_draw_mutex); + _draw_signal->notify_one(); + + /* Now wait for the first thing to draw! */ + _draw_signal->wait(*_draw_mutex); + + while (_draw_continue) { + CheckPaletteAnim(); + /* Then just draw and wait till we stop */ + DrawSurfaceToScreen(); + _draw_signal->wait(lock); + } +} + +static void GetVideoModes() +{ + int modes = SDL_GetNumDisplayModes(0); + if (modes == 0) usererror("sdl: no modes available"); + + _resolutions.clear(); + + SDL_DisplayMode mode; + for (int i = 0; i < modes; i++) { + SDL_GetDisplayMode(0, i, &mode); + + uint w = mode.w; + uint h = mode.h; + + if (w < 640 || h < 480) continue; // reject too small resolutions + + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(w, h)) != _resolutions.end()) continue; + _resolutions.emplace_back(w, h); + } + if (_resolutions.empty()) usererror("No usable screen resolutions found!\n"); + SortResolutions(); +} + +static void GetAvailableVideoMode(uint *w, uint *h) +{ + /* All modes available? */ + if (!_fullscreen || _resolutions.empty()) return; + + /* Is the wanted mode among the available modes? */ + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(*w, *h)) != _resolutions.end()) return; + + /* Use the closest possible resolution */ + uint best = 0; + uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); + for (uint i = 1; i != _resolutions.size(); ++i) { + uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); + if (newdelta < delta) { + best = i; + delta = newdelta; + } + } + *w = _resolutions[best].width; + *h = _resolutions[best].height; +} + +bool VideoDriver_SDL::CreateMainSurface(uint w, uint h, bool resize) +{ + SDL_Surface *newscreen; + char caption[50]; + int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); + + GetAvailableVideoMode(&w, &h); + + DEBUG(driver, 1, "SDL2: using mode %ux%ux%d", w, h, bpp); + + if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); + + /* Free any previously allocated shadow surface */ + if (_sdl_surface != nullptr && _sdl_surface != _sdl_realscreen) SDL_FreeSurface(_sdl_surface); + + seprintf(caption, lastof(caption), "OpenTTD %s", _openttd_revision); + + if (_sdl_window == nullptr) { + Uint32 flags = SDL_WINDOW_SHOWN; + + if (_fullscreen) { + flags |= SDL_WINDOW_FULLSCREEN; + } else { + flags |= SDL_WINDOW_RESIZABLE; + } + + _sdl_window = SDL_CreateWindow( + caption, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + w, h, + flags); + + if (_sdl_window == nullptr) { + DEBUG(driver, 0, "SDL2: Couldn't allocate a window to draw on"); + return false; + } + + char icon_path[MAX_PATH]; + if (FioFindFullPath(icon_path, lastof(icon_path), BASESET_DIR, "openttd.32.bmp") != nullptr) { + /* Give the application an icon */ + SDL_Surface *icon = SDL_LoadBMP(icon_path); + if (icon != nullptr) { + /* Get the colourkey, which will be magenta */ + uint32 rgbmap = SDL_MapRGB(icon->format, 255, 0, 255); + + SDL_SetColorKey(icon, SDL_TRUE, rgbmap); + SDL_SetWindowIcon(_sdl_window, icon); + SDL_FreeSurface(icon); + } + } + } + + if (resize) SDL_SetWindowSize(_sdl_window, w, h); + + newscreen = SDL_GetWindowSurface(_sdl_window); + if (newscreen == NULL) { + DEBUG(driver, 0, "SDL2: Couldn't get window surface: %s", SDL_GetError()); + return false; + } + + _sdl_realscreen = newscreen; + + if (bpp == 8) { + newscreen = SDL_CreateRGBSurface(0, w, h, 8, 0, 0, 0, 0); + + if (newscreen == nullptr) { + DEBUG(driver, 0, "SDL2: Couldn't allocate shadow surface: %s", SDL_GetError()); + return false; + } + } + + if (_sdl_palette == nullptr) { + _sdl_palette = SDL_AllocPalette(256); + } + + if (_sdl_palette == nullptr) { + DEBUG(driver, 0, "SDL_AllocPalette() failed: %s", SDL_GetError()); + return false; + } + + /* Delay drawing for this cycle; the next cycle will redraw the whole screen */ + _num_dirty_rects = 0; + + _screen.width = newscreen->w; + _screen.height = newscreen->h; + _screen.pitch = newscreen->pitch / (bpp / 8); + _screen.dst_ptr = newscreen->pixels; + _sdl_surface = newscreen; + + /* When in full screen, we will always have the mouse cursor + * within the window, even though SDL does not give us the + * appropriate event to know this. */ + if (_fullscreen) _cursor.in_window = true; + + Blitter *blitter = BlitterFactory::GetCurrentBlitter(); + blitter->PostResize(); + + InitPalette(); + + GameSizeChanged(); + + return true; +} + +bool VideoDriver_SDL::ClaimMousePointer() +{ + SDL_ShowCursor(0); + return true; +} + +struct VkMapping { + SDL_Keycode vk_from; + byte vk_count; + byte map_to; +}; + +#define AS(x, z) {x, 0, z} +#define AM(x, y, z, w) {x, (byte)(y - x), z} + +static const VkMapping _vk_mapping[] = { + /* Pageup stuff + up/down */ + AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN), + AS(SDLK_UP, WKC_UP), + AS(SDLK_DOWN, WKC_DOWN), + AS(SDLK_LEFT, WKC_LEFT), + AS(SDLK_RIGHT, WKC_RIGHT), + + AS(SDLK_HOME, WKC_HOME), + AS(SDLK_END, WKC_END), + + AS(SDLK_INSERT, WKC_INSERT), + AS(SDLK_DELETE, WKC_DELETE), + + /* Map letters & digits */ + AM(SDLK_a, SDLK_z, 'A', 'Z'), + AM(SDLK_0, SDLK_9, '0', '9'), + + AS(SDLK_ESCAPE, WKC_ESC), + AS(SDLK_PAUSE, WKC_PAUSE), + AS(SDLK_BACKSPACE, WKC_BACKSPACE), + + AS(SDLK_SPACE, WKC_SPACE), + AS(SDLK_RETURN, WKC_RETURN), + AS(SDLK_TAB, WKC_TAB), + + /* Function keys */ + AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12), + + /* Numeric part. */ + AM(SDLK_KP_0, SDLK_KP_9, '0', '9'), + AS(SDLK_KP_DIVIDE, WKC_NUM_DIV), + AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL), + AS(SDLK_KP_MINUS, WKC_NUM_MINUS), + AS(SDLK_KP_PLUS, WKC_NUM_PLUS), + AS(SDLK_KP_ENTER, WKC_NUM_ENTER), + AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL), + + /* Other non-letter keys */ + AS(SDLK_SLASH, WKC_SLASH), + AS(SDLK_SEMICOLON, WKC_SEMICOLON), + AS(SDLK_EQUALS, WKC_EQUALS), + AS(SDLK_LEFTBRACKET, WKC_L_BRACKET), + AS(SDLK_BACKSLASH, WKC_BACKSLASH), + AS(SDLK_RIGHTBRACKET, WKC_R_BRACKET), + + AS(SDLK_QUOTE, WKC_SINGLEQUOTE), + AS(SDLK_COMMA, WKC_COMMA), + AS(SDLK_MINUS, WKC_MINUS), + AS(SDLK_PERIOD, WKC_PERIOD) +}; + +static uint ConvertSdlKeyIntoMy(SDL_Keysym *sym, WChar *character) +{ + const VkMapping *map; + uint key = 0; + + for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { + if ((uint)(sym->sym - map->vk_from) <= map->vk_count) { + key = sym->sym - map->vk_from + map->map_to; + break; + } + } + + /* check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards) */ +#if defined(_WIN32) || defined(__OS2__) + if (sym->scancode == 41) key = WKC_BACKQUOTE; +#elif defined(__APPLE__) + if (sym->scancode == 10) key = WKC_BACKQUOTE; +#elif defined(__SVR4) && defined(__sun) + if (sym->scancode == 60) key = WKC_BACKQUOTE; + if (sym->scancode == 49) key = WKC_BACKSPACE; +#elif defined(__sgi__) + if (sym->scancode == 22) key = WKC_BACKQUOTE; +#else + if (sym->scancode == 49) key = WKC_BACKQUOTE; +#endif + + /* META are the command keys on mac */ + if (sym->mod & KMOD_GUI) key |= WKC_META; + if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT; + if (sym->mod & KMOD_CTRL) key |= WKC_CTRL; + if (sym->mod & KMOD_ALT) key |= WKC_ALT; + + /* The mod keys have no character. Prevent '?' */ + if (sym->mod & KMOD_GUI || + sym->mod & KMOD_SHIFT || + sym->mod & KMOD_CTRL || + sym->mod & KMOD_ALT) { + *character = WKC_NONE; + } else { + *character = sym->sym; + } + + return key; +} + +/** + * Like ConvertSdlKeyIntoMy(), but takes an SDL_Keycode as input + * instead of an SDL_Keysym. + */ +static uint ConvertSdlKeycodeIntoMy(SDL_Keycode kc) +{ + const VkMapping *map; + uint key = 0; + + for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { + if ((uint)(kc - map->vk_from) <= map->vk_count) { + key = kc - map->vk_from + map->map_to; + break; + } + } + + /* check scancode for BACKQUOTE key, because we want the key left + of "1", not anything else (on non-US keyboards) */ + SDL_Scancode sc = SDL_GetScancodeFromKey(kc); + if (sc == SDL_SCANCODE_GRAVE) key = WKC_BACKQUOTE; + + return key; +} + +int VideoDriver_SDL::PollEvent() +{ + SDL_Event ev; + + if (!SDL_PollEvent(&ev)) return -2; + + switch (ev.type) { + case SDL_MOUSEMOTION: + if (_cursor.UpdateCursorPosition(ev.motion.x, ev.motion.y, true)) { + SDL_WarpMouseInWindow(_sdl_window, _cursor.pos.x, _cursor.pos.y); + } + HandleMouseEvents(); + break; + + case SDL_MOUSEWHEEL: + if (ev.wheel.y > 0) { + _cursor.wheel--; + } else if (ev.wheel.y < 0) { + _cursor.wheel++; + } + break; + + case SDL_MOUSEBUTTONDOWN: + if (_rightclick_emulate && SDL_GetModState() & KMOD_CTRL) { + ev.button.button = SDL_BUTTON_RIGHT; + } + + switch (ev.button.button) { + case SDL_BUTTON_LEFT: + _left_button_down = true; + break; + + case SDL_BUTTON_RIGHT: + _right_button_down = true; + _right_button_clicked = true; + break; + + default: break; + } + HandleMouseEvents(); + break; + + case SDL_MOUSEBUTTONUP: + if (_rightclick_emulate) { + _right_button_down = false; + _left_button_down = false; + _left_button_clicked = false; + } else if (ev.button.button == SDL_BUTTON_LEFT) { + _left_button_down = false; + _left_button_clicked = false; + } else if (ev.button.button == SDL_BUTTON_RIGHT) { + _right_button_down = false; + } + HandleMouseEvents(); + break; + + case SDL_QUIT: + HandleExitGameRequest(); + break; + + case SDL_KEYDOWN: // Toggle full-screen on ALT + ENTER/F + if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_GUI)) && + (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) { + if (ev.key.repeat == 0) ToggleFullScreen(!_fullscreen); + } else { + WChar character; + + uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character); + // Only handle non-text keys here. Text is handled in + // SDL_TEXTINPUT below. + if (keycode == WKC_DELETE || + keycode == WKC_NUM_ENTER || + keycode == WKC_LEFT || + keycode == WKC_RIGHT || + keycode & WKC_META || + keycode & WKC_SHIFT || + keycode & WKC_CTRL || + keycode & WKC_ALT || + (keycode >= WKC_F1 && keycode <= WKC_F12) || + !IsValidChar(character, CS_ALPHANUMERAL)) { + HandleKeypress(keycode, character); + } + } + break; + + case SDL_TEXTINPUT: { + WChar character; + SDL_Keycode kc = SDL_GetKeyFromName(ev.text.text); + uint keycode = ConvertSdlKeycodeIntoMy(kc); + + Utf8Decode(&character, ev.text.text); + HandleKeypress(keycode, character); + break; + } + case SDL_WINDOWEVENT: { + if (ev.window.event == SDL_WINDOWEVENT_EXPOSED) { + // Force a redraw of the entire screen. + _num_dirty_rects = MAX_DIRTY_RECTS + 1; + } else if (ev.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + int w = max(ev.window.data1, 64); + int h = max(ev.window.data2, 64); + CreateMainSurface(w, h, w != ev.window.data1 || h != ev.window.data2); + } else if (ev.window.event == SDL_WINDOWEVENT_ENTER) { + // mouse entered the window, enable cursor + _cursor.in_window = true; + } else if (ev.window.event == SDL_WINDOWEVENT_LEAVE) { + // mouse left the window, undraw cursor + UndrawMouseCursor(); + _cursor.in_window = false; + } + break; + } + } + return -1; +} + +const char *VideoDriver_SDL::Start(const char * const *parm) +{ + /* Explicitly disable hardware acceleration. Enabling this causes + * UpdateWindowSurface() to update the window's texture instead of + * its surface. */ + SDL_SetHint(SDL_HINT_FRAMEBUFFER_ACCELERATION , "0"); + + /* Just on the offchance the audio subsystem started before the video system, + * check whether any part of SDL has been initialised before getting here. + * Slightly duplicated with sound/sdl_s.cpp */ + int ret_code = 0; + if (SDL_WasInit(SDL_INIT_VIDEO) == 0) { + ret_code = SDL_InitSubSystem(SDL_INIT_VIDEO); + } + if (ret_code < 0) return SDL_GetError(); + + GetVideoModes(); + if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height, false)) { + return SDL_GetError(); + } + + const char *dname = SDL_GetVideoDriver(0); + DEBUG(driver, 1, "SDL2: using driver '%s'", dname); + + MarkWholeScreenDirty(); + + _draw_threaded = GetDriverParam(parm, "no_threads") == nullptr && GetDriverParam(parm, "no_thread") == nullptr; + + return nullptr; +} + +void VideoDriver_SDL::Stop() +{ + SDL_QuitSubSystem(SDL_INIT_VIDEO); + if (SDL_WasInit(SDL_INIT_EVERYTHING) == 0) { + SDL_Quit(); // If there's nothing left, quit SDL + } +} + +void VideoDriver_SDL::MainLoop() +{ + uint32 cur_ticks = SDL_GetTicks(); + uint32 last_cur_ticks = cur_ticks; + uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; + uint32 mod; + int numkeys; + const Uint8 *keys; + + CheckPaletteAnim(); + + std::thread draw_thread; + std::unique_lock draw_lock; + if (_draw_threaded) { + /* Initialise the mutex first, because that's the thing we *need* + * directly in the newly created thread. */ + _draw_mutex = new std::recursive_mutex(); + if (_draw_mutex == nullptr) { + _draw_threaded = false; + } else { + draw_lock = std::unique_lock(*_draw_mutex); + _draw_signal = new std::condition_variable_any(); + _draw_continue = true; + + _draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &DrawSurfaceToScreenThread); + + /* Free the mutex if we won't be able to use it. */ + if (!_draw_threaded) { + draw_lock.unlock(); + draw_lock.release(); + delete _draw_mutex; + delete _draw_signal; + _draw_mutex = nullptr; + _draw_signal = nullptr; + } else { + /* Wait till the draw mutex has started itself. */ + _draw_signal->wait(*_draw_mutex); + } + } + } + + DEBUG(driver, 1, "SDL2: using %sthreads", _draw_threaded ? "" : "no "); + + for (;;) { + uint32 prev_cur_ticks = cur_ticks; // to check for wrapping + InteractiveRandom(); // randomness + + while (PollEvent() == -1) {} + if (_exit_game) break; + + mod = SDL_GetModState(); + keys = SDL_GetKeyboardState(&numkeys); + +#if defined(_DEBUG) + if (_shift_pressed) +#else + /* Speedup when pressing tab, except when using ALT+TAB + * to switch to another application */ + if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0) +#endif /* defined(_DEBUG) */ + { + if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; + } else if (_fast_forward & 2) { + _fast_forward = 0; + } + + cur_ticks = SDL_GetTicks(); + if (SDL_TICKS_PASSED(cur_ticks, next_tick) || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { + _realtime_tick += cur_ticks - last_cur_ticks; + last_cur_ticks = cur_ticks; + next_tick = cur_ticks + MILLISECONDS_PER_TICK; + + bool old_ctrl_pressed = _ctrl_pressed; + + _ctrl_pressed = !!(mod & KMOD_CTRL); + _shift_pressed = !!(mod & KMOD_SHIFT); + + /* determine which directional keys are down */ + _dirkeys = + (keys[SDL_SCANCODE_LEFT] ? 1 : 0) | + (keys[SDL_SCANCODE_UP] ? 2 : 0) | + (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) | + (keys[SDL_SCANCODE_DOWN] ? 8 : 0); + if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); + + /* The gameloop is the part that can run asynchronously. The rest + * except sleeping can't. */ + if (_draw_mutex != nullptr) draw_lock.unlock(); + + GameLoop(); + + if (_draw_mutex != nullptr) draw_lock.lock(); + + UpdateWindows(); + _local_palette = _cur_palette; + } else { + /* Release the thread while sleeping */ + if (_draw_mutex != nullptr) draw_lock.unlock(); + CSleep(1); + if (_draw_mutex != nullptr) draw_lock.lock(); + + NetworkDrawChatMessage(); + DrawMouseCursor(); + } + + /* End of the critical part. */ + if (_draw_mutex != nullptr && !HasModalProgress()) { + _draw_signal->notify_one(); + } else { + /* Oh, we didn't have threads, then just draw unthreaded */ + CheckPaletteAnim(); + DrawSurfaceToScreen(); + } + } + + if (_draw_mutex != nullptr) { + _draw_continue = false; + /* Sending signal if there is no thread blocked + * is very valid and results in noop */ + _draw_signal->notify_one(); + if (draw_lock.owns_lock()) draw_lock.unlock(); + draw_lock.release(); + draw_thread.join(); + + delete _draw_mutex; + delete _draw_signal; + + _draw_mutex = nullptr; + _draw_signal = nullptr; + } +} + +bool VideoDriver_SDL::ChangeResolution(int w, int h) +{ + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + + return CreateMainSurface(w, h, true); +} + +bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) +{ + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + + /* Remember current window size */ + if (fullscreen) { + SDL_GetWindowSize(_sdl_window, &_window_size_w, &_window_size_h); + + /* Find fullscreen window size */ + SDL_DisplayMode dm; + if (SDL_GetCurrentDisplayMode(0, &dm) < 0) { + DEBUG(driver, 0, "SDL_GetCurrentDisplayMode() failed: %s", SDL_GetError()); + } else { + SDL_SetWindowSize(_sdl_window, dm.w, dm.h); + } + } + + DEBUG(driver, 1, "SDL2: Setting %s", fullscreen ? "fullscreen" : "windowed"); + int ret = SDL_SetWindowFullscreen(_sdl_window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0); + if (ret == 0) { + /* Switching resolution succeeded, set fullscreen value of window. */ + _fullscreen = fullscreen; + if (!fullscreen) SDL_SetWindowSize(_sdl_window, _window_size_w, _window_size_h); + } else { + DEBUG(driver, 0, "SDL_SetWindowFullscreen() failed: %s", SDL_GetError()); + } + + return ret == 0; +} + +bool VideoDriver_SDL::AfterBlitterChange() +{ + int w, h; + SDL_GetWindowSize(_sdl_window, &w, &h); + return CreateMainSurface(w, h, false); +} + +void VideoDriver_SDL::AcquireBlitterLock() +{ + if (_draw_mutex != nullptr) _draw_mutex->lock(); +} + +void VideoDriver_SDL::ReleaseBlitterLock() +{ + if (_draw_mutex != nullptr) _draw_mutex->unlock(); +} + +#endif /* WITH_SDL2 */ diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h new file mode 100644 index 0000000000..ba7e322ed3 --- /dev/null +++ b/src/video/sdl2_v.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 sdl2_v.h Base of the SDL2 video driver. */ + +#ifndef VIDEO_SDL_H +#define VIDEO_SDL_H + +#include "video_driver.hpp" + +/** The SDL video driver. */ +class VideoDriver_SDL : public VideoDriver { +public: + const char *Start(const char * const *param) override; + + void Stop() override; + + void MakeDirty(int left, int top, int width, int height) override; + + void MainLoop() override; + + bool ChangeResolution(int w, int h) override; + + bool ToggleFullscreen(bool fullscreen) override; + + bool AfterBlitterChange() override; + + void AcquireBlitterLock() override; + + void ReleaseBlitterLock() override; + + bool ClaimMousePointer() override; + + const char *GetName() const override { return "sdl"; } +private: + int PollEvent(); + bool CreateMainSurface(uint w, uint h, bool resize); +}; + +/** Factory for the SDL video driver. */ +class FVideoDriver_SDL : public DriverFactoryBase { +public: + FVideoDriver_SDL() : DriverFactoryBase(Driver::DT_VIDEO, 5, "sdl", "SDL Video Driver") {} + Driver *CreateInstance() const override { return new VideoDriver_SDL(); } +}; + +#endif /* VIDEO_SDL_H */ diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index a81a9828cd..905f75daac 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -17,7 +17,7 @@ #include "../rev.h" #include "../blitter/factory.hpp" #include "../network/network.h" -#include "../thread/thread.h" +#include "../thread.h" #include "../progress.h" #include "../core/random_func.hpp" #include "../core/math_func.hpp" @@ -25,6 +25,9 @@ #include "../framerate_type.h" #include "sdl_v.h" #include +#include +#include +#include #include "../safeguards.h" @@ -36,10 +39,10 @@ static bool _all_modes; /** Whether the drawing is/may be done in a separate thread. */ static bool _draw_threaded; -/** Thread used to 'draw' to the screen, i.e. push data to the screen. */ -static ThreadObject *_draw_thread = NULL; /** Mutex to keep the access to the shared memory controlled. */ -static ThreadMutex *_draw_mutex = NULL; +static std::recursive_mutex *_draw_mutex = nullptr; +/** Signal to draw the next frame. */ +static std::condition_variable_any *_draw_signal = nullptr; /** Should we keep continue drawing? */ static volatile bool _draw_continue; static Palette _local_palette; @@ -109,7 +112,7 @@ static void UpdatePalette(bool init = false) * best mapping of shadow palette colors to real palette * colors from scratch. */ - SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); + SDL_BlitSurface(_sdl_screen, nullptr, _sdl_realscreen, nullptr); SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); } } @@ -156,7 +159,7 @@ static void DrawSurfaceToScreen() _num_dirty_rects = 0; if (n > MAX_DIRTY_RECTS) { if (_sdl_screen != _sdl_realscreen) { - SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); + SDL_BlitSurface(_sdl_screen, nullptr, _sdl_realscreen, nullptr); } SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); } else { @@ -169,24 +172,21 @@ static void DrawSurfaceToScreen() } } -static void DrawSurfaceToScreenThread(void *) +static void DrawSurfaceToScreenThread() { /* First tell the main thread we're started */ - _draw_mutex->BeginCritical(); - _draw_mutex->SendSignal(); + std::unique_lock lock(*_draw_mutex); + _draw_signal->notify_one(); /* Now wait for the first thing to draw! */ - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); while (_draw_continue) { CheckPaletteAnim(); /* Then just draw and wait till we stop */ DrawSurfaceToScreen(); - _draw_mutex->WaitForSignal(); + _draw_signal->wait(lock); } - - _draw_mutex->EndCritical(); - _draw_thread->Exit(); } static const Dimension _default_resolutions[] = { @@ -205,54 +205,43 @@ static const Dimension _default_resolutions[] = { static void GetVideoModes() { - SDL_Rect **modes = SDL_ListModes(NULL, SDL_SWSURFACE | SDL_FULLSCREEN); - if (modes == NULL) usererror("sdl: no modes available"); + SDL_Rect **modes = SDL_ListModes(nullptr, SDL_SWSURFACE | SDL_FULLSCREEN); + if (modes == nullptr) usererror("sdl: no modes available"); - _all_modes = (SDL_ListModes(NULL, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (void*)-1); + _resolutions.clear(); + + _all_modes = (SDL_ListModes(nullptr, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (void*)-1); if (modes == (void*)-1) { - int n = 0; for (uint i = 0; i < lengthof(_default_resolutions); i++) { if (SDL_VideoModeOK(_default_resolutions[i].width, _default_resolutions[i].height, 8, SDL_FULLSCREEN) != 0) { - _resolutions[n] = _default_resolutions[i]; - if (++n == lengthof(_resolutions)) break; + _resolutions.push_back(_default_resolutions[i]); } } - _num_resolutions = n; } else { - int n = 0; for (int i = 0; modes[i]; i++) { uint w = modes[i]->w; uint h = modes[i]->h; - int j; - for (j = 0; j < n; j++) { - if (_resolutions[j].width == w && _resolutions[j].height == h) break; - } - - if (j == n) { - _resolutions[j].width = w; - _resolutions[j].height = h; - if (++n == lengthof(_resolutions)) break; - } + if (w < 640 || h < 480) continue; // reject too small resolutions + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(w, h)) != _resolutions.end()) continue; + _resolutions.emplace_back(w, h); } - _num_resolutions = n; - SortResolutions(_num_resolutions); + if (_resolutions.empty()) usererror("No usable screen resolutions found!\n"); + SortResolutions(); } } static void GetAvailableVideoMode(uint *w, uint *h) { /* All modes available? */ - if (_all_modes || _num_resolutions == 0) return; + if (_all_modes || _resolutions.empty()) return; /* Is the wanted mode among the available modes? */ - for (int i = 0; i != _num_resolutions; i++) { - if (*w == _resolutions[i].width && *h == _resolutions[i].height) return; - } + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(*w, *h)) != _resolutions.end()) return; /* Use the closest possible resolution */ - int best = 0; + uint best = 0; uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); - for (int i = 1; i != _num_resolutions; ++i) { + for (uint i = 1; i != _resolutions.size(); ++i) { uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); if (newdelta < delta) { best = i; @@ -277,15 +266,15 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); char icon_path[MAX_PATH]; - if (FioFindFullPath(icon_path, lastof(icon_path), BASESET_DIR, "openttd.32.bmp") != NULL) { + if (FioFindFullPath(icon_path, lastof(icon_path), BASESET_DIR, "openttd.32.bmp") != nullptr) { /* Give the application an icon */ icon = SDL_LoadBMP(icon_path); - if (icon != NULL) { + if (icon != nullptr) { /* Get the colourkey, which will be magenta */ uint32 rgbmap = SDL_MapRGB(icon->format, 255, 0, 255); SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap); - SDL_WM_SetIcon(icon, NULL); + SDL_WM_SetIcon(icon, nullptr); SDL_FreeSurface(icon); } } @@ -321,9 +310,9 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) if (want_hwpalette) DEBUG(driver, 1, "SDL: requesting hardware palette"); /* Free any previously allocated shadow surface */ - if (_sdl_screen != NULL && _sdl_screen != _sdl_realscreen) SDL_FreeSurface(_sdl_screen); + if (_sdl_screen != nullptr && _sdl_screen != _sdl_realscreen) SDL_FreeSurface(_sdl_screen); - if (_sdl_realscreen != NULL) { + if (_sdl_realscreen != nullptr) { if (_requested_hwpalette != want_hwpalette) { /* SDL (at least the X11 driver), reuses the * same window and palette settings when the bpp @@ -348,7 +337,7 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) /* DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK */ newscreen = SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); - if (newscreen == NULL) { + if (newscreen == nullptr) { DEBUG(driver, 0, "SDL: Couldn't allocate a window to draw on"); return false; } @@ -375,7 +364,7 @@ bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) */ DEBUG(driver, 1, "SDL: using shadow surface"); newscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0); - if (newscreen == NULL) { + if (newscreen == nullptr) { DEBUG(driver, 0, "SDL: Couldn't allocate a shadow surface to draw on"); return false; } @@ -504,10 +493,6 @@ static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character) if (sym->scancode == 41) key = WKC_BACKQUOTE; #elif defined(__APPLE__) if (sym->scancode == 10) key = WKC_BACKQUOTE; -#elif defined(__MORPHOS__) - if (sym->scancode == 0) key = WKC_BACKQUOTE; // yes, that key is code '0' under MorphOS :) -#elif defined(__BEOS__) - if (sym->scancode == 17) key = WKC_BACKQUOTE; #elif defined(__SVR4) && defined(__sun) if (sym->scancode == 60) key = WKC_BACKQUOTE; if (sym->scancode == 49) key = WKC_BACKSPACE; @@ -648,9 +633,9 @@ const char *VideoDriver_SDL::Start(const char * const *parm) MarkWholeScreenDirty(); SetupKeyboard(); - _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL; + _draw_threaded = GetDriverParam(parm, "no_threads") == nullptr && GetDriverParam(parm, "no_thread") == nullptr; - return NULL; + return nullptr; } void VideoDriver_SDL::SetupKeyboard() @@ -678,26 +663,32 @@ void VideoDriver_SDL::MainLoop() CheckPaletteAnim(); + std::thread draw_thread; + std::unique_lock draw_lock; if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ - _draw_mutex = ThreadMutex::New(); - if (_draw_mutex == NULL) { + _draw_mutex = new std::recursive_mutex(); + if (_draw_mutex == nullptr) { _draw_threaded = false; } else { - _draw_mutex->BeginCritical(); + draw_lock = std::unique_lock(*_draw_mutex); + _draw_signal = new std::condition_variable_any(); _draw_continue = true; - _draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread, "ottd:draw-sdl"); + _draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &DrawSurfaceToScreenThread); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { - _draw_mutex->EndCritical(); + draw_lock.unlock(); + draw_lock.release(); delete _draw_mutex; - _draw_mutex = NULL; + delete _draw_signal; + _draw_mutex = nullptr; + _draw_signal = nullptr; } else { /* Wait till the draw mutex has started itself. */ - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); } } } @@ -763,27 +754,27 @@ void VideoDriver_SDL::MainLoop() /* The gameloop is the part that can run asynchronously. The rest * except sleeping can't. */ - if (_draw_mutex != NULL) _draw_mutex->EndCritical(); + if (_draw_mutex != nullptr) draw_lock.unlock(); GameLoop(); - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); + if (_draw_mutex != nullptr) draw_lock.lock(); UpdateWindows(); _local_palette = _cur_palette; } else { /* Release the thread while sleeping */ - if (_draw_mutex != NULL) _draw_mutex->EndCritical(); + if (_draw_mutex != nullptr) draw_lock.unlock(); CSleep(1); - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); + if (_draw_mutex != nullptr) draw_lock.lock(); NetworkDrawChatMessage(); DrawMouseCursor(); } /* End of the critical part. */ - if (_draw_mutex != NULL && !HasModalProgress()) { - _draw_mutex->SendSignal(); + if (_draw_mutex != nullptr && !HasModalProgress()) { + _draw_signal->notify_one(); } else { /* Oh, we didn't have threads, then just draw unthreaded */ CheckPaletteAnim(); @@ -791,43 +782,45 @@ void VideoDriver_SDL::MainLoop() } } - if (_draw_mutex != NULL) { + if (_draw_mutex != nullptr) { _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ - _draw_mutex->SendSignal(); - _draw_mutex->EndCritical(); - _draw_thread->Join(); + _draw_signal->notify_one(); + if (draw_lock.owns_lock()) draw_lock.unlock(); + draw_lock.release(); + draw_thread.join(); delete _draw_mutex; - delete _draw_thread; + delete _draw_signal; - _draw_mutex = NULL; - _draw_thread = NULL; + _draw_mutex = nullptr; + _draw_signal = nullptr; } } bool VideoDriver_SDL::ChangeResolution(int w, int h) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - bool ret = CreateMainSurface(w, h); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + + return CreateMainSurface(w, h); } bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + _fullscreen = fullscreen; GetVideoModes(); // get the list of available video modes - bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height); + bool ret = !_resolutions.empty() && CreateMainSurface(_cur_resolution.width, _cur_resolution.height); if (!ret) { /* switching resolution failed, put back full_screen to original status */ _fullscreen ^= true; } - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } @@ -838,12 +831,12 @@ bool VideoDriver_SDL::AfterBlitterChange() void VideoDriver_SDL::AcquireBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + if (_draw_mutex != nullptr) _draw_mutex->lock(); } void VideoDriver_SDL::ReleaseBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + if (_draw_mutex != nullptr) _draw_mutex->unlock(); } #endif /* WITH_SDL */ diff --git a/src/video/sdl_v.h b/src/video/sdl_v.h index 8855c3566e..cafdbbc614 100644 --- a/src/video/sdl_v.h +++ b/src/video/sdl_v.h @@ -17,27 +17,27 @@ /** The SDL video driver. */ class VideoDriver_SDL : public VideoDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void MakeDirty(int left, int top, int width, int height); + void MakeDirty(int left, int top, int width, int height) override; - /* virtual */ void MainLoop(); + void MainLoop() override; - /* virtual */ bool ChangeResolution(int w, int h); + bool ChangeResolution(int w, int h) override; - /* virtual */ bool ToggleFullscreen(bool fullscreen); + bool ToggleFullscreen(bool fullscreen) override; - /* virtual */ bool AfterBlitterChange(); + bool AfterBlitterChange() override; - /* virtual */ void AcquireBlitterLock(); + void AcquireBlitterLock() override; - /* virtual */ void ReleaseBlitterLock(); + void ReleaseBlitterLock() override; - /* virtual */ bool ClaimMousePointer(); + bool ClaimMousePointer() override; - /* virtual */ const char *GetName() const { return "sdl"; } + const char *GetName() const override { return "sdl"; } private: int PollEvent(); bool CreateMainSurface(uint w, uint h); @@ -48,7 +48,7 @@ private: class FVideoDriver_SDL : public DriverFactoryBase { public: FVideoDriver_SDL() : DriverFactoryBase(Driver::DT_VIDEO, 5, "sdl", "SDL Video Driver") {} - /* virtual */ Driver *CreateInstance() const { return new VideoDriver_SDL(); } + Driver *CreateInstance() const override { return new VideoDriver_SDL(); } }; #endif /* VIDEO_SDL_H */ diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp index 5cb3c6cc3f..b774c7ba6e 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -14,6 +14,7 @@ #include "../driver.h" #include "../core/geometry_type.hpp" +#include /** The base of all video drivers. */ class VideoDriver : public Driver { @@ -101,8 +102,7 @@ public: }; extern char *_ini_videodriver; -extern int _num_resolutions; -extern Dimension _resolutions[32]; +extern std::vector _resolutions; extern Dimension _cur_resolution; extern bool _rightclick_emulate; diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 0ffe2669d4..388a1ade06 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -19,7 +19,7 @@ #include "../core/math_func.hpp" #include "../core/random_func.hpp" #include "../texteff.hpp" -#include "../thread/thread.h" +#include "../thread.h" #include "../progress.h" #include "../window_gui.h" #include "../window_func.h" @@ -27,6 +27,9 @@ #include "win32_v.h" #include #include +#include +#include +#include #include "../safeguards.h" @@ -40,7 +43,7 @@ #endif typedef BOOL (WINAPI *PFNTRACKMOUSEEVENT)(LPTRACKMOUSEEVENT lpEventTrack); -static PFNTRACKMOUSEEVENT _pTrackMouseEvent = NULL; +static PFNTRACKMOUSEEVENT _pTrackMouseEvent = nullptr; static struct { HWND main_wnd; @@ -65,12 +68,10 @@ DWORD _imm_props; /** Whether the drawing is/may be done in a separate thread. */ static bool _draw_threaded; -/** Thread used to 'draw' to the screen, i.e. push data to the screen. */ -static ThreadObject *_draw_thread = NULL; /** Mutex to keep the access to the shared memory controlled. */ -static ThreadMutex *_draw_mutex = NULL; -/** Event that is signaled when the drawing thread has finished initializing. */ -static HANDLE _draw_thread_initialized = NULL; +static std::recursive_mutex *_draw_mutex = nullptr; +/** Signal to draw the next frame. */ +static std::condition_variable_any *_draw_signal = nullptr; /** Should we keep continue drawing? */ static volatile bool _draw_continue; /** Local copy of the palette for use in the drawing thread. */ @@ -91,7 +92,7 @@ static void MakePalette() } _wnd.gdi_palette = CreatePalette(pal); - if (_wnd.gdi_palette == NULL) usererror("CreatePalette failed!\n"); + if (_wnd.gdi_palette == nullptr) usererror("CreatePalette failed!\n"); _cur_palette.first_dirty = 0; _cur_palette.count_dirty = 256; @@ -309,7 +310,7 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) } } else if (_wnd.fullscreen) { /* restore display? */ - ChangeDisplaySettings(NULL, 0); + ChangeDisplaySettings(nullptr, 0); /* restore the resolution */ _wnd.width = _bck_resolution.width; _wnd.height = _bck_resolution.height; @@ -336,7 +337,7 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) w = r.right - r.left; h = r.bottom - r.top; - if (_wnd.main_wnd != NULL) { + if (_wnd.main_wnd != nullptr) { if (!_window_maximize) SetWindowPos(_wnd.main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE); } else { int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; @@ -345,8 +346,8 @@ bool VideoDriver_Win32::MakeWindow(bool full_screen) char window_title[64]; seprintf(window_title, lastof(window_title), "OpenTTD %s", _openttd_revision); - _wnd.main_wnd = CreateWindow(_T("OTTD"), MB_TO_WIDE(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(NULL), 0); - if (_wnd.main_wnd == NULL) usererror("CreateWindow failed"); + _wnd.main_wnd = CreateWindow(_T("OTTD"), MB_TO_WIDE(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), 0); + if (_wnd.main_wnd == nullptr) usererror("CreateWindow failed"); ShowWindow(_wnd.main_wnd, showstyle); } } @@ -393,14 +394,14 @@ static void PaintWindow(HDC dc) DeleteDC(dc2); } -static void PaintWindowThread(void *) +static void PaintWindowThread() { /* First tell the main thread we're started */ - _draw_mutex->BeginCritical(); - SetEvent(_draw_thread_initialized); + std::unique_lock lock(*_draw_mutex); + _draw_signal->notify_one(); /* Now wait for the first thing to draw! */ - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); while (_draw_continue) { /* Convert update region from logical to device coordinates. */ @@ -422,11 +423,8 @@ static void PaintWindowThread(void *) /* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */ GdiFlush(); - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); } - - _draw_mutex->EndCritical(); - _draw_thread->Exit(); } /** Forward key presses to the window system. */ @@ -562,14 +560,14 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) if (hIMC != NULL) { if (lParam & GCS_RESULTSTR) { /* Read result string from the IME. */ - LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0); // Length is always in bytes, even in UNICODE build. + LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, nullptr, 0); // Length is always in bytes, even in UNICODE build. TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR)); len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str, len); str[len / sizeof(TCHAR)] = '\0'; /* Transmit text to windowing system. */ if (len > 0) { - HandleTextInput(NULL, true); // Clear marked string. + HandleTextInput(nullptr, true); // Clear marked string. HandleTextInput(FS2OTTD(str)); } SetCompositionPos(hwnd); @@ -580,7 +578,7 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) if ((lParam & GCS_COMPSTR) && DrawIMECompositionString()) { /* Read composition string from the IME. */ - LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR, NULL, 0); // Length is always in bytes, even in UNICODE build. + LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR, nullptr, 0); // Length is always in bytes, even in UNICODE build. TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR)); len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str, len); str[len / sizeof(TCHAR)] = '\0'; @@ -590,7 +588,7 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) convert_from_fs(str, utf8_buf, lengthof(utf8_buf)); /* Convert caret position from bytes in the input string to a position in the UTF-8 encoded string. */ - LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS, NULL, 0); + LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS, nullptr, 0); const char *caret = utf8_buf; for (const TCHAR *c = str; *c != '\0' && *caret != '\0' && caret_bytes > 0; c++, caret_bytes--) { /* Skip DBCS lead bytes or leading surrogates. */ @@ -607,7 +605,7 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) HandleTextInput(utf8_buf, true, caret); } else { - HandleTextInput(NULL, true); + HandleTextInput(nullptr, true); } lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART); @@ -625,7 +623,7 @@ static void CancelIMEComposition(HWND hwnd) if (hIMC != NULL) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); ImmReleaseContext(hwnd, hIMC); /* Clear any marked string from the current edit box. */ - HandleTextInput(NULL, true); + HandleTextInput(nullptr, true); } static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -650,15 +648,15 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP break; case WM_PAINT: - if (!in_sizemove && _draw_mutex != NULL && !HasModalProgress()) { + if (!in_sizemove && _draw_mutex != nullptr && !HasModalProgress()) { /* Get the union of the old update rect and the new update rect. */ RECT r; GetUpdateRect(hwnd, &r, FALSE); UnionRect(&_wnd.update_rect, &_wnd.update_rect, &r); /* Mark the window as updated, otherwise Windows would send more WM_PAINT messages. */ - ValidateRect(hwnd, NULL); - _draw_mutex->SendSignal(); + ValidateRect(hwnd, nullptr); + _draw_signal->notify_one(); } else { PAINTSTRUCT ps; @@ -679,7 +677,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP SelectPalette(hDC, hOldPalette, TRUE); ReleaseDC(hwnd, hDC); - if (nChanged != 0) InvalidateRect(hwnd, NULL, FALSE); + if (nChanged != 0) InvalidateRect(hwnd, nullptr, FALSE); return 0; } @@ -733,7 +731,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP * tracking the mouse for exiting the window */ if (!_cursor.in_window) { _cursor.in_window = true; - if (_pTrackMouseEvent != NULL) { + if (_pTrackMouseEvent != nullptr) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.dwFlags = TME_LEAVE; @@ -786,7 +784,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP case WM_IME_ENDCOMPOSITION: /* Clear any pending composition string. */ - HandleTextInput(NULL, true); + HandleTextInput(nullptr, true); if (DrawIMECompositionString()) return 0; break; @@ -834,7 +832,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP /* Silently drop all messages handled by WM_CHAR. */ MSG msg; - if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + if (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) { if ((msg.message == WM_CHAR || msg.message == WM_DEADCHAR) && GB(lParam, 16, 8) == GB(msg.lParam, 16, 8)) { return 0; } @@ -996,7 +994,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP } else if (!active && !minimized) { /* Minimise the window and restore desktop */ ShowWindow(hwnd, SW_MINIMIZE); - ChangeDisplaySettings(NULL, 0); + ChangeDisplaySettings(nullptr, 0); } } break; @@ -1011,7 +1009,7 @@ static void RegisterWndClass() static bool registered = false; if (!registered) { - HINSTANCE hinst = GetModuleHandle(NULL); + HINSTANCE hinst = GetModuleHandle(nullptr); WNDCLASS wnd = { CS_OWNDC, WndProcGdi, @@ -1019,7 +1017,7 @@ static void RegisterWndClass() 0, hinst, LoadIcon(hinst, MAKEINTRESOURCE(100)), - LoadCursor(NULL, IDC_ARROW), + LoadCursor(nullptr, IDC_ARROW), 0, 0, _T("OTTD") @@ -1060,8 +1058,8 @@ static bool AllocateDibSection(int w, int h, bool force) if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect); dc = GetDC(0); - _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, NULL, 0); - if (_wnd.dib_sect == NULL) usererror("CreateDIBSection failed"); + _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, nullptr, 0); + if (_wnd.dib_sect == nullptr) usererror("CreateDIBSection failed"); ReleaseDC(0, dc); _screen.width = w; @@ -1088,45 +1086,29 @@ static const Dimension default_resolutions[] = { static void FindResolutions() { - uint n = 0; uint i; DEVMODEA dm; /* Check modes for the relevant fullscreen bpp */ uint bpp = _support8bpp != S8BPP_HARDWARE ? 32 : BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); + _resolutions.clear(); + /* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95 * Doesn't really matter since we don't pass a string anyways, but still * a letdown */ - for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) { - if (dm.dmBitsPerPel == bpp && - dm.dmPelsWidth >= 640 && dm.dmPelsHeight >= 480) { - uint j; - - for (j = 0; j < n; j++) { - if (_resolutions[j].width == dm.dmPelsWidth && _resolutions[j].height == dm.dmPelsHeight) break; - } - - /* In the previous loop we have checked already existing/added resolutions if - * they are the same as the new ones. If this is not the case (j == n); we have - * looped all and found none, add the new one to the list. If we have reached the - * maximum amount of resolutions, then quit querying the display */ - if (j == n) { - _resolutions[j].width = dm.dmPelsWidth; - _resolutions[j].height = dm.dmPelsHeight; - if (++n == lengthof(_resolutions)) break; - } - } + for (i = 0; EnumDisplaySettingsA(nullptr, i, &dm) != 0; i++) { + if (dm.dmBitsPerPel != bpp || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480) continue; + if (std::find(_resolutions.begin(), _resolutions.end(), Dimension(dm.dmPelsWidth, dm.dmPelsHeight)) != _resolutions.end()) continue; + _resolutions.emplace_back(dm.dmPelsWidth, dm.dmPelsHeight); } /* We have found no resolutions, show the default list */ - if (n == 0) { - memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); - n = lengthof(default_resolutions); + if (_resolutions.empty()) { + _resolutions.assign(std::begin(default_resolutions), std::end(default_resolutions)); } - _num_resolutions = n; - SortResolutions(_num_resolutions); + SortResolutions(); } static FVideoDriver_Win32 iFVideoDriver_Win32; @@ -1152,9 +1134,9 @@ const char *VideoDriver_Win32::Start(const char * const *parm) MarkWholeScreenDirty(); - _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL && GetCPUCoreCount() > 1; + _draw_threaded = GetDriverParam(parm, "no_threads") == nullptr && GetDriverParam(parm, "no_thread") == nullptr && std::thread::hardware_concurrency() > 1; - return NULL; + return nullptr; } void VideoDriver_Win32::Stop() @@ -1163,7 +1145,7 @@ void VideoDriver_Win32::Stop() DeleteObject(_wnd.dib_sect); DestroyWindow(_wnd.main_wnd); - if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0); + if (_wnd.fullscreen) ChangeDisplaySettings(nullptr, 0); MyShowCursor(true); } @@ -1179,7 +1161,7 @@ static void CheckPaletteAnim() if (_cur_palette.count_dirty == 0) return; _local_palette = _cur_palette; - InvalidateRect(_wnd.main_wnd, NULL, FALSE); + InvalidateRect(_wnd.main_wnd, nullptr, FALSE); } void VideoDriver_Win32::MainLoop() @@ -1189,28 +1171,37 @@ void VideoDriver_Win32::MainLoop() uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; + std::thread draw_thread; + std::unique_lock draw_lock; + if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ - _draw_mutex = ThreadMutex::New(); - _draw_thread_initialized = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_draw_mutex == NULL || _draw_thread_initialized == NULL) { + try { + _draw_signal = new std::condition_variable_any(); + _draw_mutex = new std::recursive_mutex(); + } catch (...) { _draw_threaded = false; - } else { + } + + if (_draw_threaded) { + draw_lock = std::unique_lock(*_draw_mutex); + _draw_continue = true; - _draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread, "ottd:draw-win32"); + _draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &PaintWindowThread); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { + draw_lock.unlock(); + draw_lock.release(); delete _draw_mutex; - _draw_mutex = NULL; - CloseHandle(_draw_thread_initialized); - _draw_thread_initialized = NULL; + delete _draw_signal; + _draw_mutex = nullptr; + _draw_signal = nullptr; } else { DEBUG(driver, 1, "Threaded drawing enabled"); /* Wait till the draw thread has started itself. */ - WaitForSingleObject(_draw_thread_initialized, INFINITE); - _draw_mutex->BeginCritical(); + _draw_signal->wait(*_draw_mutex); } } } @@ -1221,13 +1212,13 @@ void VideoDriver_Win32::MainLoop() for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping - while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) { + while (PeekMessage(&mesg, nullptr, 0, 0, PM_REMOVE)) { InteractiveRandom(); // randomness /* Convert key messages to char messages if we want text input. */ if (EditBoxInGlobalFocus()) TranslateMessage(&mesg); DispatchMessage(&mesg); } - if (_exit_game) return; + if (_exit_game) break; #if defined(_DEBUG) if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 && @@ -1271,9 +1262,9 @@ void VideoDriver_Win32::MainLoop() /* The game loop is the part that can run asynchronously. * The rest except sleeping can't. */ - if (_draw_threaded) _draw_mutex->EndCritical(); + if (_draw_threaded) draw_lock.unlock(); GameLoop(); - if (_draw_threaded) _draw_mutex->BeginCritical(); + if (_draw_threaded) draw_lock.lock(); if (_force_full_redraw) MarkWholeScreenDirty(); @@ -1284,9 +1275,9 @@ void VideoDriver_Win32::MainLoop() GdiFlush(); /* Release the thread while sleeping */ - if (_draw_threaded) _draw_mutex->EndCritical(); + if (_draw_threaded) draw_lock.unlock(); Sleep(1); - if (_draw_threaded) _draw_mutex->BeginCritical(); + if (_draw_threaded) draw_lock.lock(); NetworkDrawChatMessage(); DrawMouseCursor(); @@ -1297,35 +1288,37 @@ void VideoDriver_Win32::MainLoop() _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ - _draw_mutex->SendSignal(); - _draw_mutex->EndCritical(); - _draw_thread->Join(); + _draw_signal->notify_all(); + if (draw_lock.owns_lock()) draw_lock.unlock(); + draw_lock.release(); + draw_thread.join(); - CloseHandle(_draw_thread_initialized); delete _draw_mutex; - delete _draw_thread; + delete _draw_signal; + + _draw_mutex = nullptr; } } bool VideoDriver_Win32::ChangeResolution(int w, int h) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL); _wnd.width = _wnd.width_org = w; _wnd.height = _wnd.height_org = h; - bool ret = this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; + return this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching } bool VideoDriver_Win32::ToggleFullscreen(bool full_screen) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - bool ret = this->MakeWindow(full_screen); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + + return this->MakeWindow(full_screen); } bool VideoDriver_Win32::AfterBlitterChange() @@ -1335,19 +1328,20 @@ bool VideoDriver_Win32::AfterBlitterChange() void VideoDriver_Win32::AcquireBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + if (_draw_mutex != nullptr) _draw_mutex->lock(); } void VideoDriver_Win32::ReleaseBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + if (_draw_mutex != nullptr) _draw_mutex->unlock(); } void VideoDriver_Win32::EditBoxLostFocus() { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + std::unique_lock lock; + if (_draw_mutex != nullptr) lock = std::unique_lock(*_draw_mutex); + CancelIMEComposition(_wnd.main_wnd); SetCompositionPos(_wnd.main_wnd); SetCandidatePos(_wnd.main_wnd); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); } diff --git a/src/video/win32_v.h b/src/video/win32_v.h index 7609d0422d..aa6bb7c0d5 100644 --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -17,29 +17,29 @@ /** The video driver for windows. */ class VideoDriver_Win32 : public VideoDriver { public: - /* virtual */ const char *Start(const char * const *param); + const char *Start(const char * const *param) override; - /* virtual */ void Stop(); + void Stop() override; - /* virtual */ void MakeDirty(int left, int top, int width, int height); + void MakeDirty(int left, int top, int width, int height) override; - /* virtual */ void MainLoop(); + void MainLoop() override; - /* virtual */ bool ChangeResolution(int w, int h); + bool ChangeResolution(int w, int h) override; - /* virtual */ bool ToggleFullscreen(bool fullscreen); + bool ToggleFullscreen(bool fullscreen) override; - /* virtual */ bool AfterBlitterChange(); + bool AfterBlitterChange() override; - /* virtual */ void AcquireBlitterLock(); + void AcquireBlitterLock() override; - /* virtual */ void ReleaseBlitterLock(); + void ReleaseBlitterLock() override; - /* virtual */ bool ClaimMousePointer(); + bool ClaimMousePointer() override; - /* virtual */ void EditBoxLostFocus(); + void EditBoxLostFocus() override; - /* virtual */ const char *GetName() const { return "win32"; } + const char *GetName() const override { return "win32"; } bool MakeWindow(bool full_screen); }; @@ -48,7 +48,7 @@ public: class FVideoDriver_Win32 : public DriverFactoryBase { public: FVideoDriver_Win32() : DriverFactoryBase(Driver::DT_VIDEO, 10, "win32", "Win32 GDI Video Driver") {} - /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Win32(); } + Driver *CreateInstance() const override { return new VideoDriver_Win32(); } }; #endif /* VIDEO_WIN32_H */ diff --git a/src/viewport.cpp b/src/viewport.cpp index eacf442012..ba645cdd9b 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -85,6 +85,8 @@ #include "tilehighlight_func.h" #include "window_gui.h" #include "linkgraph/linkgraph_gui.h" +#include "viewport_kdtree.h" +#include "town_kdtree.h" #include "viewport_sprite_sorter.h" #include "tunnelbridge_map.h" #include "company_base.h" @@ -104,6 +106,10 @@ Point _tile_fract_coords; +ViewportSignKdtree _viewport_sign_kdtree(&Kdtree_ViewportSignXYFunc); +static int _viewport_sign_maxwidth = 0; + + static const int MAX_TILE_EXTENT_LEFT = ZOOM_LVL_BASE * TILE_PIXELS; ///< Maximum left extent of tile relative to north corner. static const int MAX_TILE_EXTENT_RIGHT = ZOOM_LVL_BASE * TILE_PIXELS; ///< Maximum right extent of tile relative to north corner. static const int MAX_TILE_EXTENT_TOP = ZOOM_LVL_BASE * MAX_BUILDING_PIXELS; ///< Maximum top extent of tile relative to north corner (not considering bridges). @@ -153,10 +159,10 @@ enum SpriteCombineMode { SPRITE_COMBINE_ACTIVE, ///< %Sprite combining is active. #AddSortableSpriteToDraw outputs child sprites. }; -typedef SmallVector TileSpriteToDrawVector; -typedef SmallVector StringSpriteToDrawVector; -typedef SmallVector ParentSpriteToDrawVector; -typedef SmallVector ChildScreenSpriteToDrawVector; +typedef std::vector TileSpriteToDrawVector; +typedef std::vector StringSpriteToDrawVector; +typedef std::vector ParentSpriteToDrawVector; +typedef std::vector ChildScreenSpriteToDrawVector; /** * Snapping point for a track. @@ -169,7 +175,7 @@ struct LineSnapPoint : Point { uint8 dirs; ///< Allowed line directions, set of #Direction bits. }; -typedef SmallVector LineSnapPoints; ///< Set of snapping points +typedef std::vector LineSnapPoints; ///< Set of snapping points /** Coordinates of a polyline track made of 2 connected line segments. */ struct RailPolyline { @@ -209,7 +215,7 @@ static TileInfo *_cur_ti; bool _draw_bounding_boxes = false; bool _draw_dirty_blocks = false; uint _dirty_block_colour = 0; -static VpSpriteSorter _vp_sprite_sorter = NULL; +static VpSpriteSorter _vp_sprite_sorter = nullptr; static IndustryType _industry_forbidden_tiles = INVALID_INDUSTRYTYPE; @@ -231,11 +237,11 @@ static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z) void DeleteWindowViewport(Window *w) { - if (w->viewport == NULL) return; + if (w->viewport == nullptr) return; delete w->viewport->overlay; free(w->viewport); - w->viewport = NULL; + w->viewport = nullptr; } /** @@ -253,7 +259,7 @@ void DeleteWindowViewport(Window *w) void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom) { - assert(w->viewport == NULL); + assert(w->viewport == nullptr); ViewportData *vp = CallocT(1); @@ -288,7 +294,7 @@ void InitializeWindowViewport(Window *w, int x, int y, vp->dest_scrollpos_x = pt.x; vp->dest_scrollpos_y = pt.y; - vp->overlay = NULL; + vp->overlay = nullptr; w->viewport = vp; vp->virtual_left = 0; // pt.x; @@ -421,18 +427,18 @@ static void SetViewportPosition(Window *w, int x, int y) * @param x X coordinate of the xy position * @param y Y coordinate of the xy position * @return Pointer to the viewport if the xy position is in the viewport of the window, - * otherwise \c NULL is returned. + * otherwise \c nullptr is returned. */ ViewPort *IsPtInWindowViewport(const Window *w, int x, int y) { ViewPort *vp = w->viewport; - if (vp != NULL && + if (vp != nullptr && IsInsideMM(x, vp->left, vp->left + vp->width) && IsInsideMM(y, vp->top, vp->top + vp->height)) return vp; - return NULL; + return nullptr; } /** @@ -468,8 +474,8 @@ static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y) ViewPort *vp; Point pt; - if ( (w = FindWindowFromPt(x, y)) != NULL && - (vp = IsPtInWindowViewport(w, x, y)) != NULL) + if ( (w = FindWindowFromPt(x, y)) != nullptr && + (vp = IsPtInWindowViewport(w, x, y)) != nullptr) return TranslateXYToTileCoord(vp, zoom_x, zoom_y); pt.y = pt.x = -1; @@ -527,17 +533,18 @@ void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte * @param extra_offs_x Pixel X offset for the sprite position. * @param extra_offs_y Pixel Y offset for the sprite position. */ -static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0) +static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0) { assert((image & SPRITE_MASK) < MAX_SPRITES); - TileSpriteToDraw *ts = _vd.tile_sprites_to_draw.Append(); - ts->image = image; - ts->pal = pal; - ts->sub = sub; + /*C++17: TileSpriteToDraw &ts = */ _vd.tile_sprites_to_draw.emplace_back(); + TileSpriteToDraw &ts = _vd.tile_sprites_to_draw.back(); + ts.image = image; + ts.pal = pal; + ts.sub = sub; Point pt = RemapCoords(x, y, z); - ts->x = pt.x + extra_offs_x; - ts->y = pt.y + extra_offs_y; + ts.x = pt.x + extra_offs_x; + ts.y = pt.y + extra_offs_y; } /** @@ -629,8 +636,8 @@ void OffsetGroundSprite(int x, int y) default: NOT_REACHED(); } - /* _vd.last_child == NULL if foundation sprite was clipped by the viewport bounds */ - if (_vd.last_child != NULL) _vd.foundation[_vd.foundation_part] = _vd.parent_sprites_to_draw.Length() - 1; + /* _vd.last_child == nullptr if foundation sprite was clipped by the viewport bounds */ + if (_vd.last_child != nullptr) _vd.foundation[_vd.foundation_part] = (uint)_vd.parent_sprites_to_draw.size() - 1; _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_LVL_BASE; _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_LVL_BASE; @@ -659,8 +666,8 @@ static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z pt.y + spr->y_offs + spr->height <= _vd.dpi.top) return; - const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1; - AddChildSpriteScreen(image, pal, pt.x - pstd->left, pt.y - pstd->top, false, sub, false); + const ParentSpriteToDraw &pstd = _vd.parent_sprites_to_draw.back(); + AddChildSpriteScreen(image, pal, pt.x - pstd.left, pt.y - pstd.top, false, sub, false); } /** @@ -705,7 +712,7 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, return; } - _vd.last_child = NULL; + _vd.last_child = nullptr; Point pt = RemapCoords(x, y, z); int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y; @@ -740,29 +747,30 @@ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, return; } - ParentSpriteToDraw *ps = _vd.parent_sprites_to_draw.Append(); - ps->x = tmp_x; - ps->y = tmp_y; + /*C++17: ParentSpriteToDraw &ps = */ _vd.parent_sprites_to_draw.emplace_back(); + ParentSpriteToDraw &ps = _vd.parent_sprites_to_draw.back(); + ps.x = tmp_x; + ps.y = tmp_y; - ps->left = tmp_left; - ps->top = tmp_top; + ps.left = tmp_left; + ps.top = tmp_top; - ps->image = image; - ps->pal = pal; - ps->sub = sub; - ps->xmin = x + bb_offset_x; - ps->xmax = x + max(bb_offset_x, w) - 1; + ps.image = image; + ps.pal = pal; + ps.sub = sub; + ps.xmin = x + bb_offset_x; + ps.xmax = x + max(bb_offset_x, w) - 1; - ps->ymin = y + bb_offset_y; - ps->ymax = y + max(bb_offset_y, h) - 1; + ps.ymin = y + bb_offset_y; + ps.ymax = y + max(bb_offset_y, h) - 1; - ps->zmin = z + bb_offset_z; - ps->zmax = z + max(bb_offset_z, dz) - 1; + ps.zmin = z + bb_offset_z; + ps.zmax = z + max(bb_offset_z, dz) - 1; - ps->comparison_done = false; - ps->first_child = -1; + ps.comparison_done = false; + ps.first_child = -1; - _vd.last_child = &ps->first_child; + _vd.last_child = &ps.first_child; if (_vd.combine_sprites == SPRITE_COMBINE_PENDING) _vd.combine_sprites = SPRITE_COMBINE_ACTIVE; } @@ -852,7 +860,7 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran assert((image & SPRITE_MASK) < MAX_SPRITES); /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */ - if (_vd.last_child == NULL) return; + if (_vd.last_child == nullptr) return; /* make the sprites transparent with the right palette */ if (transparent) { @@ -860,35 +868,37 @@ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool tran pal = PALETTE_TO_TRANSPARENT; } - *_vd.last_child = _vd.child_screen_sprites_to_draw.Length(); + *_vd.last_child = (uint)_vd.child_screen_sprites_to_draw.size(); - ChildScreenSpriteToDraw *cs = _vd.child_screen_sprites_to_draw.Append(); - cs->image = image; - cs->pal = pal; - cs->sub = sub; - cs->x = scale ? x * ZOOM_LVL_BASE : x; - cs->y = scale ? y * ZOOM_LVL_BASE : y; - cs->next = -1; + /*C++17: ChildScreenSpriteToDraw &cs = */ _vd.child_screen_sprites_to_draw.emplace_back(); + ChildScreenSpriteToDraw &cs = _vd.child_screen_sprites_to_draw.back(); + cs.image = image; + cs.pal = pal; + cs.sub = sub; + cs.x = scale ? x * ZOOM_LVL_BASE : x; + cs.y = scale ? y * ZOOM_LVL_BASE : y; + cs.next = -1; /* Append the sprite to the active ChildSprite list. * If the active ParentSprite is a foundation, update last_foundation_child as well. * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */ - if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = &cs->next; - if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = &cs->next; - _vd.last_child = &cs->next; + if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = &cs.next; + if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = &cs.next; + _vd.last_child = &cs.next; } static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width) { assert(width != 0); - StringSpriteToDraw *ss = _vd.string_sprites_to_draw.Append(); - ss->string = string; - ss->x = x; - ss->y = y; - ss->params[0] = params_1; - ss->params[1] = params_2; - ss->width = width; - ss->colour = colour; + /*C++17: StringSpriteToDraw &ss = */ _vd.string_sprites_to_draw.emplace_back(); + StringSpriteToDraw &ss = _vd.string_sprites_to_draw.back(); + ss.string = string; + ss.x = x; + ss.y = y; + ss.params[0] = params_1; + ss.params[1] = params_2; + ss.width = width; + ss.colour = colour; } @@ -911,7 +921,7 @@ static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *t AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset); } else { /* draw on top of foundation */ - AddChildSpriteToFoundation(image, pal, NULL, foundation_part, 0, -z_offset * ZOOM_LVL_BASE); + AddChildSpriteToFoundation(image, pal, nullptr, foundation_part, 0, -z_offset * ZOOM_LVL_BASE); } } @@ -1004,16 +1014,115 @@ static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_ty DrawSelectionSprite(image, pal, ti, 7, foundation_part); } +enum TileHighlightType { + THT_NONE, + THT_WHITE, + THT_BLUE, + THT_RED, +}; + +const Station *_viewport_highlight_station; ///< Currently selected station for coverage area highlight +const Town *_viewport_highlight_town; ///< Currently selected town for coverage area highlight + +/** + * Get tile highlight type of coverage area for a given tile. + * @param t Tile that is being drawn + * @return Tile highlight type to draw + */ +static TileHighlightType GetTileHighlightType(TileIndex t) +{ + if (_viewport_highlight_station != nullptr) { + if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_WHITE; + if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE; + } + + if (_viewport_highlight_town != nullptr) { + if (IsTileType(t, MP_HOUSE)) { + if (GetTownIndex(t) == _viewport_highlight_town->index) { + TileHighlightType type = THT_RED; + for (const Station *st : _viewport_highlight_town->stations_near) { + if (st->owner != _current_company) continue; + if (st->TileIsInCatchment(t)) return THT_BLUE; + } + return type; + } + } else if (IsTileType(t, MP_STATION)) { + for (const Station *st : _viewport_highlight_town->stations_near) { + if (st->owner != _current_company) continue; + if (GetStationIndex(t) == st->index) return THT_WHITE; + } + } + } + + return THT_NONE; +} + +/** + * Draw tile highlight for coverage area highlight. + * @param *ti TileInfo Tile that is being drawn + * @param tht Highlight type to draw. + */ +static void DrawTileHighlightType(const TileInfo *ti, TileHighlightType tht) +{ + switch (tht) { + default: + case THT_NONE: break; + case THT_WHITE: DrawTileSelectionRect(ti, PAL_NONE); break; + case THT_BLUE: DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); break; + case THT_RED: DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); break; + } +} + +/** + * Highlights tiles insede local authority of selected towns. + * @param *ti TileInfo Tile that is being drawn + */ +static void HighlightTownLocalAuthorityTiles(const TileInfo *ti) +{ + /* Going through cases in order of computational time. */ + + if (_town_local_authority_kdtree.Count() == 0) return; + + /* Tile belongs to town regardless of distance from town. */ + if (GetTileType(ti->tile) == MP_HOUSE) { + if (!Town::GetByTile(ti->tile)->show_zone) return; + + DrawTileSelectionRect(ti, PALETTE_CRASH); + return; + } + + /* If the closest town in the highlighted list is far, we can stop searching. */ + TownID tid = _town_local_authority_kdtree.FindNearest(TileX(ti->tile), TileY(ti->tile)); + Town *closest_highlighted_town = Town::Get(tid); + + if (DistanceManhattan(ti->tile, closest_highlighted_town->xy) >= _settings_game.economy.dist_local_authority) return; + + /* Tile is inside of the local autrhority distance of a highlighted town, + but it is possible that a non-highlighted town is even closer. */ + Town *closest_town = ClosestTownFromTile(ti->tile, _settings_game.economy.dist_local_authority); + + if (closest_town->show_zone) { + DrawTileSelectionRect(ti, PALETTE_CRASH); + } + +} + /** * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. * @param *ti TileInfo Tile that is being drawn */ static void DrawTileSelection(const TileInfo *ti) { + /* Highlight tiles insede local authority of selected towns. */ + HighlightTownLocalAuthorityTiles(ti); + /* Draw a red error square? */ bool is_redsq = _thd.redsq == ti->tile; if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); + TileHighlightType tht = GetTileHighlightType(ti->tile); + DrawTileHighlightType(ti, tht); + switch (_thd.drawstyle & HT_DRAG_MASK) { default: break; // No tile selection active? @@ -1207,8 +1316,8 @@ static void ViewportAddLandscape() _vd.foundation_part = FOUNDATION_PART_NONE; _vd.foundation[0] = -1; _vd.foundation[1] = -1; - _vd.last_foundation_child[0] = NULL; - _vd.last_foundation_child[1] = NULL; + _vd.last_foundation_child[0] = nullptr; + _vd.last_foundation_child[1] = nullptr; _tile_type_procs[tile_type]->draw_tile_proc(&tile_info); if (tile_info.tile != INVALID_TILE){ @@ -1263,61 +1372,117 @@ void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const Vie } } -static void ViewportAddTownNames(DrawPixelInfo *dpi) +static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom) { - if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU) return; + /* Pessimistically always use normal font, but also assume small font is never larger in either dimension */ + const int fh = FONT_HEIGHT_NORMAL; + const int max_tw = _viewport_sign_maxwidth / 2 + 1; + const int expand_y = ScaleByZoom(VPSM_TOP + fh + VPSM_BOTTOM, zoom); + const int expand_x = ScaleByZoom(VPSM_LEFT + max_tw + VPSM_RIGHT, zoom); - const Town *t; - FOR_ALL_TOWNS(t) { - ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign, - t->Label(), t->SmallLabel(), STR_VIEWPORT_TOWN_TINY_BLACK, - t->index, t->cache.population); - } + r.left -= expand_x; + r.right += expand_x; + r.top -= expand_y; + r.bottom += expand_y; + + return r; } - -static void ViewportAddStationNames(DrawPixelInfo *dpi) +static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi) { - if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || _game_mode == GM_MENU) return; + Rect search_rect{ dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height }; + search_rect = ExpandRectWithViewportSignMargins(search_rect, dpi->zoom); + + bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && _game_mode != GM_MENU; + bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && _game_mode != GM_MENU; + bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES) && _game_mode != GM_MENU; + bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS); + bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS); const BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - /* Check whether the base station is a station or a waypoint */ - bool is_station = Station::IsExpected(st); - - /* Don't draw if the display options are disabled */ - if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; - - /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; - - ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign, - is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT, - (is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT) + 1, STR_NULL, - st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); - } -} - - -static void ViewportAddSigns(DrawPixelInfo *dpi) -{ - /* Signs are turned off or are invisible */ - if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS)) return; - const Sign *si; - FOR_ALL_SIGNS(si) { - /* Don't draw if sign is owned by another company and competitor signs should be hidden. - * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt - * companies can leave OWNER_NONE signs after them. */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; + /* Collect all the items first and draw afterwards, to ensure layering */ + std::vector stations; + std::vector towns; + std::vector signs; + + _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) { + switch (item.type) { + case ViewportSignKdtreeItem::VKI_STATION: + if (!show_stations) break; + st = BaseStation::Get(item.id.station); + + /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ + if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break; + + stations.push_back(st); + break; + + case ViewportSignKdtreeItem::VKI_WAYPOINT: + if (!show_waypoints) break; + st = BaseStation::Get(item.id.station); + + /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ + if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break; + + stations.push_back(st); + break; + + case ViewportSignKdtreeItem::VKI_TOWN: + if (!show_towns) break; + towns.push_back(Town::Get(item.id.town)); + break; + + case ViewportSignKdtreeItem::VKI_SIGN: + if (!show_signs) break; + si = Sign::Get(item.id.sign); + + /* Don't draw if sign is owned by another company and competitor signs should be hidden. + * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt + * companies can leave OWNER_NONE signs after them. */ + if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break; + + signs.push_back(si); + break; + + default: + NOT_REACHED(); + } + }); + + /* Layering order (bottom to top): Town names, signs, stations */ + + for (const auto *t : towns) { + ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign, + _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, + STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK, + t->index, t->cache.population); + } + + for (const auto *si : signs) { ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &si->sign, - STR_WHITE_SIGN, - (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL, - si->index, 0, (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); + STR_WHITE_SIGN, + (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL, + si->index, 0, (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); + } + + for (const auto *st : stations) { + if (Station::IsExpected(st)) { + /* Station */ + ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign, + STR_VIEWPORT_STATION, STR_VIEWPORT_STATION + 1, STR_NULL, + st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); + } else { + /* Waypoint */ + ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign, + STR_VIEWPORT_WAYPOINT, STR_VIEWPORT_WAYPOINT + 1, STR_NULL, + st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); + } } } + /** * Update the position of the viewport sign. * @param center the (preferred) center of the viewport sign @@ -1367,7 +1532,7 @@ void ViewportSign::MarkDirty(ZoomLevel maxzoom) const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { ViewPort *vp = w->viewport; - if (vp != NULL && vp->zoom <= maxzoom) { + if (vp != nullptr && vp->zoom <= maxzoom) { assert(vp->width != 0); Rect &zl = zoomlevels[vp->zoom]; MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom); @@ -1377,9 +1542,8 @@ void ViewportSign::MarkDirty(ZoomLevel maxzoom) const static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv) { - const TileSpriteToDraw *tsend = tstdv->End(); - for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) { - DrawSpriteViewport(ts->image, ts->pal, ts->x, ts->y, ts->sub); + for (const TileSpriteToDraw &ts : *tstdv) { + DrawSpriteViewport(ts.image, ts.pal, ts.x, ts.y, ts.sub); } } @@ -1392,8 +1556,8 @@ static bool ViewportSortParentSpritesChecker() /** Sort parent sprites pointer array */ static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) { - ParentSpriteToDraw **psdvend = psdv->End(); - ParentSpriteToDraw **psd = psdv->Begin(); + auto psdvend = psdv->end(); + auto psd = psdv->begin(); while (psd != psdvend) { ParentSpriteToDraw *ps = *psd; @@ -1404,7 +1568,7 @@ static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) ps->comparison_done = true; - for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) { + for (auto psd2 = psd + 1; psd2 != psdvend; psd2++) { ParentSpriteToDraw *ps2 = *psd2; if (ps2->comparison_done) continue; @@ -1439,7 +1603,7 @@ static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) /* Move ps2 in front of ps */ ParentSpriteToDraw *temp = ps2; - for (ParentSpriteToDraw **psd3 = psd2; psd3 > psd; psd3--) { + for (auto psd3 = psd2; psd3 > psd; psd3--) { *psd3 = *(psd3 - 1); } *psd = temp; @@ -1449,14 +1613,12 @@ static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv) { - const ParentSpriteToDraw * const *psd_end = psd->End(); - for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { - const ParentSpriteToDraw *ps = *it; + for (const ParentSpriteToDraw *ps : *psd) { if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub); int child_idx = ps->first_child; while (child_idx >= 0) { - const ChildScreenSpriteToDraw *cs = csstdv->Get(child_idx); + const ChildScreenSpriteToDraw *cs = csstdv->data() + child_idx; child_idx = cs->next; DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub); } @@ -1469,9 +1631,7 @@ static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const */ static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd) { - const ParentSpriteToDraw * const *psd_end = psd->End(); - for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { - const ParentSpriteToDraw *ps = *it; + for (const ParentSpriteToDraw *ps : *psd) { Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner @@ -1508,38 +1668,37 @@ static void ViewportDrawDirtyBlocks() static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv) { - const StringSpriteToDraw *ssend = sstdv->End(); - for (const StringSpriteToDraw *ss = sstdv->Begin(); ss != ssend; ++ss) { + for (const StringSpriteToDraw &ss : *sstdv) { TextColour colour = TC_BLACK; - bool small = HasBit(ss->width, 15); - int w = GB(ss->width, 0, 15); - int x = UnScaleByZoom(ss->x, zoom); - int y = UnScaleByZoom(ss->y, zoom); + bool small = HasBit(ss.width, 15); + int w = GB(ss.width, 0, 15); + int x = UnScaleByZoom(ss.x, zoom); + int y = UnScaleByZoom(ss.y, zoom); int h = VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM; - SetDParam(0, ss->params[0]); - SetDParam(1, ss->params[1]); + SetDParam(0, ss.params[0]); + SetDParam(1, ss.params[1]); - if (ss->colour != INVALID_COLOUR) { + if (ss.colour != INVALID_COLOUR) { /* Do not draw signs nor station names if they are set invisible */ - if (IsInvisibilitySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) continue; + if (IsInvisibilitySet(TO_SIGNS) && ss.string != STR_WHITE_SIGN) continue; - if (IsTransparencySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) { + if (IsTransparencySet(TO_SIGNS) && ss.string != STR_WHITE_SIGN) { /* Don't draw the rectangle. * Real colours need the TC_IS_PALETTE_COLOUR flag. * Otherwise colours from _string_colourmap are assumed. */ - colour = (TextColour)_colour_gradient[ss->colour][6] | TC_IS_PALETTE_COLOUR; + colour = (TextColour)_colour_gradient[ss.colour][6] | TC_IS_PALETTE_COLOUR; } else { /* Draw the rectangle if 'transparent station signs' is off, * or if we are drawing a general text sign (STR_WHITE_SIGN). */ DrawFrameRect( - x, y, x + w, y + h, ss->colour, + x, y, x + w, y + h, ss.colour, IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE ); } } - DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss->string, colour, SA_HOR_CENTER); + DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss.string, colour, SA_HOR_CENTER); } } @@ -1558,7 +1717,7 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom _vd.dpi.left = left & mask; _vd.dpi.top = top & mask; _vd.dpi.pitch = old_dpi->pitch; - _vd.last_child = NULL; + _vd.last_child = nullptr; int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left; int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top; @@ -1568,17 +1727,14 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom ViewportAddLandscape(); ViewportAddVehicles(&_vd.dpi); - ViewportAddTownNames(&_vd.dpi); - ViewportAddStationNames(&_vd.dpi); - ViewportAddSigns(&_vd.dpi); + ViewportAddKdtreeSigns(&_vd.dpi); DrawTextEffects(&_vd.dpi); - if (_vd.tile_sprites_to_draw.Length() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw); + if (_vd.tile_sprites_to_draw.size() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw); - ParentSpriteToDraw *psd_end = _vd.parent_sprites_to_draw.End(); - for (ParentSpriteToDraw *it = _vd.parent_sprites_to_draw.Begin(); it != psd_end; it++) { - *_vd.parent_sprites_to_sort.Append() = it; + for (auto &psd : _vd.parent_sprites_to_draw) { + _vd.parent_sprites_to_sort.push_back(&psd); } _vp_sprite_sorter(&_vd.parent_sprites_to_sort); @@ -1594,14 +1750,14 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom dp.height = UnScaleByZoom(dp.height, zoom); _cur_dpi = &dp; - if (vp->overlay != NULL && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) { + if (vp->overlay != nullptr && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) { /* translate to window coordinates */ dp.left = x; dp.top = y; vp->overlay->Draw(&dp); } - if (_vd.string_sprites_to_draw.Length() != 0) { + if (_vd.string_sprites_to_draw.size() != 0) { /* translate to world coordinates */ dp.left = UnScaleByZoom(_vd.dpi.left, zoom); dp.top = UnScaleByZoom(_vd.dpi.top, zoom); @@ -1610,11 +1766,11 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom _cur_dpi = old_dpi; - _vd.string_sprites_to_draw.Clear(); - _vd.tile_sprites_to_draw.Clear(); - _vd.parent_sprites_to_draw.Clear(); - _vd.parent_sprites_to_sort.Clear(); - _vd.child_screen_sprites_to_draw.Clear(); + _vd.string_sprites_to_draw.clear(); + _vd.tile_sprites_to_draw.clear(); + _vd.parent_sprites_to_draw.clear(); + _vd.parent_sprites_to_sort.clear(); + _vd.child_screen_sprites_to_draw.clear(); } /** @@ -1623,7 +1779,7 @@ void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom */ static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom) { - if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE) { + if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > (int)(180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE)) { if ((bottom - top) > (right - left)) { int t = (top + bottom) >> 1; ViewportDrawChk(vp, left, top, right, t); @@ -1802,7 +1958,7 @@ void MarkAllViewportsDirty(int left, int top, int right, int bottom) Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { ViewPort *vp = w->viewport; - if (vp != NULL) { + if (vp != nullptr) { assert(vp->width != 0); MarkViewportDirty(vp, left, top, right, bottom); } @@ -1813,7 +1969,7 @@ void ConstrainAllViewportsZoom() { Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { - if (w->viewport == NULL) continue; + if (w->viewport == nullptr) continue; ZoomLevel zoom = static_cast(Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); if (zoom != w->viewport->zoom) { @@ -1978,76 +2134,207 @@ static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const Vie int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom); int sign_height = ScaleByZoom(VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM, vp->zoom); - x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left; - y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top; - return y >= sign->top && y < sign->top + sign_height && x >= sign->center - sign_half_width && x < sign->center + sign_half_width; } -static bool CheckClickOnTown(const ViewPort *vp, int x, int y) + +/** + * Check whether any viewport sign was clicked, and dispatch the click. + * @param vp the clicked viewport + * @param x X position of click + * @param y Y position of click + * @return true if the sign was hit + */ +static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y) { - if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES)) return false; + if (_game_mode == GM_MENU) return false; - const Town *t; - FOR_ALL_TOWNS(t) { - if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) { - if (_ctrl_pressed) TownExecuteAction(t, 4); //build statue - else ShowTownViewWindow(t->index); - return true; + x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left; + y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top; + + Rect search_rect{ x - 1, y - 1, x + 1, y + 1 }; + search_rect = ExpandRectWithViewportSignMargins(search_rect, vp->zoom); + + bool show_stations = HasBit(_display_opt, DO_SHOW_STATION_NAMES) && !IsInvisibilitySet(TO_SIGNS); + bool show_waypoints = HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES) && !IsInvisibilitySet(TO_SIGNS); + bool show_towns = HasBit(_display_opt, DO_SHOW_TOWN_NAMES); + bool show_signs = HasBit(_display_opt, DO_SHOW_SIGNS) && !IsInvisibilitySet(TO_SIGNS); + bool show_competitors = HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS); + + /* Topmost of each type that was hit */ + BaseStation *st = nullptr, *last_st = nullptr; + Town *t = nullptr, *last_t = nullptr; + Sign *si = nullptr, *last_si = nullptr; + + /* See ViewportAddKdtreeSigns() for details on the search logic */ + _viewport_sign_kdtree.FindContained(search_rect.left, search_rect.top, search_rect.right, search_rect.bottom, [&](const ViewportSignKdtreeItem & item) { + switch (item.type) { + case ViewportSignKdtreeItem::VKI_STATION: + if (!show_stations) break; + st = BaseStation::Get(item.id.station); + if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break; + if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st; + break; + + case ViewportSignKdtreeItem::VKI_WAYPOINT: + if (!show_waypoints) break; + st = BaseStation::Get(item.id.station); + if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break; + if (CheckClickOnViewportSign(vp, x, y, &st->sign)) last_st = st; + break; + + case ViewportSignKdtreeItem::VKI_TOWN: + if (!show_towns) break; + t = Town::Get(item.id.town); + if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) last_t = t; + break; + + case ViewportSignKdtreeItem::VKI_SIGN: + if (!show_signs) break; + si = Sign::Get(item.id.sign); + if (!show_competitors && _local_company != si->owner && si->owner != OWNER_DEITY) break; + if (CheckClickOnViewportSign(vp, x, y, &si->sign)) last_si = si; + break; + + default: + NOT_REACHED(); } - } + }); - return false; -} - -static bool CheckClickOnStation(const ViewPort *vp, int x, int y) -{ - if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || IsInvisibilitySet(TO_SIGNS)) return false; - - const BaseStation *st; - FOR_ALL_BASE_STATIONS(st) { - /* Check whether the base station is a station or a waypoint */ - bool is_station = Station::IsExpected(st); - - /* Don't check if the display options are disabled */ - if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; - - /* Don't check if competitor signs are not shown and the sign isn't owned by the local company */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; - - if (CheckClickOnViewportSign(vp, x, y, &st->sign)) { - if (is_station) { - ShowStationViewWindow(st->index); - } else { - ShowWaypointWindow(Waypoint::From(st)); - } - return true; + /* Select which hit to handle based on priority */ + if (last_st != nullptr) { + if (Station::IsExpected(last_st)) { + ShowStationViewWindow(last_st->index); + } else { + ShowWaypointWindow(Waypoint::From(last_st)); } + return true; + } else if (last_t != nullptr) { + if (_ctrl_pressed) TownExecuteAction(last_t, 4); //CM build statue + else ShowTownViewWindow(last_t->index); + return true; + } else if (last_si != nullptr) { + HandleClickOnSign(last_si); + return true; + } else { + return false; } - - return false; } -static bool CheckClickOnSign(const ViewPort *vp, int x, int y) +ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id) { - /* Signs are turned off, or they are transparent and invisibility is ON, or company is a spectator */ - if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS) || _local_company == COMPANY_SPECTATOR) return false; + ViewportSignKdtreeItem item; + item.type = VKI_STATION; + item.id.station = id; - const Sign *si; - FOR_ALL_SIGNS(si) { - /* If competitor signs are hidden, don't check signs that aren't owned by local company */ - if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; - if (si->owner == OWNER_DEITY && _game_mode != GM_EDITOR) continue; + const Station *st = Station::Get(id); + Point pt = RemapCoords(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE, GetTileMaxZ(st->xy) * TILE_HEIGHT); - if (CheckClickOnViewportSign(vp, x, y, &si->sign)) { - HandleClickOnSign(si); - return true; - } + pt.y -= 32 * ZOOM_LVL_BASE; + if ((st->facilities & FACIL_AIRPORT) && st->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_LVL_BASE; + + item.center = pt.x; + item.top = pt.y; + + /* Assume the sign can be a candidate for drawing, so measure its width */ + _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, st->sign.width_normal); + + return item; +} + +ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id) +{ + ViewportSignKdtreeItem item; + item.type = VKI_WAYPOINT; + item.id.station = id; + + const Waypoint *st = Waypoint::Get(id); + Point pt = RemapCoords(TileX(st->xy) * TILE_SIZE, TileY(st->xy) * TILE_SIZE, GetTileMaxZ(st->xy) * TILE_HEIGHT); + + pt.y -= 32 * ZOOM_LVL_BASE; + + item.center = pt.x; + item.top = pt.y; + + /* Assume the sign can be a candidate for drawing, so measure its width */ + _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, st->sign.width_normal); + + return item; +} + +ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id) +{ + ViewportSignKdtreeItem item; + item.type = VKI_TOWN; + item.id.town = id; + + const Town *town = Town::Get(id); + /* Avoid using RemapCoords2, it has dependency on the foundations status of the tile, and that can be unavailable during saveload, leading to crashes. + * Instead "fake" foundations by taking the highest Z coordinate of any corner of the tile. */ + Point pt = RemapCoords(TileX(town->xy) * TILE_SIZE, TileY(town->xy) * TILE_SIZE, GetTileMaxZ(town->xy) * TILE_HEIGHT); + + pt.y -= 24 * ZOOM_LVL_BASE; + + item.center = pt.x; + item.top = pt.y; + + /* Assume the sign can be a candidate for drawing, so measure its width */ + _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, town->cache.sign.width_normal); + + return item; +} + +ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id) +{ + ViewportSignKdtreeItem item; + item.type = VKI_SIGN; + item.id.sign = id; + + const Sign *sign = Sign::Get(id); + Point pt = RemapCoords(sign->x, sign->y, sign->z); + + pt.y -= 6 * ZOOM_LVL_BASE; + + item.center = pt.x; + item.top = pt.y; + + /* Assume the sign can be a candidate for drawing, so measure its width */ + _viewport_sign_maxwidth = max(_viewport_sign_maxwidth, sign->sign.width_normal); + + return item; +} + +void RebuildViewportKdtree() +{ + /* Reset biggest size sign seen */ + _viewport_sign_maxwidth = 0; + + std::vector items; + items.reserve(BaseStation::GetNumItems() + Town::GetNumItems() + Sign::GetNumItems()); + + const Station *st; + FOR_ALL_STATIONS(st) { + items.push_back(ViewportSignKdtreeItem::MakeStation(st->index)); } - return false; + const Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { + items.push_back(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); + } + + const Town *town; + FOR_ALL_TOWNS(town) { + items.push_back(ViewportSignKdtreeItem::MakeTown(town->index)); + } + + const Sign *sign; + FOR_ALL_SIGNS(sign) { + items.push_back(ViewportSignKdtreeItem::MakeSign(sign->index)); + } + + _viewport_sign_kdtree.Build(items.begin(), items.end()); } @@ -2076,7 +2363,7 @@ static void PlaceObject() _tile_fract_coords.y = pt.y & TILE_UNIT_MASK; w = _thd.GetCallbackWnd(); - if (w != NULL) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y)); + if (w != nullptr) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y)); } @@ -2085,7 +2372,7 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click) const Vehicle *v = CheckClickOnVehicle(vp, x, y); if (_thd.place_mode & HT_VEHICLE) { - if (v != NULL && VehicleClicked(v)) return true; + if (v != nullptr && VehicleClicked(v)) return true; } /* Vehicle placement mode already handled above. */ @@ -2106,12 +2393,10 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click) return true; } - if (CheckClickOnTown(vp, x, y)) return true; - if (CheckClickOnStation(vp, x, y)) return true; - if (CheckClickOnSign(vp, x, y)) return true; + if (CheckClickOnViewportSign(vp, x, y)) return true; bool result = CheckClickOnLandscape(vp, x, y); - if (v != NULL) { + if (v != nullptr) { DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v); if (IsCompanyBuildableVehicleType(v)) { v = v->First(); @@ -2129,7 +2414,7 @@ bool HandleViewportClicked(const ViewPort *vp, int x, int y, bool double_click) void RebuildViewportOverlay(Window *w) { - if (w->viewport->overlay != NULL && + if (w->viewport->overlay != nullptr && w->viewport->overlay->GetCompanyMask() != 0 && w->viewport->overlay->GetCargoMask() != 0) { w->viewport->overlay->SetDirty(); @@ -2263,7 +2548,7 @@ bool TileHighlightData::IsDraggingDiagonal() /** * Get the window that started the current highlighting. - * @return The window that requested the current tile highlighting, or \c NULL if not available. + * @return The window that requested the current tile highlighting, or \c nullptr if not available. */ Window *TileHighlightData::GetCallbackWnd() { @@ -2314,6 +2599,8 @@ void UpdateTileSelection() int x1; int y1; + if (_thd.freeze) return; + HighLightStyle new_drawstyle = HT_NONE; bool new_diagonal = false; @@ -3169,10 +3456,10 @@ static HighLightStyle CalcPolyrailDrawstyle(Point pt, bool dragging) if (_current_snap_lock.x != -1) { snap_point = FindBestPolyline(pt, &_current_snap_lock, 1, &line); } else if (snap_mode == RSM_SNAP_TO_TILE) { - snap_point = FindBestPolyline(pt, _tile_snap_points.Begin(), _tile_snap_points.Length(), &line); + snap_point = FindBestPolyline(pt, _tile_snap_points.data(), _tile_snap_points.size(), &line); } else { assert(snap_mode == RSM_SNAP_TO_RAIL); - snap_point = FindBestPolyline(pt, _rail_snap_points.Begin(), _rail_snap_points.Length(), &line); + snap_point = FindBestPolyline(pt, _rail_snap_points.data(), _rail_snap_points.size(), &line); } if (snap_point == NULL) return HT_NONE; // no match @@ -3398,7 +3685,7 @@ EventState VpHandlePlaceSizingDrag() /* stop drag mode if the window has been closed */ Window *w = _thd.GetCallbackWnd(); - if (w == NULL) { + if (w == nullptr) { ResetObjectToPlace(); return ES_HANDLED; } @@ -3461,7 +3748,7 @@ void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowC * this function might in some cases reset the newly set object to * place or not properly reset the original selection. */ _thd.window_class = WC_INVALID; - if (w != NULL) w->OnPlaceObjectAbort(); + if (w != nullptr) w->OnPlaceObjectAbort(); } /* Mark the old selection dirty, in case the selection shape or colour changes */ @@ -3535,7 +3822,7 @@ void InitializeSpriteSorter() break; } } - assert(_vp_sprite_sorter != NULL); + assert(_vp_sprite_sorter != nullptr); } /** @@ -3558,12 +3845,8 @@ CommandCost CmdScrollViewport(TileIndex tile, DoCommandFlag flags, uint32 p1, ui if (_local_company != (CompanyID)p2) return CommandCost(); break; case VST_CLIENT: -#ifdef ENABLE_NETWORK if (_network_own_client_id != (ClientID)p2) return CommandCost(); break; -#else - return CommandCost(); -#endif default: return CMD_ERROR; } @@ -3575,6 +3858,68 @@ CommandCost CmdScrollViewport(TileIndex tile, DoCommandFlag flags, uint32 p1, ui return CommandCost(); } +static void MarkCatchmentTilesDirty() +{ + if (_viewport_highlight_town != nullptr) { + MarkWholeScreenDirty(); + return; + } + if (_viewport_highlight_station != nullptr) { + if (_viewport_highlight_station->catchment_tiles.tile == INVALID_TILE) { + MarkWholeScreenDirty(); + _viewport_highlight_station = nullptr; + } else { + BitmapTileIterator it(_viewport_highlight_station->catchment_tiles); + for (TileIndex tile = it; tile != INVALID_TILE; tile = ++it) { + MarkTileDirtyByTile(tile); + } + } + } +} + +/** + * Select or deselect station for coverage area highlight. + * Selecting a station will deselect a town. + * @param *st Station in question + * @param sel Select or deselect given station + */ +void SetViewportCatchmentStation(const Station *st, bool sel) +{ + if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index); + if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index); + if (sel && _viewport_highlight_station != st) { + MarkCatchmentTilesDirty(); + _viewport_highlight_station = st; + _viewport_highlight_town = nullptr; + MarkCatchmentTilesDirty(); + } else if (!sel && _viewport_highlight_station == st) { + MarkCatchmentTilesDirty(); + _viewport_highlight_station = nullptr; + } + if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index); +} + +/** + * Select or deselect town for coverage area highlight. + * Selecting a town will deselect a station. + * @param *t Town in question + * @param sel Select or deselect given town + */ +void SetViewportCatchmentTown(const Town *t, bool sel) +{ + if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index); + if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index); + if (sel && _viewport_highlight_town != t) { + _viewport_highlight_station = nullptr; + _viewport_highlight_town = t; + MarkWholeScreenDirty(); + } else if (!sel && _viewport_highlight_town == t) { + _viewport_highlight_town = nullptr; + MarkWholeScreenDirty(); + } + if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index); +} + /** * Construct a rail snapping point based on a spot where a rail tracks segment * has been placed. @@ -3659,12 +4004,11 @@ void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track snap_start = LineSnapPointAtRailTrackEndpoint(start_tile, TrackdirToExitdir(exit_trackdir_at_start), bidirectional_exit, &snap_start_ex); snap_end = LineSnapPointAtRailTrackEndpoint(end_tile, TrackdirToExitdir(exit_trackdir_at_end), bidirectional_exit, &snap_end_ex); /* Find if we already had these coordinates before. */ - LineSnapPoint *snap; bool had_start = false; bool had_end = false; - for (snap = _rail_snap_points.Begin(); snap != _rail_snap_points.End(); snap++) { - had_start |= (snap->x == snap_start.x && snap->y == snap_start.y); - had_end |= (snap->x == snap_end.x && snap->y == snap_end.y); + for (auto &snap: _rail_snap_points) { + had_start |= (snap.x == snap_start.x && snap.y == snap_start.y); + had_end |= (snap.x == snap_end.x && snap.y == snap_end.y); } /* Create new snap point set. */ if (had_start && had_end) { @@ -3672,14 +4016,14 @@ void StoreRailPlacementEndpoints(TileIndex start_tile, TileIndex end_tile, Track SetRailSnapMode(RSM_NO_SNAP); } else { /* include only new points */ - _rail_snap_points.Clear(); + _rail_snap_points.clear(); if (!had_start) { - *_rail_snap_points.Append() = snap_start; - if (snap_start_ex.dirs != 0) *_rail_snap_points.Append() = snap_start_ex; + _rail_snap_points.push_back(snap_start); + if (snap_start_ex.dirs != 0) _rail_snap_points.push_back(snap_start_ex); } if (!had_end) { - *_rail_snap_points.Append() = snap_end; - if (snap_end_ex.dirs != 0) *_rail_snap_points.Append() = snap_end_ex; + _rail_snap_points.push_back(snap_end); + if (snap_end_ex.dirs != 0) _rail_snap_points.push_back(snap_end_ex); } SetRailSnapMode(RSM_SNAP_TO_RAIL); } @@ -3701,16 +4045,16 @@ void StoreRailStationPlacementEndpoints(const TileArea &ta, Axis station_axis) uint end_x = start_x + ta.w - 1; uint end_y = start_y + ta.h - 1; - _rail_snap_points.Clear(); + _rail_snap_points.clear(); if (station_axis == AXIS_X) { for (uint y = start_y; y <= end_y; y++) { - *_rail_snap_points.Append() = LineSnapPointAtRailTrackEndpoint(TileXY(start_x, y), DIAGDIR_NE, false, NULL); - *_rail_snap_points.Append() = LineSnapPointAtRailTrackEndpoint(TileXY(end_x, y), DIAGDIR_SW, false, NULL); + _rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(start_x, y), DIAGDIR_NE, false, NULL)); + _rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(end_x, y), DIAGDIR_SW, false, NULL)); } } else { for (uint x = start_x; x <= end_x; x++) { - *_rail_snap_points.Append() = LineSnapPointAtRailTrackEndpoint(TileXY(x, start_y), DIAGDIR_NW, false, NULL); - *_rail_snap_points.Append() = LineSnapPointAtRailTrackEndpoint(TileXY(x, end_y), DIAGDIR_SE, false, NULL); + _rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(x, start_y), DIAGDIR_NW, false, NULL)); + _rail_snap_points.push_back(LineSnapPointAtRailTrackEndpoint(TileXY(x, end_y), DIAGDIR_SE, false, NULL)); } } } @@ -3724,8 +4068,8 @@ void StoreRailStationPlacementEndpoints(const TileArea &ta, Axis station_axis) */ RailSnapMode GetRailSnapMode() { - if (_rail_snap_mode == RSM_SNAP_TO_TILE && _tile_snap_points.Length() == 0) return RSM_NO_SNAP; - if (_rail_snap_mode == RSM_SNAP_TO_RAIL && _rail_snap_points.Length() == 0) return RSM_NO_SNAP; + if (_rail_snap_mode == RSM_SNAP_TO_TILE && _tile_snap_points.empty()) return RSM_NO_SNAP; + if (_rail_snap_mode == RSM_SNAP_TO_RAIL && _rail_snap_points.empty()) return RSM_NO_SNAP; return _rail_snap_mode; } @@ -3750,7 +4094,7 @@ void SetRailSnapMode(RailSnapMode mode) */ static TileIndex GetRailSnapTile() { - if (_tile_snap_points.Length() == 0) return INVALID_TILE; + if (_tile_snap_points.empty()) return INVALID_TILE; return TileVirtXY(_tile_snap_points[DIAGDIR_NE].x, _tile_snap_points[DIAGDIR_NE].y); } @@ -3762,13 +4106,13 @@ static TileIndex GetRailSnapTile() */ static void SetRailSnapTile(TileIndex tile) { - _tile_snap_points.Clear(); + _tile_snap_points.clear(); if (tile == INVALID_TILE) return; for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { - LineSnapPoint *point = _tile_snap_points.Append(); - *point = LineSnapPointAtRailTrackEndpoint(tile, dir, false, NULL); - point->dirs = ROR(point->dirs, DIRDIFF_REVERSE); + auto point = LineSnapPointAtRailTrackEndpoint(tile, dir, false, NULL); + point.dirs = ROR(point.dirs, DIRDIFF_REVERSE); + _tile_snap_points.push_back(point); } } @@ -3776,7 +4120,7 @@ static void SetRailSnapTile(TileIndex tile) void ResetRailPlacementEndpoints() { _rail_snap_mode = RSM_NO_SNAP; - _tile_snap_points.Clear(); - _rail_snap_points.Clear(); + _tile_snap_points.clear(); + _rail_snap_points.clear(); _current_snap_lock.x = -1; } diff --git a/src/viewport_func.h b/src/viewport_func.h index dd8553a74f..e4ed7c25b1 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -50,10 +50,10 @@ static inline void MaxZoomInOut(ZoomStateChange how, Window *w) void OffsetGroundSprite(int x, int y); -void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0); -void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0); -void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = NULL); -void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = NULL, bool scale = true); +void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0); +void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = nullptr, int extra_offs_x = 0, int extra_offs_y = 0); +void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = nullptr); +void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = nullptr, bool scale = true); void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2 = 0, Colours colour = INVALID_COLOUR); @@ -94,4 +94,10 @@ static inline void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset = Point GetViewportStationMiddle(const ViewPort *vp, const Station *st); +struct Station; +struct Town; + +void SetViewportCatchmentStation(const Station *st, bool sel); +void SetViewportCatchmentTown(const Town *t, bool sel); + #endif /* VIEWPORT_FUNC_H */ diff --git a/src/viewport_gui.cpp b/src/viewport_gui.cpp index aecddd1ab2..dcbf045789 100644 --- a/src/viewport_gui.cpp +++ b/src/viewport_gui.cpp @@ -80,7 +80,7 @@ public: this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { switch (widget) { case WID_EV_CAPTION: @@ -90,7 +90,7 @@ public: } } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_EV_ZOOM_IN: DoZoomInOutWindow(ZOOM_IN, this); break; @@ -120,15 +120,15 @@ public: } } - virtual void OnResize() + void OnResize() override { - if (this->viewport != NULL) { + if (this->viewport != nullptr) { NWidgetViewport *nvp = this->GetWidget(WID_EV_VIEWPORT); nvp->UpdateViewportCoordinates(this); } } - virtual void OnScroll(Point delta) + void OnScroll(Point delta) override { this->viewport->scrollpos_x += ScaleByZoom(delta.x, this->viewport->zoom); this->viewport->scrollpos_y += ScaleByZoom(delta.y, this->viewport->zoom); @@ -136,7 +136,7 @@ public: this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; } - virtual void OnMouseWheel(int wheel) + void OnMouseWheel(int wheel) override { if (_settings_client.gui.scrollwheel_scrolling != 2) { ZoomInOrOutToCursorWindow(wheel < 0, this); @@ -148,7 +148,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */ @@ -177,7 +177,7 @@ void ShowExtraViewPortWindow(TileIndex tile) int i = 0; /* find next free window number for extra viewport */ - while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++; + while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != nullptr) i++; new ExtraViewportWindow(&_extra_view_port_desc, i, tile); } diff --git a/src/viewport_kdtree.h b/src/viewport_kdtree.h new file mode 100644 index 0000000000..93344a5e63 --- /dev/null +++ b/src/viewport_kdtree.h @@ -0,0 +1,83 @@ +/* +* This file is part of OpenTTD. +* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU 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 town_kdtree.h Declarations for accessing the k-d tree of towns */ + +#ifndef VIEWPORT_KDTREE_H +#define VIEWPORT_KDTREE_H + +#include "core/kdtree.hpp" +#include "viewport_type.h" +#include "station_base.h" +#include "town_type.h" +#include "signs_base.h" + +struct ViewportSignKdtreeItem { + enum ItemType : uint16 { + VKI_STATION, + VKI_WAYPOINT, + VKI_TOWN, + VKI_SIGN, + }; + ItemType type; + union { + StationID station; + TownID town; + SignID sign; + } id; + int32 center; + int32 top; + + bool operator== (const ViewportSignKdtreeItem &other) const + { + if (this->type != other.type) return false; + switch (this->type) { + case VKI_STATION: + case VKI_WAYPOINT: + return this->id.station == other.id.station; + case VKI_TOWN: + return this->id.town == other.id.town; + case VKI_SIGN: + return this->id.sign == other.id.sign; + default: + NOT_REACHED(); + } + } + + bool operator< (const ViewportSignKdtreeItem &other) const + { + if (this->type != other.type) return this->type < other.type; + switch (this->type) { + case VKI_STATION: + case VKI_WAYPOINT: + return this->id.station < other.id.station; + case VKI_TOWN: + return this->id.town < other.id.town; + case VKI_SIGN: + return this->id.sign < other.id.sign; + default: + NOT_REACHED(); + } + } + + static ViewportSignKdtreeItem MakeStation(StationID id); + static ViewportSignKdtreeItem MakeWaypoint(StationID id); + static ViewportSignKdtreeItem MakeTown(TownID id); + static ViewportSignKdtreeItem MakeSign(SignID id); +}; + +inline int32 Kdtree_ViewportSignXYFunc(const ViewportSignKdtreeItem &item, int dim) +{ + return (dim == 0) ? item.center : item.top; +} + +typedef Kdtree ViewportSignKdtree; +extern ViewportSignKdtree _viewport_sign_kdtree; + +void RebuildViewportKdtree(); + +#endif diff --git a/src/viewport_sprite_sorter.h b/src/viewport_sprite_sorter.h index 324ece3020..24241565e7 100644 --- a/src/viewport_sprite_sorter.h +++ b/src/viewport_sprite_sorter.h @@ -41,7 +41,7 @@ struct ParentSpriteToDraw { bool comparison_done; ///< Used during sprite sorting: true if sprite has been compared with all other sprites }; -typedef SmallVector ParentSpriteToSortVector; +typedef std::vector ParentSpriteToSortVector; /** Type for method for checking whether a viewport sprite sorter exists. */ typedef bool (*VpSorterChecker)(); diff --git a/src/viewport_sprite_sorter_sse4.cpp b/src/viewport_sprite_sorter_sse4.cpp index fb78c51c86..212ff12e68 100644 --- a/src/viewport_sprite_sorter_sse4.cpp +++ b/src/viewport_sprite_sorter_sse4.cpp @@ -29,8 +29,8 @@ void ViewportSortParentSpritesSSE41(ParentSpriteToSortVector *psdv) { const __m128i mask_ptest = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0); - ParentSpriteToDraw ** const psdvend = psdv->End(); - ParentSpriteToDraw **psd = psdv->Begin(); + auto const psdvend = psdv->end(); + auto psd = psdv->begin(); while (psd != psdvend) { ParentSpriteToDraw * const ps = *psd; @@ -41,7 +41,7 @@ void ViewportSortParentSpritesSSE41(ParentSpriteToSortVector *psdv) ps->comparison_done = true; - for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) { + for (auto psd2 = psd + 1; psd2 != psdvend; psd2++) { ParentSpriteToDraw * const ps2 = *psd2; if (ps2->comparison_done) continue; @@ -85,7 +85,7 @@ void ViewportSortParentSpritesSSE41(ParentSpriteToSortVector *psdv) /* Move ps2 in front of ps */ ParentSpriteToDraw * const temp = ps2; - for (ParentSpriteToDraw **psd3 = psd2; psd3 > psd; psd3--) { + for (auto psd3 = psd2; psd3 > psd; psd3--) { *psd3 = *(psd3 - 1); } *psd = temp; diff --git a/src/viewport_type.h b/src/viewport_type.h index bfaa67e1ad..928baa81d9 100644 --- a/src/viewport_type.h +++ b/src/viewport_type.h @@ -22,7 +22,7 @@ class LinkGraphOverlay; * Data structure for viewport, display of a part of the world */ struct ViewPort { - int left; ///< Screen coordinate left egde of the viewport + int left; ///< Screen coordinate left edge of the viewport int top; ///< Screen coordinate top edge of the viewport int width; ///< Screen width of the viewport int height; ///< Screen height of the viewport @@ -119,11 +119,11 @@ enum ViewportDragDropSelectionProcess { DDSP_PLACE_ROAD_X_DIR, ///< Road placement (X axis) DDSP_PLACE_ROAD_Y_DIR, ///< Road placement (Y axis) DDSP_PLACE_AUTOROAD, ///< Road placement (auto) - DDSP_PLACE_FULLROAD, ///< Road placement (auto, full roads) DDSP_BUILD_BUSSTOP, ///< Road stop placement (buses) DDSP_BUILD_TRUCKSTOP, ///< Road stop placement (trucks) DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses) DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks) + DDSP_CONVERT_ROAD, ///< Road conversion }; diff --git a/src/void_cmd.cpp b/src/void_cmd.cpp index a2a45e7227..56e7cc5261 100644 --- a/src/void_cmd.cpp +++ b/src/void_cmd.cpp @@ -28,7 +28,7 @@ static void DrawTile_Void(TileInfo *ti) static int GetSlopePixelZ_Void(TileIndex tile, uint x, uint y) { - /* This function may be called on tiles outside the map, don't asssume + /* This function may be called on tiles outside the map, don't assume * that 'tile' is a valid tile index. See GetSlopePixelZOutsideMap. */ int z; Slope tileh = GetTilePixelSlopeOutsideMap(x >> 4, y >> 4, &z); @@ -77,15 +77,15 @@ extern const TileTypeProcs _tile_type_void_procs = { DrawTile_Void, // draw_tile_proc GetSlopePixelZ_Void, // get_slope_z_proc ClearTile_Void, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_Void, // get_tile_desc_proc GetTileTrackStatus_Void, // get_tile_track_status_proc - NULL, // click_tile_proc - NULL, // animate_tile_proc + nullptr, // click_tile_proc + nullptr, // animate_tile_proc TileLoop_Void, // tile_loop_proc ChangeTileOwner_Void, // change_tile_owner_proc - NULL, // add_produced_cargo_proc - NULL, // vehicle_enter_tile_proc + nullptr, // add_produced_cargo_proc + nullptr, // vehicle_enter_tile_proc GetFoundation_Void, // get_foundation_proc TerraformTile_Void, // terraform_tile_proc }; diff --git a/src/watch_gui.cpp b/src/watch_gui.cpp index cbb32dfc32..aa416cf6e6 100644 --- a/src/watch_gui.cpp +++ b/src/watch_gui.cpp @@ -322,15 +322,11 @@ void WatchCompany::DrawWidget(const Rect &r, int widget) const if ( Company::IsValidID( widget-EWW_HAS_CLIENT_FIRST ) ) { /* Draw the Blot only if Company Exists */ Dimension sprite_size = GetSpriteSize(SPR_BLOT); -#ifdef ENABLE_NETWORK if (!_networking) { // Local game, draw the Blot DrawSprite(SPR_BLOT, Company::IsValidAiID(widget - EWW_HAS_CLIENT_FIRST) ? PALETTE_TO_ORANGE : PALETTE_TO_GREEN, (r.left + r.right - sprite_size.width) / 2, (r.top + r.bottom - sprite_size.height) / 2 ); } else { // Network game, draw the blot according to company client count DrawSprite(SPR_BLOT, this->company_count_client[widget-EWW_HAS_CLIENT_FIRST] > 0 ? (company_activity[widget-EWW_HAS_CLIENT_FIRST] > 0 ? PALETTE_TO_RED : PALETTE_TO_GREEN) : PALETTE_TO_GREY, (r.left + r.right - sprite_size.width) / 2, (r.top + r.bottom - sprite_size.height) / 2 ); } -#else - DrawSprite(SPR_BLOT, Company::IsValidAiID(widget-EWW_HAS_CLIENT_FIRST) ? PALETTE_TO_ORANGE : PALETTE_TO_GREEN, (r.left + r.right - sprite_size.width) / 2, (r.top + r.bottom - sprite_size.height) / 2 ); -#endif } } } @@ -392,13 +388,11 @@ void WatchCompany::OnClick(Point pt, int widget, int click_count) this->SetDirty(); } } -#ifdef ENABLE_NETWORK else if ( IsInsideMM(widget, EWW_HAS_CLIENT_FIRST, EWW_HAS_CLIENT_LAST + 1)) { if(_networking && Company::IsValidID(widget - EWW_HAS_CLIENT_FIRST)){ ShowNetworkChatQueryWindow(DESTTYPE_TEAM, widget - EWW_HAS_CLIENT_FIRST); } } -#endif else { char msg[128]; switch (widget) { @@ -504,7 +498,6 @@ void WatchCompany::OnInvalidateData(int data, bool gui_scope) GetString( this->company_name, STR_JUST_NOTHING, lastof(this->company_name) ); } - #ifdef ENABLE_NETWORK if (_networking) { // Local game, draw the Blot /* Reset company count - network only */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { @@ -518,7 +511,6 @@ void WatchCompany::OnInvalidateData(int data, bool gui_scope) } } } - #endif } else if(this->Wtype == EWT_CLIENT){ if (data == 2) { @@ -554,7 +546,7 @@ void WatchCompany::ScrollToTile( TileIndex tile ) * @param company The company ID who's client is building * @param tile The tile number where action took place */ -void WatchCompany::OnDoCommand( CompanyByte company, TileIndex tile ) +void WatchCompany::OnDoCommand(CompanyID company, TileIndex tile ) { /* Check if its my company */ if (this->watched_company == company) diff --git a/src/watch_gui.h b/src/watch_gui.h index 4a49775819..c1686c77d5 100644 --- a/src/watch_gui.h +++ b/src/watch_gui.h @@ -82,7 +82,7 @@ public: virtual void OnPaint(); virtual void OnQueryTextFinished(char *str); - void OnDoCommand(CompanyByte company, TileIndex tile); + void OnDoCommand(CompanyID company, TileIndex tile); }; void ShowWatchWindow(CompanyID company_to_watch, int type); diff --git a/src/water.h b/src/water.h index 1b804720ff..9e2c23418a 100644 --- a/src/water.h +++ b/src/water.h @@ -38,6 +38,7 @@ void DrawWaterClassGround(const struct TileInfo *ti); void DrawShoreTile(Slope tileh); void MakeWaterKeepingClass(TileIndex tile, Owner o); +void CheckForDockingTile(TileIndex t); bool RiverModifyDesertZone(TileIndex tile, void *data); static const uint RIVER_OFFSET_DESERT_DISTANCE = 5; ///< Circular tile search radius to create non-desert around a river tile. diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 03b321e686..7091f9f2d4 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -39,6 +39,7 @@ #include "company_base.h" #include "company_gui.h" #include "newgrf_generic.h" +#include "industry.h" #include "table/strings.h" @@ -148,6 +149,8 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1); MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2); + CheckForDockingTile(tile); + CheckForDockingTile(tile2); MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile2); MakeDefaultName(depot); @@ -156,6 +159,48 @@ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, ui return cost; } +bool IsPossibleDockingTile(TileIndex t) +{ + assert(IsValidTile(t)); + switch (GetTileType(t)) { + case MP_WATER: + if (IsLock(t) && GetLockPart(t) == LOCK_PART_MIDDLE) return false; + FALLTHROUGH; + case MP_RAILWAY: + case MP_STATION: + case MP_TUNNELBRIDGE: + return TrackStatusToTrackBits(GetTileTrackStatus(t, TRANSPORT_WATER, 0)) != TRACK_BIT_NONE; + + default: + return false; + } +} + +/** + * Mark the supplied tile as a docking tile if it is suitable for docking. + * Tiles surrounding the tile are tested to be docks with correct orientation. + * @param t Tile to test. + */ +void CheckForDockingTile(TileIndex t) +{ + for (DiagDirection d = DIAGDIR_BEGIN; d != DIAGDIR_END; d++) { + TileIndex tile = t + TileOffsByDiagDir(d); + if (!IsValidTile(tile)) continue; + + if (IsDockTile(tile) && IsValidDockingDirectionForDock(tile, d)) { + Station::GetByTile(tile)->docking_station.Add(t); + SetDockingTile(t, true); + } + if (IsTileType(tile, MP_INDUSTRY)) { + Station *st = Industry::GetByTile(tile)->neutral_station; + if (st != nullptr) { + st->docking_station.Add(t); + SetDockingTile(t, true); + } + } + } +} + void MakeWaterKeepingClass(TileIndex tile, Owner o) { WaterClass wc = GetWaterClass(tile); @@ -168,7 +213,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o) if (wc == WATER_CLASS_CANAL) { /* If we clear the canal, we have to remove it from the infrastructure count as well. */ Company *c = Company::GetIfValid(o); - if (c != NULL) { + if (c != nullptr) { c->infrastructure.water--; DirtyCompanyInfrastructureWindows(c->index); } @@ -185,7 +230,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o) if (wc == WATER_CLASS_SEA && z > 0) { /* Update company infrastructure count. */ Company *c = Company::GetIfValid(o); - if (c != NULL) { + if (c != nullptr) { c->infrastructure.water++; DirtyCompanyInfrastructureWindows(c->index); } @@ -204,6 +249,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o) default: break; } + if (wc != WATER_CLASS_INVALID) CheckForDockingTile(tile); MarkTileDirtyByTile(tile); } @@ -227,7 +273,7 @@ static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags) delete Depot::GetByTile(tile); Company *c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + if (c != nullptr) { c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR; DirtyCompanyInfrastructureWindows(c->index); } @@ -293,7 +339,7 @@ static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag if (flags & DC_EXEC) { /* Update company infrastructure counts. */ Company *c = Company::GetIfValid(_current_company); - if (c != NULL) { + if (c != nullptr) { /* Counts for the water. */ if (!IsWaterTile(tile - delta)) c->infrastructure.water++; if (!IsWaterTile(tile + delta)) c->infrastructure.water++; @@ -303,6 +349,8 @@ static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag } MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle); + CheckForDockingTile(tile - delta); + CheckForDockingTile(tile + delta); MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile - delta); MarkTileDirtyByTile(tile + delta); @@ -338,7 +386,7 @@ static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { /* Remove middle part from company infrastructure count. */ Company *c = Company::GetIfValid(GetTileOwner(tile)); - if (c != NULL) { + if (c != nullptr) { c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // three parts of the lock. DirtyCompanyInfrastructureWindows(c->index); } @@ -428,7 +476,7 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 MakeRiver(tile, Random()); if (_game_mode == GM_EDITOR) { TileIndex tile2 = tile; - CircularTileSearch(&tile2, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, NULL); + CircularTileSearch(&tile2, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr); } break; @@ -449,6 +497,7 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } MarkTileDirtyByTile(tile); MarkCanalsAndRiversAroundDirty(tile); + CheckForDockingTile(tile); } cost.AddCost(_price[PR_BUILD_CANAL]); @@ -489,8 +538,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags) Company::Get(owner)->infrastructure.water--; DirtyCompanyInfrastructureWindows(owner); } + bool remove = IsDockingTile(tile); DoClearSquare(tile); MarkCanalsAndRiversAroundDirty(tile); + if (remove) RemoveDockingTile(tile); } return CommandCost(EXPENSES_CONSTRUCTION, base_cost); @@ -504,8 +555,10 @@ static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags) if (ret.Failed()) return ret; if (flags & DC_EXEC) { + bool remove = IsDockingTile(tile); DoClearSquare(tile); MarkCanalsAndRiversAroundDirty(tile); + if (remove) RemoveDockingTile(tile); } if (IsSlopeWithOneCornerRaised(slope)) { return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]); @@ -931,11 +984,11 @@ static void FloodVehicle(Vehicle *v) * Flood a vehicle if we are allowed to flood it, i.e. when it is on the ground. * @param v The vehicle to test for flooding. * @param data The z of level to flood. - * @return NULL as we always want to remove everything. + * @return nullptr as we always want to remove everything. */ static Vehicle *FloodVehicleProc(Vehicle *v, void *data) { - if ((v->vehstatus & VS_CRASHED) != 0) return NULL; + if ((v->vehstatus & VS_CRASHED) != 0) return nullptr; switch (v->type) { default: break; @@ -963,7 +1016,7 @@ static Vehicle *FloodVehicleProc(Vehicle *v, void *data) } } - return NULL; + return nullptr; } /** @@ -1044,7 +1097,7 @@ void DoFloodTile(TileIndex target) bool flooded = false; // Will be set to true if something is changed. - Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); + Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); Slope tileh = GetTileSlope(target); if (tileh != SLOPE_FLAT) { @@ -1095,6 +1148,8 @@ void DoFloodTile(TileIndex target) /* update signals if needed */ UpdateSignalsInBuffer(); + + if (IsPossibleDockingTile(target)) CheckForDockingTile(target); } cur_company.Restore(); @@ -1105,7 +1160,7 @@ void DoFloodTile(TileIndex target) */ static void DoDryUp(TileIndex tile) { - Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); + Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); switch (GetTileType(tile)) { case MP_RAILWAY: @@ -1321,14 +1376,14 @@ extern const TileTypeProcs _tile_type_water_procs = { DrawTile_Water, // draw_tile_proc GetSlopePixelZ_Water, // get_slope_z_proc ClearTile_Water, // clear_tile_proc - NULL, // add_accepted_cargo_proc + nullptr, // add_accepted_cargo_proc GetTileDesc_Water, // get_tile_desc_proc GetTileTrackStatus_Water, // get_tile_track_status_proc ClickTile_Water, // click_tile_proc - NULL, // animate_tile_proc + nullptr, // animate_tile_proc TileLoop_Water, // tile_loop_proc ChangeTileOwner_Water, // change_tile_owner_proc - NULL, // add_produced_cargo_proc + nullptr, // add_produced_cargo_proc VehicleEnter_Water, // vehicle_enter_tile_proc GetFoundation_Water, // get_foundation_proc TerraformTile_Water, // terraform_tile_proc diff --git a/src/water_map.h b/src/water_map.h index 5d84d5ba66..05f49afb13 100644 --- a/src/water_map.h +++ b/src/water_map.h @@ -28,8 +28,8 @@ enum WaterTileTypeBitLayout { WBL_COAST_FLAG = 0, ///< Flag for coast. - WBL_LOCK_ORIENT_BEGIN = 0, ///< Start of lock orientiation bitfield. - WBL_LOCK_ORIENT_COUNT = 2, ///< Length of lock orientiation bitfield. + WBL_LOCK_ORIENT_BEGIN = 0, ///< Start of lock orientation bitfield. + WBL_LOCK_ORIENT_COUNT = 2, ///< Length of lock orientation bitfield. WBL_LOCK_PART_BEGIN = 2, ///< Start of lock part bitfield. WBL_LOCK_PART_COUNT = 2, ///< Length of lock part bitfield. @@ -69,6 +69,8 @@ enum LockPart { LOCK_PART_UPPER = 2, ///< Upper part of a lock. }; +bool IsPossibleDockingTile(TileIndex t); + /** * Get the water tile type at a tile. * @param t Water tile to query. @@ -346,6 +348,27 @@ static inline bool HasTileWaterGround(TileIndex t) return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t); } +/** + * Set the docking tile state of a tile. This is used by pathfinders to reach their destination. + * As well as water tiles, half-rail tiles, buoys and aqueduct ends can also be docking tiles. + * @param t the tile + * @param b the docking tile state + */ +static inline void SetDockingTile(TileIndex t, bool b) +{ + assert(IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)); + SB(_m[t].m1, 7, 1, b ? 1 : 0); +} + +/** + * Checks whether the tile is marked as a dockling tile. + * @return true iff the tile is marked as a docking tile. + */ +static inline bool IsDockingTile(TileIndex t) +{ + return (IsTileType(t, MP_WATER) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)) && HasBit(_m[t].m1, 7); +} + /** * Helper function to make a coast tile. @@ -356,6 +379,7 @@ static inline void MakeShore(TileIndex t) SetTileType(t, MP_WATER); SetTileOwner(t, OWNER_WATER); SetWaterClass(t, WATER_CLASS_SEA); + SetDockingTile(t, false); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; @@ -376,6 +400,7 @@ static inline void MakeWater(TileIndex t, Owner o, WaterClass wc, uint8 random_b SetTileType(t, MP_WATER); SetTileOwner(t, o); SetWaterClass(t, wc); + SetDockingTile(t, false); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = random_bits; @@ -429,6 +454,7 @@ static inline void MakeShipDepot(TileIndex t, Owner o, DepotID did, DepotPart pa SetTileType(t, MP_WATER); SetTileOwner(t, o); SetWaterClass(t, original_water_class); + SetDockingTile(t, false); _m[t].m2 = did; _m[t].m3 = 0; _m[t].m4 = 0; @@ -451,6 +477,7 @@ static inline void MakeLockTile(TileIndex t, Owner o, LockPart part, DiagDirecti SetTileType(t, MP_WATER); SetTileOwner(t, o); SetWaterClass(t, original_water_class); + SetDockingTile(t, false); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; diff --git a/src/waypoint.cpp b/src/waypoint.cpp index 857f8ba874..8452ff6186 100644 --- a/src/waypoint.cpp +++ b/src/waypoint.cpp @@ -15,6 +15,7 @@ #include "window_func.h" #include "newgrf_station.h" #include "waypoint_base.h" +#include "viewport_kdtree.h" #include "safeguards.h" @@ -54,4 +55,5 @@ Waypoint::~Waypoint() if (CleaningPool()) return; DeleteWindowById(WC_WAYPOINT_VIEW, this->index); RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index); + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeWaypoint(this->index)); } diff --git a/src/waypoint_base.h b/src/waypoint_base.h index 8d544a3b99..be1d0bd0df 100644 --- a/src/waypoint_base.h +++ b/src/waypoint_base.h @@ -25,23 +25,25 @@ struct Waypoint FINAL : SpecializedStation { Waypoint(TileIndex tile = INVALID_TILE) : SpecializedStation(tile) { } ~Waypoint(); - void UpdateVirtCoord(); + void UpdateVirtCoord() override; - /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const + void MoveSign(TileIndex new_xy) override; + + inline bool TileBelongsToRailStation(TileIndex tile) const override { return IsRailWaypointTile(tile) && GetStationIndex(tile) == this->index; } - /* virtual */ uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const; + uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const override; - /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; + void GetTileArea(TileArea *ta, StationType type) const override; - /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const + uint GetPlatformLength(TileIndex tile, DiagDirection dir) const override { return 1; } - /* virtual */ uint GetPlatformLength(TileIndex tile) const + uint GetPlatformLength(TileIndex tile) const override { return 1; } diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp index 639dce13bc..652173a947 100644 --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -20,6 +20,7 @@ #include "pathfinder/yapf/yapf_cache.h" #include "strings_func.h" #include "viewport_func.h" +#include "viewport_kdtree.h" #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" @@ -46,6 +47,21 @@ void Waypoint::UpdateVirtCoord() InvalidateWindowData(WC_WAYPOINT_VIEW, this->index); } +/** + * Move the waypoint main coordinate somewhere else. + * @param new_xy new tile location of the sign + */ +void Waypoint::MoveSign(TileIndex new_xy) +{ + if (this->xy == new_xy) return; + + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeWaypoint(this->index)); + + this->BaseStation::MoveSign(new_xy); + + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeWaypoint(this->index)); +} + /** * Find a deleted waypoint close to a tile. * @param tile to search from @@ -55,7 +71,7 @@ void Waypoint::UpdateVirtCoord() */ static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile, StringID str, CompanyID cid) { - Waypoint *wp, *best = NULL; + Waypoint *wp, *best = nullptr; uint thres = 8; FOR_ALL_WAYPOINTS(wp) { @@ -107,7 +123,7 @@ static CommandCost IsValidTileForWaypoint(TileIndex tile, Axis axis, StationID * /* if waypoint is set, then we have special handling to allow building on top of already existing waypoints. * so waypoint points to INVALID_STATION if we can build on any waypoint. * Or it points to a waypoint if we're only allowed to build on exactly that waypoint. */ - if (waypoint != NULL && IsTileType(tile, MP_STATION)) { + if (waypoint != nullptr && IsTileType(tile, MP_STATION)) { if (!IsRailWaypoint(tile)) { return ClearTile_Station(tile, DC_AUTO); // get error message } else { @@ -198,16 +214,16 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint if (ret.Failed()) return ret; } - Waypoint *wp = NULL; - TileArea new_location(TileArea(start_tile, width, height)); + Waypoint *wp = nullptr; + TileArea new_location(start_tile, width, height); CommandCost ret = FindJoiningWaypoint(est, station_to_join, adjacent, new_location, &wp); if (ret.Failed()) return ret; /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ TileIndex center_tile = start_tile + (count / 2) * offset; - if (wp == NULL && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company); + if (wp == nullptr && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company); - if (wp != NULL) { + if (wp != nullptr) { /* Reuse an existing waypoint. */ if (wp->owner != _current_company) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT); @@ -225,11 +241,15 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint } if (flags & DC_EXEC) { - if (wp == NULL) { + bool need_sign_update = false; + if (wp == nullptr) { wp = new Waypoint(start_tile); + need_sign_update = true; } else if (!wp->IsInUse()) { /* Move existing (recently deleted) waypoint to the new location */ + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); wp->xy = start_tile; + need_sign_update = true; } wp->owner = GetTileOwner(start_tile); @@ -241,13 +261,14 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint wp->string_id = STR_SV_STNAME_WAYPOINT; wp->train_station = new_location; - if (wp->town == NULL) MakeDefaultName(wp); + if (wp->town == nullptr) MakeDefaultName(wp); wp->UpdateVirtCoord(); + if (need_sign_update) _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); const StationSpec *spec = StationClass::Get(spec_class)->GetSpec(spec_index); byte *layout_ptr = AllocaM(byte, count); - if (spec == NULL) { + if (spec == nullptr) { /* The layout must be 0 for the 'normal' waypoints by design. */ memset(layout_ptr, 0, count); } else { @@ -296,7 +317,7 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ Waypoint *wp = FindDeletedWaypointCloseTo(tile, STR_SV_STNAME_BUOY, OWNER_NONE); - if (wp == NULL && !Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); + if (wp == nullptr && !Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_WAYPOINT_BUOY]); if (!IsWaterTile(tile)) { @@ -306,10 +327,11 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 } if (flags & DC_EXEC) { - if (wp == NULL) { + if (wp == nullptr) { wp = new Waypoint(tile); } else { /* Move existing (recently deleted) buoy to the new location */ + _viewport_sign_kdtree.Remove(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); wp->xy = tile; InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index); } @@ -322,12 +344,14 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 wp->build_date = _date; - if (wp->town == NULL) MakeDefaultName(wp); + if (wp->town == nullptr) MakeDefaultName(wp); MakeBuoy(tile, wp->index, GetWaterClass(tile)); + CheckForDockingTile(tile); MarkTileDirtyByTile(tile); wp->UpdateVirtCoord(); + _viewport_sign_kdtree.Insert(ViewportSignKdtreeItem::MakeWaypoint(wp->index)); InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index); } @@ -384,7 +408,7 @@ static bool IsUniqueWaypointName(const char *name) const Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { - if (wp->name != NULL && strcmp(wp->name, name) == 0) return false; + if (wp->name != nullptr && strcmp(wp->name, name) == 0) return false; } return true; @@ -402,7 +426,7 @@ static bool IsUniqueWaypointName(const char *name) CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Waypoint *wp = Waypoint::GetIfValid(p1); - if (wp == NULL) return CMD_ERROR; + if (wp == nullptr) return CMD_ERROR; if (wp->owner != OWNER_NONE) { CommandCost ret = CheckOwnership(wp->owner); @@ -418,7 +442,7 @@ CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, ui if (flags & DC_EXEC) { free(wp->name); - wp->name = reset ? NULL : stredup(text); + wp->name = reset ? nullptr : stredup(text); wp->UpdateVirtCoord(); } diff --git a/src/waypoint_gui.cpp b/src/waypoint_gui.cpp index fa4deaac68..54578a4bb5 100644 --- a/src/waypoint_gui.cpp +++ b/src/waypoint_gui.cpp @@ -81,12 +81,12 @@ public: DeleteWindowById(GetWindowClassForVehicleType(this->vt), VehicleListIdentifier(VL_STATION_LIST, this->vt, this->owner, this->window_number).Pack(), false); } - virtual void SetStringParameters(int widget) const + void SetStringParameters(int widget) const override { if (widget == WID_W_CAPTION) SetDParam(0, this->wp->index); } - virtual void OnClick(Point pt, int widget, int click_count) + void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_W_CENTER_VIEW: // scroll to location @@ -113,7 +113,7 @@ public: * @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) + void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; /* You can only change your own waypoints */ @@ -124,9 +124,9 @@ public: ScrollWindowToTile(this->GetCenterTile(), this, true); } - virtual void OnResize() + void OnResize() override { - if (this->viewport != NULL) { + if (this->viewport != nullptr) { NWidgetViewport *nvp = this->GetWidget(WID_W_VIEWPORT); nvp->UpdateViewportCoordinates(this); this->wp->UpdateVirtCoord(); @@ -135,11 +135,11 @@ public: } } - virtual void OnQueryTextFinished(char *str) + void OnQueryTextFinished(char *str) override { - if (str == NULL) return; + if (str == nullptr) return; - DoCommandP(0, this->window_number, 0, CMD_RENAME_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME), NULL, str); + DoCommandP(0, this->window_number, 0, CMD_RENAME_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME), nullptr, str); } }; diff --git a/src/widget.cpp b/src/widget.cpp index 96e66ab7ad..e226dd9d37 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -147,7 +147,7 @@ void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y) ma = nw->pos_y + nw->current_y; } NWidgetScrollbar *scrollbar = dynamic_cast(nw); - assert(scrollbar != NULL); + assert(scrollbar != nullptr); ScrollbarClickPositioning(w, scrollbar, x, y, mi, ma); } @@ -162,7 +162,7 @@ void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y) int GetWidgetFromPos(const Window *w, int x, int y) { NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); - return (nw != NULL) ? nw->index : -1; + return (nw != nullptr) ? nw->index : -1; } /** @@ -614,7 +614,7 @@ void Window::DrawWidgets() const extern bool _window_highlight_colour; for (uint i = 0; i < this->nested_array_size; i++) { const NWidgetBase *widget = this->GetWidget(i); - if (widget == NULL || !widget->IsHighlighted()) continue; + if (widget == nullptr || !widget->IsHighlighted()) continue; int left = widget->pos_x; int top = widget->pos_y; @@ -640,7 +640,7 @@ void Window::DrawSortButtonState(int widget, SortButtonState state) const { if (state == SBS_OFF) return; - assert(this->nested_array != NULL); + assert(this->nested_array != nullptr); const NWidgetBase *nwid = this->GetWidget(widget); /* Sort button uses the same sprites as vertical scrollbar */ @@ -785,17 +785,17 @@ void NWidgetBase::SetDirty(const Window *w) const * Retrieve a widget by its position. * @param x Horizontal position relative to the left edge of the window. * @param y Vertical position relative to the top edge of the window. - * @return Returns the deepest nested widget that covers the given position, or \c NULL if no widget can be found. + * @return Returns the deepest nested widget that covers the given position, or \c nullptr if no widget can be found. */ /** * Retrieve a widget by its type. * @param tp Widget type to search for. - * @return Returns the first widget of the specified type, or \c NULL if no widget can be found. + * @return Returns the first widget of the specified type, or \c nullptr if no widget can be found. */ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) { - return (this->type == tp) ? this : NULL; + return (this->type == tp) ? this : nullptr; } /** @@ -905,7 +905,7 @@ void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length) NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) { - return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : NULL; + return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : nullptr; } /** @@ -914,28 +914,28 @@ NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) */ NWidgetContainer::NWidgetContainer(WidgetType tp) : NWidgetBase(tp) { - this->head = NULL; - this->tail = NULL; + this->head = nullptr; + this->tail = nullptr; } NWidgetContainer::~NWidgetContainer() { - while (this->head != NULL) { + while (this->head != nullptr) { NWidgetBase *wid = this->head->next; delete this->head; this->head = wid; } - this->tail = NULL; + this->tail = nullptr; } NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) { if (this->type == tp) return this; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { NWidgetBase *nwid = child_wid->GetWidgetOfType(tp); - if (nwid != NULL) return nwid; + if (nwid != nullptr) return nwid; } - return NULL; + return nullptr; } /** @@ -944,14 +944,14 @@ NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) */ void NWidgetContainer::Add(NWidgetBase *wid) { - assert(wid->next == NULL && wid->prev == NULL); + assert(wid->next == nullptr && wid->prev == nullptr); - if (this->head == NULL) { + if (this->head == nullptr) { this->head = wid; this->tail = wid; } else { - assert(this->tail != NULL); - assert(this->tail->next == NULL); + assert(this->tail != nullptr); + assert(this->tail->next == nullptr); this->tail->next = wid; wid->prev = this->tail; @@ -961,7 +961,7 @@ void NWidgetContainer::Add(NWidgetBase *wid) void NWidgetContainer::FillNestedArray(NWidgetBase **array, uint length) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->FillNestedArray(array, length); } } @@ -1007,11 +1007,11 @@ void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) /* First sweep, recurse down and compute minimal size and filling. */ this->smallest_x = 0; this->smallest_y = 0; - this->fill_x = (this->head != NULL) ? 1 : 0; - this->fill_y = (this->head != NULL) ? 1 : 0; - this->resize_x = (this->head != NULL) ? 1 : 0; - this->resize_y = (this->head != NULL) ? 1 : 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + this->fill_x = (this->head != nullptr) ? 1 : 0; + this->fill_y = (this->head != nullptr) ? 1 : 0; + this->resize_x = (this->head != nullptr) ? 1 : 0; + this->resize_y = (this->head != nullptr) ? 1 : 0; + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); @@ -1030,7 +1030,7 @@ void NWidgetStacked::AssignSizePosition(SizingType sizing, uint x, uint y, uint if (this->shown_plane >= SZSP_BEGIN) return; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); uint child_width = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); uint child_pos_x = (rtl ? child_wid->padding_right : child_wid->padding_left); @@ -1054,7 +1054,7 @@ void NWidgetStacked::Draw(const Window *w) if (this->shown_plane >= SZSP_BEGIN) return; int plane = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; plane++, child_wid = child_wid->next) { if (plane == this->shown_plane) { child_wid->Draw(w); return; @@ -1066,16 +1066,16 @@ void NWidgetStacked::Draw(const Window *w) NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y) { - if (this->shown_plane >= SZSP_BEGIN) return NULL; + if (this->shown_plane >= SZSP_BEGIN) return nullptr; - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; int plane = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; plane++, child_wid = child_wid->next) { if (plane == this->shown_plane) { return child_wid->GetWidgetFromPos(x, y); } } - return NULL; + return nullptr; } /** @@ -1110,20 +1110,20 @@ void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) void NWidgetPIPContainer::Draw(const Window *w) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->Draw(w); } } NWidgetCore *NWidgetPIPContainer::GetWidgetFromPos(int x, int y) { - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); - if (nwid != NULL) return nwid; + if (nwid != nullptr) return nwid; } - return NULL; + return nullptr; } /** Horizontal container widget. */ @@ -1143,7 +1143,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ uint longest = 0; // Longest child found. uint max_vert_fill = 0; // Biggest vertical fill step. - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); longest = max(longest, child_wid->smallest_x); max_vert_fill = max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); @@ -1153,7 +1153,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) uint max_smallest = this->smallest_y + 3 * max_vert_fill; // Upper limit to computing smallest height. uint cur_height = this->smallest_y; for (;;) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint step_size = child_wid->GetVerticalStepSize(ST_SMALLEST); uint child_height = child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; if (step_size > 1 && child_height < cur_height) { // Small step sizes or already fitting children are not interesting. @@ -1170,14 +1170,14 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) } /* 2. For containers that must maintain equal width, extend child minimal size. */ if (this->flags & NC_EQUALSIZE) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (child_wid->fill_x == 1) child_wid->smallest_x = longest; } } /* 3. Move PIP space to the children, compute smallest, fill, and resize values of the container. */ - if (this->head != NULL) this->head->padding_left += this->pip_pre; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->next != NULL) { + if (this->head != nullptr) this->head->padding_left += this->pip_pre; + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + if (child_wid->next != nullptr) { child_wid->padding_right += this->pip_inter; } else { child_wid->padding_right += this->pip_post; @@ -1206,7 +1206,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, ui uint additional_length = given_width; if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { additional_length -= child_wid->smallest_x + child_wid->padding_right + child_wid->padding_left; } } else { @@ -1231,7 +1231,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, ui */ int num_changing_childs = 0; // Number of children that can change size. uint biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step > 0) { num_changing_childs++; @@ -1247,7 +1247,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, ui /* Second loop: Allocate the additional horizontal space over the resizing children, starting with the biggest resize steps. */ while (biggest_stepsize > 0) { uint next_biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step > biggest_stepsize) continue; // Already done if (hor_step == biggest_stepsize) { @@ -1267,7 +1267,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, ui /* Third loop: Compute position and call the child. */ uint position = rtl ? this->current_x : 0; // Place to put next child relative to origin of the container. NWidgetBase *child_wid = this->head; - while (child_wid != NULL) { + while (child_wid != nullptr) { uint child_width = child_wid->current_x; uint child_x = x + (rtl ? position - child_width - child_wid->padding_left : position + child_wid->padding_left); uint child_y = y + child_wid->padding_top; @@ -1308,7 +1308,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ uint highest = 0; // Highest child found. uint max_hor_fill = 0; // Biggest horizontal fill step. - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); highest = max(highest, child_wid->smallest_y); max_hor_fill = max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); @@ -1318,7 +1318,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) uint max_smallest = this->smallest_x + 3 * max_hor_fill; // Upper limit to computing smallest height. uint cur_width = this->smallest_x; for (;;) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint step_size = child_wid->GetHorizontalStepSize(ST_SMALLEST); uint child_width = child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; if (step_size > 1 && child_width < cur_width) { // Small step sizes or already fitting children are not interesting. @@ -1335,14 +1335,14 @@ void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) } /* 2. For containers that must maintain equal width, extend children minimal size. */ if (this->flags & NC_EQUALSIZE) { - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { if (child_wid->fill_y == 1) child_wid->smallest_y = highest; } } /* 3. Move PIP space to the child, compute smallest, fill, and resize values of the container. */ - if (this->head != NULL) this->head->padding_top += this->pip_pre; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { - if (child_wid->next != NULL) { + if (this->head != nullptr) this->head->padding_top += this->pip_pre; + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + if (child_wid->next != nullptr) { child_wid->padding_bottom += this->pip_inter; } else { child_wid->padding_bottom += this->pip_post; @@ -1371,7 +1371,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint uint additional_length = given_height; if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { additional_length -= child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; } } else { @@ -1387,7 +1387,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle horizontal size for all children, handle vertical size for non-resizing child. */ int num_changing_childs = 0; // Number of children that can change size. uint biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step > 0) { num_changing_childs++; @@ -1403,7 +1403,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint /* Second loop: Allocate the additional vertical space over the resizing children, starting with the biggest resize steps. */ while (biggest_stepsize > 0) { uint next_biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step > biggest_stepsize) continue; // Already done if (vert_step == biggest_stepsize) { @@ -1422,7 +1422,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint /* Third loop: Compute position and call the child. */ uint position = 0; // Place to put next child relative to origin of the container. - for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { uint child_x = x + (rtl ? child_wid->padding_right : child_wid->padding_left); uint child_height = child_wid->current_y; @@ -1464,7 +1464,7 @@ void NWidgetSpacer::SetDirty(const Window *w) const NWidgetCore *NWidgetSpacer::GetWidgetFromPos(int x, int y) { - return NULL; + return nullptr; } NWidgetMatrix::NWidgetMatrix() : NWidgetPIPContainer(NWID_MATRIX, NC_EQUALSIZE), index(-1), clicked(-1), count(-1) @@ -1488,7 +1488,7 @@ void NWidgetMatrix::SetColour(Colours colour) void NWidgetMatrix::SetClicked(int clicked) { this->clicked = clicked; - if (this->clicked >= 0 && this->sb != NULL && this->widgets_x != 0) { + if (this->clicked >= 0 && this->sb != nullptr && this->widgets_x != 0) { int vpos = (this->clicked / this->widgets_x) * this->widget_h; // Vertical position of the top. /* Need to scroll down -> Scroll to the bottom. * However, last entry has no 'this->pip_inter' underneath, and we must stay below this->sb->GetCount() */ @@ -1506,7 +1506,7 @@ void NWidgetMatrix::SetCount(int count) { this->count = count; - if (this->sb == NULL || this->widgets_x == 0) return; + if (this->sb == nullptr || this->widgets_x == 0) return; /* We need to get the number of pixels the matrix is high/wide. * So, determine the number of rows/columns based on the number of @@ -1533,8 +1533,8 @@ void NWidgetMatrix::SetScrollbar(Scrollbar *sb) void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array) { - assert(this->head != NULL); - assert(this->head->next == NULL); + assert(this->head != nullptr); + assert(this->head->next == nullptr); if (this->index >= 0 && init_array) { // Fill w->nested_array[] assert(w->nested_array_size > (uint)this->index); @@ -1543,7 +1543,7 @@ void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array) /* Reset the widget number. */ NWidgetCore *nw = dynamic_cast(this->head); - assert(nw != NULL); + assert(nw != nullptr); SB(nw->index, 16, 16, 0); this->head->SetupSmallestSize(w, init_array); @@ -1595,7 +1595,7 @@ void NWidgetMatrix::FillNestedArray(NWidgetBase **array, uint length) NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) { /* Falls outside of the matrix widget. */ - if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; + if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; int start_x, start_y, base_offs_x, base_offs_y; this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); @@ -1610,10 +1610,10 @@ NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) int widget_row = (y - base_offs_y - (int)this->pip_pre - (int)this->pos_y) / this->widget_h; int sub_wid = (widget_row + start_y) * this->widgets_x + start_x + widget_col; - if (sub_wid >= this->count) return NULL; + if (sub_wid >= this->count) return nullptr; NWidgetCore *child = dynamic_cast(this->head); - assert(child != NULL); + assert(child != nullptr); child->AssignSizePosition(ST_RESIZE, this->pos_x + (rtl ? this->pip_post - widget_col * this->widget_w : this->pip_pre + widget_col * this->widget_w) + base_offs_x, this->pos_y + this->pip_pre + widget_row * this->widget_h + base_offs_y, @@ -1638,7 +1638,7 @@ NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) /* Get the appropriate offsets so we can draw the right widgets. */ NWidgetCore *child = dynamic_cast(this->head); - assert(child != NULL); + assert(child != nullptr); int start_x, start_y, base_offs_x, base_offs_y; this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); @@ -1685,7 +1685,7 @@ void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_ base_offs_y = 0; start_x = 0; start_y = 0; - if (this->sb != NULL) { + if (this->sb != nullptr) { if (this->sb->IsVertical()) { start_y = this->sb->GetPosition() / this->widget_h; base_offs_y += -this->sb->GetPosition() + start_y * this->widget_h; @@ -1719,7 +1719,7 @@ NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, N NWidgetBackground::~NWidgetBackground() { - if (this->child != NULL) delete this->child; + if (this->child != nullptr) delete this->child; } /** @@ -1731,7 +1731,7 @@ NWidgetBackground::~NWidgetBackground() */ void NWidgetBackground::Add(NWidgetBase *nwid) { - if (this->child == NULL) { + if (this->child == nullptr) { this->child = new NWidgetVertical(); } this->child->Add(nwid); @@ -1749,7 +1749,7 @@ void NWidgetBackground::Add(NWidgetBase *nwid) */ void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) { - if (this->child == NULL) { + if (this->child == nullptr) { this->child = new NWidgetVertical(); } this->child->SetPIP(pip_pre, pip_inter, pip_post); @@ -1761,7 +1761,7 @@ void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } - if (this->child != NULL) { + if (this->child != nullptr) { this->child->SetupSmallestSize(w, init_array); this->smallest_x = this->child->smallest_x; @@ -1772,7 +1772,7 @@ void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) this->resize_y = this->child->resize_y; /* Account for the size of the frame's text if that exists */ - if (w != NULL && this->type == WWT_FRAME) { + if (w != nullptr && this->type == WWT_FRAME) { this->child->padding_left = WD_FRAMETEXT_LEFT; this->child->padding_right = WD_FRAMETEXT_RIGHT; this->child->padding_top = max((int)WD_FRAMETEXT_TOP, this->widget_data != STR_NULL ? FONT_HEIGHT_NORMAL + WD_FRAMETEXT_TOP / 2 : 0); @@ -1788,7 +1788,7 @@ void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) Dimension d = {this->min_x, this->min_y}; Dimension fill = {this->fill_x, this->fill_y}; Dimension resize = {this->resize_x, this->resize_y}; - if (w != NULL) { // A non-NULL window pointer acts as switch to turn dynamic widget size on. + if (w != nullptr) { // A non-nullptr window pointer acts as switch to turn dynamic widget size on. if (this->type == WWT_FRAME || this->type == WWT_INSET) { if (this->index >= 0) w->SetStringParameters(this->index); Dimension background = GetStringBoundingBox(this->widget_data); @@ -1813,7 +1813,7 @@ void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, ui { this->StoreSizePosition(sizing, x, y, given_width, given_height); - if (this->child != NULL) { + if (this->child != nullptr) { uint x_offset = (rtl ? this->child->padding_right : this->child->padding_left); uint width = given_width - this->child->padding_right - this->child->padding_left; uint height = given_height - this->child->padding_top - this->child->padding_bottom; @@ -1824,7 +1824,7 @@ void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, ui void NWidgetBackground::FillNestedArray(NWidgetBase **array, uint length) { if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; - if (this->child != NULL) this->child->FillNestedArray(array, length); + if (this->child != nullptr) this->child->FillNestedArray(array, length); } void NWidgetBackground::Draw(const Window *w) @@ -1861,7 +1861,7 @@ void NWidgetBackground::Draw(const Window *w) } if (this->index >= 0) w->DrawWidget(r, this->index); - if (this->child != NULL) this->child->Draw(w); + if (this->child != nullptr) this->child->Draw(w); if (this->IsDisabled()) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); @@ -1870,19 +1870,19 @@ void NWidgetBackground::Draw(const Window *w) NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y) { - NWidgetCore *nwid = NULL; + NWidgetCore *nwid = nullptr; if (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) { - if (this->child != NULL) nwid = this->child->GetWidgetFromPos(x, y); - if (nwid == NULL) nwid = this; + if (this->child != nullptr) nwid = this->child->GetWidgetFromPos(x, y); + if (nwid == nullptr) nwid = this; } return nwid; } NWidgetBase *NWidgetBackground::GetWidgetOfType(WidgetType tp) { - NWidgetBase *nwid = NULL; - if (this->child != NULL) nwid = this->child->GetWidgetOfType(tp); - if (nwid == NULL && this->type == tp) nwid = this; + NWidgetBase *nwid = nullptr; + if (this->child != nullptr) nwid = this->child->GetWidgetOfType(tp); + if (nwid == nullptr && this->type == tp) nwid = this; return nwid; } @@ -1937,7 +1937,7 @@ void NWidgetViewport::InitializeViewport(Window *w, uint32 follow_flags, ZoomLev void NWidgetViewport::UpdateViewportCoordinates(Window *w) { ViewPort *vp = w->viewport; - if (vp != NULL) { + if (vp != nullptr) { vp->left = w->left + this->pos_x; vp->top = w->top + this->pos_y; vp->width = this->current_x; @@ -2208,7 +2208,7 @@ void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array) Dimension fill = {this->fill_x, this->fill_y}; Dimension resize = {this->resize_x, this->resize_y}; /* Get padding, and update size with the real content size if appropriate. */ - const Dimension *padding = NULL; + const Dimension *padding = nullptr; switch (this->type) { case WWT_EMPTY: { static const Dimension extra = {0, 0}; @@ -2465,7 +2465,7 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_EDITBOX: { const QueryString *query = w->GetQueryString(this->index); - if (query != NULL) query->DrawEditBox(w, this->index); + if (query != nullptr) query->DrawEditBox(w, this->index); break; } @@ -2495,7 +2495,7 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_RESIZEBOX: assert(this->widget_data == 0); - DrawResizeBox(r, this->colour, this->pos_x < (uint)(w->width / 2), !!(w->flags & WF_SIZING)); + DrawResizeBox(r, this->colour, this->pos_x < (w->width / 2), !!(w->flags & WF_SIZING)); break; case WWT_CLOSEBOX: @@ -2558,30 +2558,30 @@ bool NWidgetLeaf::ButtonHit(const Point &pt) * @param fill_dest Fill the composed widget with child widgets. * @param biggest_index Pointer to biggest nested widget index in the tree encountered so far. * @return Number of widget part elements used to compose the widget. - * @pre \c biggest_index != NULL. + * @pre \c biggest_index != nullptr. */ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, bool *fill_dest, int *biggest_index) { int num_used = 0; - *dest = NULL; + *dest = nullptr; *fill_dest = false; while (count > num_used) { switch (parts->type) { case NWID_SPACER: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetSpacer(0, 0); break; case NWID_HORIZONTAL: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetHorizontal(parts->u.cont_flags); *fill_dest = true; break; case NWID_HORIZONTAL_LTR: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetHorizontalLTR(parts->u.cont_flags); *fill_dest = true; break; @@ -2589,20 +2589,20 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, case WWT_PANEL: case WWT_INSET: case WWT_FRAME: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetBackground(parts->type, parts->u.widget.colour, parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); *fill_dest = true; break; case NWID_VERTICAL: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetVertical(parts->u.cont_flags); *fill_dest = true; break; case NWID_MATRIX: { - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; NWidgetMatrix *nwm = new NWidgetMatrix(); *dest = nwm; *fill_dest = true; @@ -2613,7 +2613,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, } case WPT_FUNCTION: { - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; /* Ensure proper functioning even when the called code simply writes its largest index. */ int biggest = -1; *dest = parts->u.func_ptr(&biggest); @@ -2624,7 +2624,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, case WPT_RESIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { + if (nwrb != nullptr) { assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); nwrb->SetResize(parts->u.xy.x, parts->u.xy.y); } @@ -2633,7 +2633,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, case WPT_MINSIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { + if (nwrb != nullptr) { assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); nwrb->SetMinimalSize(ScaleGUITrad(parts->u.xy.x), ScaleGUITrad(parts->u.xy.y)); } @@ -2642,7 +2642,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, case WPT_MINTEXTLINES: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) { + if (nwrb != nullptr) { assert(parts->u.text_lines.size >= FS_BEGIN && parts->u.text_lines.size < FS_END); nwrb->SetMinimalTextLines(parts->u.text_lines.lines, parts->u.text_lines.spacing, parts->u.text_lines.size); } @@ -2651,13 +2651,13 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, case WPT_FILL: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); - if (nwrb != NULL) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y); + if (nwrb != nullptr) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y); break; } case WPT_DATATIP: { NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != NULL) { + if (nwc != nullptr) { nwc->widget_data = parts->u.data_tip.data; nwc->tool_tip = parts->u.data_tip.tooltip; } @@ -2665,21 +2665,21 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, } case WPT_PADDING: - if (*dest != NULL) (*dest)->SetPadding(ScaleGUITrad(parts->u.padding.top), ScaleGUITrad(parts->u.padding.right), ScaleGUITrad(parts->u.padding.bottom), ScaleGUITrad(parts->u.padding.left)); + if (*dest != nullptr) (*dest)->SetPadding(ScaleGUITrad(parts->u.padding.top), ScaleGUITrad(parts->u.padding.right), ScaleGUITrad(parts->u.padding.bottom), ScaleGUITrad(parts->u.padding.left)); break; case WPT_PIPSPACE: { NWidgetPIPContainer *nwc = dynamic_cast(*dest); - if (nwc != NULL) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); + if (nwc != nullptr) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); NWidgetBackground *nwb = dynamic_cast(*dest); - if (nwb != NULL) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); + if (nwb != nullptr) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); break; } case WPT_SCROLLBAR: { NWidgetCore *nwc = dynamic_cast(*dest); - if (nwc != NULL) { + if (nwc != nullptr) { nwc->scrollbar_index = parts->u.widget.index; } break; @@ -2689,20 +2689,20 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, return num_used; case NWID_VIEWPORT: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetViewport(parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; case NWID_HSCROLLBAR: case NWID_VSCROLLBAR: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; *dest = new NWidgetScrollbar(parts->type, parts->u.widget.colour, parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; case NWID_SELECTION: { - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; NWidgetStacked *nws = new NWidgetStacked(); *dest = nws; *fill_dest = true; @@ -2712,7 +2712,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, } default: - if (*dest != NULL) return num_used; + if (*dest != nullptr) return num_used; assert((parts->type & WWT_MASK) < WWT_LAST || (parts->type & WWT_MASK) == NWID_BUTTON_DROPDOWN); *dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); @@ -2729,29 +2729,29 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, * Build a nested widget tree by recursively filling containers with nested widgets read from their parts. * @param parts Array with parts of the nested widgets. * @param count Length of the \a parts array. - * @param parent Pointer or container to use for storing the child widgets (*parent == NULL or *parent == container or background widget). + * @param parent Pointer or container to use for storing the child widgets (*parent == nullptr or *parent == container or background widget). * @param biggest_index Pointer to biggest nested widget index in the tree. * @return Number of widget part elements used to fill the container. * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. */ static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **parent, int *biggest_index) { - /* If *parent == NULL, only the first widget is read and returned. Otherwise, *parent must point to either + /* If *parent == nullptr, only the first widget is read and returned. Otherwise, *parent must point to either * a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */ NWidgetContainer *nwid_cont = dynamic_cast(*parent); NWidgetBackground *nwid_parent = dynamic_cast(*parent); - assert(*parent == NULL || (nwid_cont != NULL && nwid_parent == NULL) || (nwid_cont == NULL && nwid_parent != NULL)); + assert(*parent == nullptr || (nwid_cont != nullptr && nwid_parent == nullptr) || (nwid_cont == nullptr && nwid_parent != nullptr)); int total_used = 0; for (;;) { - NWidgetBase *sub_widget = NULL; + NWidgetBase *sub_widget = nullptr; bool fill_sub = false; int num_used = MakeNWidget(parts, count - total_used, &sub_widget, &fill_sub, biggest_index); parts += num_used; total_used += num_used; /* Break out of loop when end reached */ - if (sub_widget == NULL) break; + if (sub_widget == nullptr) break; /* If sub-widget is a container, recursively fill that container. */ WidgetType tp = sub_widget->type; @@ -2764,9 +2764,9 @@ static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **par } /* Add sub_widget to parent container if available, otherwise return the widget to the caller. */ - if (nwid_cont != NULL) nwid_cont->Add(sub_widget); - if (nwid_parent != NULL) nwid_parent->Add(sub_widget); - if (nwid_cont == NULL && nwid_parent == NULL) { + if (nwid_cont != nullptr) nwid_cont->Add(sub_widget); + if (nwid_parent != nullptr) nwid_parent->Add(sub_widget); + if (nwid_cont == nullptr && nwid_parent == nullptr) { *parent = sub_widget; return total_used; } @@ -2784,16 +2784,16 @@ static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **par * @param parts Array with parts of the widgets. * @param count Length of the \a parts array. * @param biggest_index Pointer to biggest nested widget index collected in the tree. - * @param container Container to add the nested widgets to. In case it is NULL a vertical container is used. + * @param container Container to add the nested widgets to. In case it is nullptr a vertical container is used. * @return Root of the nested widget tree, a vertical container containing the entire GUI. * @ingroup NestedWidgetParts - * @pre \c biggest_index != NULL + * @pre \c biggest_index != nullptr * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. */ NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container) { *biggest_index = -1; - if (container == NULL) container = new NWidgetVertical(); + if (container == nullptr) container = new NWidgetVertical(); NWidgetBase *cont_ptr = container; MakeWidgetTree(parts, count, &cont_ptr, biggest_index); return container; @@ -2806,10 +2806,10 @@ NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest * @param parts Array with parts of the widgets. * @param count Length of the \a parts array. * @param biggest_index Pointer to biggest nested widget index collected in the tree. - * @param[out] shade_select Pointer to the inserted shade selection widget (\c NULL if not unserted). + * @param[out] shade_select Pointer to the inserted shade selection widget (\c nullptr if not unserted). * @return Root of the nested widget tree, a vertical container containing the entire GUI. * @ingroup NestedWidgetParts - * @pre \c biggest_index != NULL + * @pre \c biggest_index != nullptr * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. */ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select) @@ -2817,16 +2817,16 @@ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index = -1; /* Read the first widget recursively from the array. */ - NWidgetBase *nwid = NULL; + NWidgetBase *nwid = nullptr; int num_used = MakeWidgetTree(parts, count, &nwid, biggest_index); - assert(nwid != NULL); + assert(nwid != nullptr); parts += num_used; count -= num_used; NWidgetContainer *root = new NWidgetVertical; root->Add(nwid); if (count == 0) { // There is no body at all. - *shade_select = NULL; + *shade_select = nullptr; return root; } @@ -2834,13 +2834,13 @@ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int * If it has a shading box, silently add a shade selection widget in the tree. */ NWidgetHorizontal *hor_cont = dynamic_cast(nwid); NWidgetContainer *body; - if (hor_cont != NULL && hor_cont->GetWidgetOfType(WWT_CAPTION) != NULL && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != NULL) { + if (hor_cont != nullptr && hor_cont->GetWidgetOfType(WWT_CAPTION) != nullptr && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != nullptr) { *shade_select = new NWidgetStacked; root->Add(*shade_select); body = new NWidgetVertical; (*shade_select)->Add(body); } else { - *shade_select = NULL; + *shade_select = nullptr; body = root; } @@ -2865,8 +2865,8 @@ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip) { assert(max_length >= 1); - NWidgetVertical *vert = NULL; // Storage for all rows. - NWidgetHorizontal *hor = NULL; // Storage for buttons in one row. + NWidgetVertical *vert = nullptr; // Storage for all rows. + NWidgetHorizontal *hor = nullptr; // Storage for buttons in one row. int hor_length = 0; Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); @@ -2876,12 +2876,12 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid for (int widnum = widget_first; widnum <= widget_last; widnum++) { /* Ensure there is room in 'hor' for another button. */ if (hor_length == max_length) { - if (vert == NULL) vert = new NWidgetVertical(); + if (vert == nullptr) vert = new NWidgetVertical(); vert->Add(hor); - hor = NULL; + hor = nullptr; hor_length = 0; } - if (hor == NULL) { + if (hor == nullptr) { hor = new NWidgetHorizontal(); hor_length = 0; } @@ -2895,7 +2895,7 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid hor_length++; } *biggest_index = widget_last; - if (vert == NULL) return hor; // All buttons fit in a single row. + if (vert == nullptr) return hor; // All buttons fit in a single row. if (hor_length > 0 && hor_length < max_length) { /* Last row is partial, add a spacer at the end to force all buttons to the left. */ @@ -2904,6 +2904,6 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid spc->SetResize(1, 0); hor->Add(spc); } - if (hor != NULL) vert->Add(hor); + if (hor != nullptr) vert->Add(hor); return vert; } diff --git a/src/widget_type.h b/src/widget_type.h index 33fb8bce08..261e3cdf34 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -174,8 +174,8 @@ public: uint current_x; ///< Current horizontal size (after resizing). uint current_y; ///< Current vertical size (after resizing). - uint pos_x; ///< Horizontal position of top-left corner of the widget in the window. - uint pos_y; ///< Vertical position of top-left corner of the widget in the window. + int pos_x; ///< Horizontal position of top-left corner of the widget in the window. + int pos_y; ///< Vertical position of top-left corner of the widget in the window. NWidgetBase *next; ///< Pointer to next widget in container. Managed by parent container widget. NWidgetBase *prev; ///< Pointer to previous widget in container. Managed by parent container widget. @@ -247,7 +247,7 @@ public: uint min_y; ///< Minimal vertical size of only this widget. }; -/** Nested widget flags that affect display and interaction withe 'real' widgets. */ +/** Nested widget flags that affect display and interaction with 'real' widgets. */ enum NWidgetDisplay { /* Generic. */ NDB_LOWERED = 0, ///< Widget is lowered (pressed down) bit. @@ -293,11 +293,11 @@ public: inline void SetDisabled(bool disabled); inline bool IsDisabled() const; - /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); - /* virtual */ bool IsHighlighted() const; - /* virtual */ TextColour GetHighlightColour() const; - /* virtual */ void SetHighlighted(TextColour highlight_colour); + void FillNestedArray(NWidgetBase **array, uint length) override; + NWidgetCore *GetWidgetFromPos(int x, int y) override; + bool IsHighlighted() const override; + TextColour GetHighlightColour() const override; + void SetHighlighted(TextColour highlight_colour) override; NWidgetDisplay disp_flags; ///< Flags that affect display and interaction with the widget. Colours colour; ///< Colour of this widget. @@ -371,12 +371,12 @@ public: ~NWidgetContainer(); void Add(NWidgetBase *wid); - /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); + void FillNestedArray(NWidgetBase **array, uint length) override; /** Return whether the container is empty. */ - inline bool IsEmpty() { return head == NULL; } + inline bool IsEmpty() { return head == nullptr; } - /* virtual */ NWidgetBase *GetWidgetOfType(WidgetType tp); + NWidgetBase *GetWidgetOfType(WidgetType tp) override; protected: NWidgetBase *head; ///< Pointer to first widget in container. @@ -408,12 +408,12 @@ public: void SetIndex(int index); - void SetupSmallestSize(Window *w, bool init_array); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); - /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); + void SetupSmallestSize(Window *w, bool init_array) override; + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void FillNestedArray(NWidgetBase **array, uint length) override; - /* virtual */ void Draw(const Window *w); - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); + void Draw(const Window *w) override; + NWidgetCore *GetWidgetFromPos(int x, int y) override; void SetDisplayedPlane(int plane); @@ -437,8 +437,8 @@ public: void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); - /* virtual */ void Draw(const Window *w); - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); + void Draw(const Window *w) override; + NWidgetCore *GetWidgetFromPos(int x, int y) override; protected: NWidContainerFlags flags; ///< Flags of the container. @@ -500,12 +500,12 @@ public: void SetCount(int count); void SetScrollbar(Scrollbar *sb); - void SetupSmallestSize(Window *w, bool init_array); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); - /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); + void SetupSmallestSize(Window *w, bool init_array) override; + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; + void FillNestedArray(NWidgetBase **array, uint length) override; - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); - /* virtual */ void Draw(const Window *w); + NWidgetCore *GetWidgetFromPos(int x, int y) override; + void Draw(const Window *w) override; protected: int index; ///< If non-negative, index in the #Window::nested_array. Colours colour; ///< Colour of this widget. @@ -530,12 +530,12 @@ class NWidgetSpacer : public NWidgetResizeBase { public: NWidgetSpacer(int length, int height); - void SetupSmallestSize(Window *w, bool init_array); - /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); + void SetupSmallestSize(Window *w, bool init_array) override; + void FillNestedArray(NWidgetBase **array, uint length) override; - /* virtual */ void Draw(const Window *w); - /* virtual */ void SetDirty(const Window *w) const; - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); + void Draw(const Window *w) override; + void SetDirty(const Window *w) const override; + NWidgetCore *GetWidgetFromPos(int x, int y) override; }; /** @@ -544,20 +544,20 @@ public: */ class NWidgetBackground : public NWidgetCore { public: - NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child = NULL); + NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child = nullptr); ~NWidgetBackground(); void Add(NWidgetBase *nwid); void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); - void SetupSmallestSize(Window *w, bool init_array); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); + void SetupSmallestSize(Window *w, bool init_array) override; + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; - /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); + void FillNestedArray(NWidgetBase **array, uint length) override; - /* virtual */ void Draw(const Window *w); - /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); - /* virtual */ NWidgetBase *GetWidgetOfType(WidgetType tp); + void Draw(const Window *w) override; + NWidgetCore *GetWidgetFromPos(int x, int y) override; + NWidgetBase *GetWidgetOfType(WidgetType tp) override; private: NWidgetPIPContainer *child; ///< Child widget. @@ -576,8 +576,8 @@ class NWidgetViewport : public NWidgetCore { public: NWidgetViewport(int index); - /* virtual */ void SetupSmallestSize(Window *w, bool init_array); - /* virtual */ void Draw(const Window *w); + void SetupSmallestSize(Window *w, bool init_array) override; + void Draw(const Window *w) override; void InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom); void UpdateViewportCoordinates(Window *w); @@ -751,8 +751,8 @@ class NWidgetScrollbar : public NWidgetCore, public Scrollbar { public: NWidgetScrollbar(WidgetType tp, Colours colour, int index); - /* virtual */ void SetupSmallestSize(Window *w, bool init_array); - /* virtual */ void Draw(const Window *w); + void SetupSmallestSize(Window *w, bool init_array) override; + void Draw(const Window *w) override; static void InvalidateDimensionCache(); static Dimension GetVerticalDimension(); @@ -771,8 +771,8 @@ class NWidgetLeaf : public NWidgetCore { public: NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, StringID tip); - /* virtual */ void SetupSmallestSize(Window *w, bool init_array); - /* virtual */ void Draw(const Window *w); + void SetupSmallestSize(Window *w, bool init_array) override; + void Draw(const Window *w) override; bool ButtonHit(const Point &pt); diff --git a/src/widgets/autoreplace_widget.h b/src/widgets/autoreplace_widget.h index 4b761ca45d..8432b1a7f2 100644 --- a/src/widgets/autoreplace_widget.h +++ b/src/widgets/autoreplace_widget.h @@ -34,9 +34,11 @@ enum ReplaceVehicleWidgets { WID_RV_INFO_TAB, ///< Info tab. WID_RV_STOP_REPLACE, ///< Stop Replacing button. + /* Train/road only widgets */ + WID_RV_RAIL_ROAD_TYPE_DROPDOWN, ///< Dropdown menu about the rail/roadtype. + /* Train only widgets. */ WID_RV_TRAIN_ENGINEWAGON_DROPDOWN, ///< Dropdown to select engines and/or wagons. - WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. }; diff --git a/src/widgets/company_widget.h b/src/widgets/company_widget.h index becd87f400..7984f93738 100644 --- a/src/widgets/company_widget.h +++ b/src/widgets/company_widget.h @@ -183,6 +183,8 @@ enum CompanyInfrastructureWidgets { WID_CI_RAIL_COUNT, ///< Count of rail. WID_CI_ROAD_DESC, ///< Description of road. WID_CI_ROAD_COUNT, ///< Count of road. + WID_CI_TRAM_DESC, ///< Description of tram. + WID_CI_TRAM_COUNT, ///< Count of tram. WID_CI_WATER_DESC, ///< Description of water. WID_CI_WATER_COUNT, ///< Count of water. WID_CI_STATION_DESC, ///< Description of station. diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 33aed644bd..665f203a03 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -22,7 +22,7 @@ #include "../safeguards.h" -void DropDownListItem::Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const +void DropDownListItem::Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const { int c1 = _colour_gradient[bg_colour][3]; int c2 = _colour_gradient[bg_colour][7]; @@ -39,7 +39,7 @@ uint DropDownListStringItem::Width() const return GetStringBoundingBox(buffer).width; } -void DropDownListStringItem::Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const +void DropDownListStringItem::Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, this->String(), sel ? TC_WHITE : TC_BLACK); } @@ -56,12 +56,12 @@ const char * DropDownListCharStringItem::String() const * @return true if \a first precedes \a second. * @warning All items in the list need to be derivates of DropDownListStringItem. */ -/* static */ int DropDownListStringItem::NatSortFunc(const DropDownListItem * const *first, const DropDownListItem * const * second) +/* static */ bool DropDownListStringItem::NatSortFunc(std::unique_ptr const &first, std::unique_ptr const &second) { char buffer1[512], buffer2[512]; - GetString(buffer1, static_cast(*first)->String(), lastof(buffer1)); - GetString(buffer2, static_cast(*second)->String(), lastof(buffer2)); - return strnatcmp(buffer1, buffer2); + GetString(buffer1, static_cast(first.get())->String(), lastof(buffer1)); + GetString(buffer2, static_cast(second.get())->String(), lastof(buffer2)); + return strnatcmp(buffer1, buffer2) < 0; } StringID DropDownListParamStringItem::String() const @@ -76,6 +76,40 @@ StringID DropDownListCharStringItem::String() const return this->string; } +DropDownListIconItem::DropDownListIconItem(SpriteID sprite, PaletteID pal, StringID string, int result, bool masked) : DropDownListParamStringItem(string, result, masked), sprite(sprite), pal(pal) +{ + this->dim = GetSpriteSize(sprite); + if (this->dim.height < (uint)FONT_HEIGHT_NORMAL) { + this->sprite_y = (FONT_HEIGHT_NORMAL - dim.height) / 2; + this->text_y = 0; + } else { + this->sprite_y = 0; + this->text_y = (dim.height - FONT_HEIGHT_NORMAL) / 2; + } +} + +uint DropDownListIconItem::Height(uint width) const +{ + return max(this->dim.height, (uint)FONT_HEIGHT_NORMAL); +} + +uint DropDownListIconItem::Width() const +{ + return DropDownListStringItem::Width() + this->dim.width + WD_FRAMERECT_LEFT; +} + +void DropDownListIconItem::Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const +{ + bool rtl = _current_text_dir == TD_RTL; + DrawSprite(this->sprite, this->pal, rtl ? right - this->dim.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + this->sprite_y); + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : (this->dim.width + WD_FRAMERECT_LEFT)), right - WD_FRAMERECT_RIGHT - (rtl ? (this->dim.width + WD_FRAMERECT_RIGHT) : 0), top + this->text_y, this->String(), sel ? TC_WHITE : TC_BLACK); +} + +void DropDownListIconItem::SetDimension(Dimension d) +{ + this->dim = d; +} + static const NWidgetPart _nested_dropdown_menu_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_END, WID_DM_ITEMS), SetMinimalSize(1, 1), SetScrollbar(WID_DM_SCROLL), EndContainer(), @@ -86,7 +120,7 @@ static const NWidgetPart _nested_dropdown_menu_widgets[] = { }; static WindowDesc _dropdown_desc( - WDP_MANUAL, NULL, 0, 0, + WDP_MANUAL, nullptr, 0, 0, WC_DROPDOWN_MENU, WC_NONE, WDF_NO_FOCUS, _nested_dropdown_menu_widgets, lengthof(_nested_dropdown_menu_widgets) @@ -97,7 +131,7 @@ struct DropdownWindow : Window { WindowClass parent_wnd_class; ///< Parent window class. WindowNumber parent_wnd_num; ///< Parent window number. int parent_button; ///< Parent widget number where the window is dropped from. - const DropDownList *list; ///< List with dropdown menu items. + const DropDownList list; ///< List with dropdown menu items. int selected_index; ///< Index of the selected item in the list. byte click_delay; ///< Timer to delay selection. bool drag_mode; @@ -119,10 +153,10 @@ struct DropdownWindow : Window { * @param wi_colour Colour of the parent widget. * @param scroll Dropdown menu has a scrollbar. */ - DropdownWindow(Window *parent, const DropDownList *list, int selected, int button, bool instant_close, const Point &position, const Dimension &size, Colours wi_colour, bool scroll) - : Window(&_dropdown_desc) + DropdownWindow(Window *parent, DropDownList &&list, int selected, int button, bool instant_close, const Point &position, const Dimension &size, Colours wi_colour, bool scroll) + : Window(&_dropdown_desc), list(std::move(list)) { - assert(list->Length() > 0); + assert(this->list.size() > 0); this->position = position; @@ -145,19 +179,17 @@ struct DropdownWindow : Window { /* Total length of list */ int list_height = 0; - for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { - const DropDownListItem *item = *it; + for (const auto &item : this->list) { list_height += item->Height(items_width); } /* Capacity is the average number of items visible */ - this->vscroll->SetCapacity(size.height * (uint16)list->Length() / list_height); - this->vscroll->SetCount((uint16)list->Length()); + this->vscroll->SetCapacity(size.height * (uint16)this->list.size() / list_height); + this->vscroll->SetCount((uint16)this->list.size()); this->parent_wnd_class = parent->window_class; this->parent_wnd_num = parent->window_number; this->parent_button = button; - this->list = list; this->selected_index = selected; this->click_delay = 0; this->drag_mode = true; @@ -173,13 +205,12 @@ struct DropdownWindow : Window { this->SetDirty(); Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num); - if (w2 != NULL) { + if (w2 != nullptr) { Point pt = _cursor.pos; pt.x -= w2->left; pt.y -= w2->top; w2->OnDropdownClose(pt, this->parent_button, this->selected_index, this->instant_close); } - delete this->list; } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) @@ -201,13 +232,10 @@ struct DropdownWindow : Window { int width = nwi->current_x - 4; int pos = this->vscroll->GetPosition(); - const DropDownList *list = this->list; - - for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { + for (const auto &item : this->list) { /* Skip items that are scrolled up */ if (--pos >= 0) continue; - const DropDownListItem *item = *it; int item_height = item->Height(width); if (y < item_height) { @@ -230,8 +258,7 @@ struct DropdownWindow : Window { int y = r.top + 2; int pos = this->vscroll->GetPosition(); - for (const DropDownListItem * const *it = this->list->Begin(); it != this->list->End(); ++it) { - const DropDownListItem *item = *it; + for (const auto &item : this->list) { int item_height = item->Height(r.right - r.left + 1); /* Skip items that are scrolled up */ @@ -282,7 +309,7 @@ struct DropdownWindow : Window { virtual void OnMouseLoop() { Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num); - if (w2 == NULL) { + if (w2 == nullptr) { delete this; return; } @@ -333,8 +360,7 @@ struct DropdownWindow : Window { /** * Show a drop down list. * @param w Parent window for the list. - * @param list Prepopulated DropDownList. Will be deleted when the list is - * closed. + * @param list Prepopulated DropDownList. * @param selected The initially selected list item. * @param button The widget which is passed to Window::OnDropdownSelect and OnDropdownClose. * Unless you override those functions, this should be then widget index of the dropdown button. @@ -344,7 +370,7 @@ struct DropdownWindow : Window { * @param instant_close Set to true if releasing mouse button should close the * list regardless of where the cursor is. */ -void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width, bool instant_close) +void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width, bool instant_close) { DeleteWindowById(WC_DROPDOWN_MENU, 0); @@ -360,8 +386,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* Total height of list */ uint height = 0; - for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { - const DropDownListItem *item = *it; + for (const auto &item : list) { height += item->Height(width); if (auto_width) max_item_width = max(max_item_width, item->Width() + 5); } @@ -389,7 +414,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /* If the dropdown doesn't fully fit, we need a dropdown. */ if (height > available_height) { scroll = true; - uint avg_height = height / list->Length(); + uint avg_height = height / (uint)list.size(); /* Check at least there is space for one item. */ assert(available_height >= avg_height); @@ -412,7 +437,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b Point dw_pos = { w->left + (_current_text_dir == TD_RTL ? wi_rect.right + 1 - (int)width : wi_rect.left), top}; Dimension dw_size = {width, height}; - DropdownWindow *dropdown = new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll); + DropdownWindow *dropdown = new DropdownWindow(w, std::move(list), selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll); /* The dropdown starts scrolling downwards when opening it towards * the top and holding down the mouse button. It can be fooled by @@ -423,8 +448,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b /** * Show a drop down list. * @param w Parent window for the list. - * @param list Prepopulated DropDownList. Will be deleted when the list is - * closed. + * @param list Prepopulated DropDownList. * @param selected The initially selected list item. * @param button The widget within the parent window that is used to determine * the list's location. @@ -433,7 +457,7 @@ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int b * @param instant_close Set to true if releasing mouse button should close the * list regardless of where the cursor is. */ -void ShowDropDownList(Window *w, const DropDownList *list, int selected, int button, uint width, bool auto_width, bool instant_close) +void ShowDropDownList(Window *w, DropDownList &&list, int selected, int button, uint width, bool auto_width, bool instant_close) { /* Our parent's button widget is used to determine where to place the drop * down list window. */ @@ -460,7 +484,7 @@ void ShowDropDownList(Window *w, const DropDownList *list, int selected, int but } } - ShowDropDownListAt(w, list, selected, button, wi_rect, wi_colour, auto_width, instant_close); + ShowDropDownListAt(w, std::move(list), selected, button, wi_rect, wi_colour, auto_width, instant_close); } /** @@ -476,21 +500,15 @@ void ShowDropDownList(Window *w, const DropDownList *list, int selected, int but */ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask, uint width) { - DropDownList *list = new DropDownList(); + DropDownList list; for (uint i = 0; strings[i] != INVALID_STRING_ID; i++) { if (!HasBit(hidden_mask, i)) { - *list->Append() = new DropDownListStringItem(strings[i], i, HasBit(disabled_mask, i)); + list.emplace_back(new DropDownListStringItem(strings[i], i, HasBit(disabled_mask, i))); } } - /* No entries in the list? */ - if (list->Length() == 0) { - delete list; - return; - } - - ShowDropDownList(w, list, selected, button, width); + if (!list.empty()) ShowDropDownList(w, std::move(list), selected, button, width); } /** @@ -505,7 +523,7 @@ int HideDropDownMenu(Window *pw) if (w->window_class != WC_DROPDOWN_MENU) continue; DropdownWindow *dw = dynamic_cast(w); - assert(dw != NULL); + assert(dw != nullptr); if (pw->window_class == dw->parent_wnd_class && pw->window_number == dw->parent_wnd_num) { int parent_button = dw->parent_button; diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h index 5678468ae0..fdf0f56986 100644 --- a/src/widgets/dropdown_type.h +++ b/src/widgets/dropdown_type.h @@ -37,7 +37,7 @@ public: virtual bool Selectable() const { return false; } virtual uint Height(uint width) const { return FONT_HEIGHT_NORMAL; } virtual uint Width() const { return 0; } - virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const; + virtual void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const; }; /** @@ -50,13 +50,12 @@ public: DropDownListStringItem(StringID string, int result, bool masked) : DropDownListItem(result, masked), string(string) {} virtual ~DropDownListStringItem() {} - virtual bool Selectable() const { return true; } - virtual uint Width() const; - //virtual const char * String() const; - virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const; + bool Selectable() const override { return true; } + uint Width() const override; + void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override; virtual StringID String() const { return this->string; } - static int CDECL NatSortFunc(const DropDownListItem * const *first, const DropDownListItem * const *second); + static bool NatSortFunc(std::unique_ptr const &first, std::unique_ptr const &second); }; /** @@ -102,8 +101,8 @@ public: DropDownListParamStringItem(StringID string, int result, bool masked) : DropDownListStringItem(string, result, masked) {} virtual ~DropDownListParamStringItem() {} - virtual StringID String() const; - virtual void SetParam(uint index, uint64 value) { decode_params[index] = value; } + StringID String() const override; + void SetParam(uint index, uint64 value) { decode_params[index] = value; } }; /** @@ -116,16 +115,34 @@ public: DropDownListCharStringItem(const char *raw_string, int result, bool masked) : DropDownListStringItem(STR_JUST_RAW_STRING, result, masked), raw_string(raw_string) {} virtual ~DropDownListCharStringItem() {} - virtual StringID String() const; + StringID String() const override; +}; + +/** + * List item with icon and string. + */ +class DropDownListIconItem : public DropDownListParamStringItem { + SpriteID sprite; + PaletteID pal; + Dimension dim; + uint sprite_y; + uint text_y; +public: + DropDownListIconItem(SpriteID sprite, PaletteID pal, StringID string, int result, bool masked); + + uint Height(uint width) const override; + uint Width() const override; + void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override; + void SetDimension(Dimension d); }; /** * A drop down list is a collection of drop down list items. */ -typedef AutoDeleteSmallVector DropDownList; +typedef std::vector> DropDownList; -void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width = false, bool instant_close = false); +void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width = false, bool instant_close = false); -void ShowDropDownList(Window *w, const DropDownList *list, int selected, int button, uint width = 0, bool auto_width = false, bool instant_close = false); +void ShowDropDownList(Window *w, DropDownList &&list, int selected, int button, uint width = 0, bool auto_width = false, bool instant_close = false); #endif /* WIDGETS_DROPDOWN_TYPE_H */ diff --git a/src/widgets/framerate_widget.h b/src/widgets/framerate_widget.h index 2c82c85e5e..b03d3aef73 100644 --- a/src/widgets/framerate_widget.h +++ b/src/widgets/framerate_widget.h @@ -22,6 +22,8 @@ enum FramerateWindowWidgets { WID_FRW_TIMES_NAMES, WID_FRW_TIMES_CURRENT, WID_FRW_TIMES_AVERAGE, + WID_FRW_ALLOCSIZE, + WID_FRW_SEL_MEMORY, WID_FRW_SCROLLBAR, }; diff --git a/src/widgets/misc_widget.h b/src/widgets/misc_widget.h index a6dd081a9d..806f889bbf 100644 --- a/src/widgets/misc_widget.h +++ b/src/widgets/misc_widget.h @@ -32,6 +32,7 @@ enum AboutWidgets { enum QueryStringWidgets { WID_QS_CAPTION, ///< Caption of the window. WID_QS_TEXT, ///< Text of the query. + WID_QS_WARNING, ///< Warning label about password security WID_QS_DEFAULT, ///< Default button. WID_QS_CANCEL, ///< Cancel button. WID_QS_OK, ///< OK button. diff --git a/src/widgets/network_widget.h b/src/widgets/network_widget.h index ef4a7fc4ce..def4eb4d98 100644 --- a/src/widgets/network_widget.h +++ b/src/widgets/network_widget.h @@ -127,6 +127,7 @@ enum NetworkCompanyPasswordWidgets { WID_NCP_LABEL, ///< Label in front of the password field. WID_NCP_PASSWORD, ///< Input field for the password. WID_NCP_SAVE_AS_DEFAULT_PASSWORD, ///< Toggle 'button' for saving the current password as default password. + WID_NCP_WARNING, ///< Warning text about password security WID_NCP_CANCEL, ///< Close the window without changing anything. WID_NCP_OK, ///< Safe the password etc. }; diff --git a/src/widgets/road_widget.h b/src/widgets/road_widget.h index 9a8359d7be..88102f0e43 100644 --- a/src/widgets/road_widget.h +++ b/src/widgets/road_widget.h @@ -15,10 +15,10 @@ /** Widgets of the #BuildRoadToolbarWindow class. */ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ + WID_ROT_CAPTION, ///< Caption of the window WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y, ///< Build road in y-direction. WID_ROT_AUTOROAD, ///< Autoroad. - WID_ROT_FULLROAD, ///< Auto full road (no half-tiles). WID_ROT_DEMOLISH, ///< Demolish. WID_ROT_DEPOT, ///< Build depot. WID_ROT_BUS_STATION, ///< Build bus station. @@ -27,6 +27,7 @@ enum RoadToolbarWidgets { WID_ROT_BUILD_BRIDGE, ///< Build bridge. WID_ROT_BUILD_TUNNEL, ///< Build tunnel. WID_ROT_REMOVE, ///< Remove road. + WID_ROT_CONVERT_ROAD, ///< Convert road. }; /** Widgets of the #BuildRoadDepotWindow class. */ diff --git a/src/widgets/station_widget.h b/src/widgets/station_widget.h index 82fe392e33..f9b5b266ab 100644 --- a/src/widgets/station_widget.h +++ b/src/widgets/station_widget.h @@ -30,6 +30,7 @@ enum StationViewWidgets { WID_SV_ROADVEHS, ///< List of scheduled road vehs button. WID_SV_SHIPS, ///< List of scheduled ships button. WID_SV_PLANES, ///< List of scheduled planes button. + WID_SV_CATCHMENT, ///< Toggle catchment area highlight. }; /** Widgets of the #CompanyStationsWindow class. */ diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index e5a5b80faf..6810ff332d 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -41,6 +41,7 @@ enum ToolbarNormalWidgets { WID_TN_BUILDING_TOOLS_START, ///< Helper for the offset of the building tools WID_TN_RAILS = WID_TN_BUILDING_TOOLS_START, ///< Rail building menu. WID_TN_ROADS, ///< Road building menu. + WID_TN_TRAMS, ///< Tram building menu. WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR, ///< Airport building toolbar. WID_TN_LANDSCAPE, ///< Landscaping toolbar. @@ -68,14 +69,14 @@ enum ToolbarEditorWidgets { WID_TE_TOWN_GENERATE, ///< Town building window. WID_TE_INDUSTRY, ///< Industry building window. WID_TE_ROADS, ///< Road building menu. + WID_TE_TRAMS, ///< Tram building menu. WID_TE_WATER, ///< Water building toolbar. WID_TE_TREES, ///< Tree building toolbar. WID_TE_SIGNS, ///< Sign building. WID_TE_DATE_PANEL, ///< Container for the date widgets. - /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ - WID_TE_MUSIC_SOUND = WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu. - WID_TE_HELP = WID_TN_HELP, ///< Help menu. - WID_TE_SWITCH_BAR = WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. + WID_TE_MUSIC_SOUND, ///< Music/sound configuration menu. + WID_TE_HELP, ///< Help menu. + WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; #endif /* WIDGETS_TOOLBAR_WIDGET_H */ diff --git a/src/widgets/town_widget.h b/src/widgets/town_widget.h index 22d4dc4984..4d5966eff6 100644 --- a/src/widgets/town_widget.h +++ b/src/widgets/town_widget.h @@ -16,6 +16,7 @@ enum TownDirectoryWidgets { WID_TD_SORT_ORDER, ///< Direction of sort dropdown. WID_TD_SORT_CRITERIA, ///< Criteria of sort dropdown. + WID_TD_FILTER, ///< Filter of name. WID_TD_LIST, ///< List of towns. WID_TD_SCROLLBAR, ///< Scrollbar for the town list. WID_TD_WORLD_POPULATION, ///< The world's population. @@ -25,6 +26,7 @@ enum TownDirectoryWidgets { /** Widgets of the #TownAuthorityWindow class. */ enum TownAuthorityWidgets { WID_TA_CAPTION, ///< Caption of window. + WID_TA_ZONE_BUTTON, ///< Turn on/off showing local authority zone. WID_TA_RATING_INFO, ///< Overview with ratings for each company. WID_TA_COMMAND_LIST, ///< List of commands for the player. WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands. @@ -40,6 +42,7 @@ enum TownViewWidgets { WID_TV_CENTER_VIEW, ///< Center the main view on this town. WID_TV_SHOW_AUTHORITY, ///< Show the town authority window. WID_TV_CHANGE_NAME, ///< Change the name of this town. + WID_TV_CATCHMENT, ///< Toggle catchment area highlight. WID_TV_EXPAND, ///< Expand this town (scenario editor only). WID_TV_DELETE, ///< Delete this town (scenario editor only). WID_TV_CB, diff --git a/src/window.cpp b/src/window.cpp index 5054b7fd95..e68e652983 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -54,13 +54,13 @@ enum ViewportAutoscrolling { }; static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window -static Window *_mouseover_last_w = NULL; ///< Window of the last OnMouseOver event. -static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. +static Window *_mouseover_last_w = nullptr; ///< Window of the last OnMouseOver event. +static Window *_last_scroll_window = nullptr; ///< Window of the last scroll event. /** List of windows opened at the screen sorted from the front. */ -Window *_z_front_window = NULL; +Window *_z_front_window = nullptr; /** List of windows opened at the screen sorted from the back. */ -Window *_z_back_window = NULL; +Window *_z_back_window = nullptr; /** If false, highlight is white, otherwise the by the widget defined colour. */ bool _window_highlight_colour = false; @@ -87,7 +87,7 @@ SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. * List of all WindowDescs. * This is a pointer to ensure initialisation order with the various static WindowDesc instances. */ -static SmallVector *_window_descs = NULL; +static std::vector *_window_descs = nullptr; /** Config file to store WindowDesc */ char *_windows_file; @@ -110,18 +110,18 @@ WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_wi default_width_trad(def_width_trad), default_height_trad(def_height_trad) { - if (_window_descs == NULL) _window_descs = new SmallVector(); - *_window_descs->Append() = this; + if (_window_descs == nullptr) _window_descs = new std::vector(); + _window_descs->push_back(this); } WindowDesc::~WindowDesc() { - _window_descs->Erase(_window_descs->Find(this)); + _window_descs->erase(std::find(_window_descs->begin(), _window_descs->end(), this)); } /** * Determine default width of window. - * This is either a stored user preferred size, or the build-in default. + * This is either a stored user preferred size, or the built-in default. * @return Width in pixels. */ int16 WindowDesc::GetDefaultWidth() const @@ -131,7 +131,7 @@ int16 WindowDesc::GetDefaultWidth() const /** * Determine default height of window. - * This is either a stored user preferred size, or the build-in default. + * This is either a stored user preferred size, or the built-in default. * @return Height in pixels. */ int16 WindowDesc::GetDefaultHeight() const @@ -146,9 +146,9 @@ void WindowDesc::LoadFromConfig() { IniFile *ini = new IniFile(); ini->LoadFromDisk(_windows_file, NO_DIRECTORY); - for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { - if ((*it)->ini_key == NULL) continue; - IniLoadWindowSettings(ini, (*it)->ini_key, *it); + for (WindowDesc *wd : *_window_descs) { + if (wd->ini_key == nullptr) continue; + IniLoadWindowSettings(ini, wd->ini_key, wd); } delete ini; } @@ -156,10 +156,10 @@ void WindowDesc::LoadFromConfig() /** * Sort WindowDesc by ini_key. */ -static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) +static bool DescSorter(WindowDesc* const &a, WindowDesc* const &b) { - if ((*a)->ini_key != NULL && (*b)->ini_key != NULL) return strcmp((*a)->ini_key, (*b)->ini_key); - return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0); + if (a->ini_key != nullptr && b->ini_key != nullptr) return strcmp(a->ini_key, b->ini_key) < 0; + return a->ini_key != nullptr; } /** @@ -168,13 +168,13 @@ static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) void WindowDesc::SaveToConfig() { /* Sort the stuff to get a nice ini file on first write */ - QSortT(_window_descs->Begin(), _window_descs->Length(), DescSorter); + std::sort(_window_descs->begin(), _window_descs->end(), DescSorter); IniFile *ini = new IniFile(); ini->LoadFromDisk(_windows_file, NO_DIRECTORY); - for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { - if ((*it)->ini_key == NULL) continue; - IniSaveWindowSettings(ini, (*it)->ini_key, *it); + for (WindowDesc *wd : *_window_descs) { + if (wd->ini_key == nullptr) continue; + IniSaveWindowSettings(ini, wd->ini_key, wd); } ini->SaveToDisk(_windows_file); delete ini; @@ -185,7 +185,7 @@ void WindowDesc::SaveToConfig() */ void Window::ApplyDefaults() { - if (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != NULL) { + if (this->nested_root != nullptr && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != nullptr) { if (this->window_desc->pref_sticky) this->flags |= WF_STICKY; } else { /* There is no stickybox; clear the preference in case someone tried to be funny */ @@ -217,7 +217,7 @@ void Window::DisableAllWidgetHighlight() { for (uint i = 0; i < this->nested_array_size; i++) { NWidgetBase *nwid = this->GetWidget(i); - if (nwid == NULL) continue; + if (nwid == nullptr) continue; if (nwid->IsHighlighted()) { nwid->SetHighlighted(TC_INVALID); @@ -238,7 +238,7 @@ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour assert(widget_index < this->nested_array_size); NWidgetBase *nwid = this->GetWidget(widget_index); - if (nwid == NULL) return; + if (nwid == nullptr) return; nwid->SetHighlighted(highlighted_colour); this->SetWidgetDirty(widget_index); @@ -251,7 +251,7 @@ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour bool valid = false; for (uint i = 0; i < this->nested_array_size; i++) { NWidgetBase *nwid = this->GetWidget(i); - if (nwid == NULL) continue; + if (nwid == nullptr) continue; if (!nwid->IsHighlighted()) continue; valid = true; @@ -271,7 +271,7 @@ bool Window::IsWidgetHighlighted(byte widget_index) const assert(widget_index < this->nested_array_size); const NWidgetBase *nwid = this->GetWidget(widget_index); - if (nwid == NULL) return false; + if (nwid == nullptr) return false; return nwid->IsHighlighted(); } @@ -328,63 +328,63 @@ Scrollbar *Window::GetScrollbar(uint widnum) /** * Return the querystring associated to a editbox. * @param widnum Editbox widget index - * @return QueryString or NULL. + * @return QueryString or nullptr. */ const QueryString *Window::GetQueryString(uint widnum) const { - const SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : NULL; + auto query = this->querystrings.Find(widnum); + return query != this->querystrings.end() ? query->second : nullptr; } /** * Return the querystring associated to a editbox. * @param widnum Editbox widget index - * @return QueryString or NULL. + * @return QueryString or nullptr. */ QueryString *Window::GetQueryString(uint widnum) { SmallMap::Pair *query = this->querystrings.Find(widnum); - return query != this->querystrings.End() ? query->second : NULL; + return query != this->querystrings.End() ? query->second : nullptr; } /** * Get the current input text if an edit box has the focus. - * @return The currently focused input text or NULL if no input focused. + * @return The currently focused input text or nullptr if no input focused. */ /* virtual */ const char *Window::GetFocusedText() const { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetText(); } - return NULL; + return nullptr; } /** * Get the string at the caret if an edit box has the focus. - * @return The text at the caret or NULL if no edit box is focused. + * @return The text at the caret or nullptr if no edit box is focused. */ /* virtual */ const char *Window::GetCaret() const { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCaret(); } - return NULL; + return nullptr; } /** * Get the range of the currently marked input text. * @param[out] length Length of the marked text. - * @return Pointer to the start of the marked text or NULL if no text is marked. + * @return Pointer to the start of the marked text or nullptr if no text is marked. */ /* virtual */ const char *Window::GetMarkedText(size_t *length) const { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length); } - return NULL; + return nullptr; } /** @@ -393,7 +393,7 @@ QueryString *Window::GetQueryString(uint widnum) */ /* virtual */ Point Window::GetCaretPosition() const { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); } @@ -409,7 +409,7 @@ QueryString *Window::GetQueryString(uint widnum) */ /* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); } @@ -420,15 +420,15 @@ QueryString *Window::GetQueryString(uint widnum) /** * Get the character that is rendered at a position by the focused edit box. * @param pt The position to test. - * @return Pointer to the character at the position or NULL if no character is at the position. + * @return Pointer to the character at the position or nullptr if no character is at the position. */ /* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); } - return NULL; + return nullptr; } /** @@ -440,8 +440,8 @@ void SetFocusedWindow(Window *w) if (_focused_window == w) return; /* Invalidate focused widget */ - if (_focused_window != NULL) { - if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window); + if (_focused_window != nullptr) { + if (_focused_window->nested_focus != nullptr) _focused_window->nested_focus->SetDirty(_focused_window); } /* Remember which window was previously focused */ @@ -449,8 +449,8 @@ void SetFocusedWindow(Window *w) _focused_window = w; /* So we can inform it that it lost focus */ - if (old_focused != NULL) old_focused->OnFocusLost(); - if (_focused_window != NULL) _focused_window->OnFocus(); + if (old_focused != nullptr) old_focused->OnFocusLost(); + if (_focused_window != nullptr) _focused_window->OnFocus(); } /** @@ -460,12 +460,12 @@ void SetFocusedWindow(Window *w) */ bool EditBoxInGlobalFocus() { - if (_focused_window == NULL) return false; + if (_focused_window == nullptr) return false; /* The console does not have an edit box so a special case is needed. */ if (_focused_window->window_class == WC_CONSOLE) return true; - return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX; + return _focused_window->nested_focus != nullptr && _focused_window->nested_focus->type == WWT_EDITBOX; } /** @@ -473,12 +473,12 @@ bool EditBoxInGlobalFocus() */ void Window::UnfocusFocusedWidget() { - if (this->nested_focus != NULL) { + if (this->nested_focus != nullptr) { if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ this->nested_focus->SetDirty(this); - this->nested_focus = NULL; + this->nested_focus = nullptr; } } @@ -492,8 +492,8 @@ bool Window::SetFocusedWidget(int widget_index) /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ if ((uint)widget_index >= this->nested_array_size) return false; - assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea. - if (this->nested_focus != NULL) { + assert(this->nested_array[widget_index] != nullptr); // Setting focus to a non-existing widget is a bad idea. + if (this->nested_focus != nullptr) { if (this->GetWidget(widget_index) == this->nested_focus) return false; /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ @@ -509,7 +509,7 @@ bool Window::SetFocusedWidget(int widget_index) */ void Window::OnFocusLost() { - if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); + if (this->nested_focus != nullptr && this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); } /** @@ -559,7 +559,7 @@ void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...) void Window::RaiseButtons(bool autoraise) { for (uint i = 0; i < this->nested_array_size; i++) { - if (this->nested_array[i] == NULL) continue; + if (this->nested_array[i] == nullptr) continue; WidgetType type = this->nested_array[i]->type; if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { @@ -569,8 +569,8 @@ void Window::RaiseButtons(bool autoraise) } /* Special widgets without widget index */ - NWidgetCore *wid = this->nested_root != NULL ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : NULL; - if (wid != NULL) { + NWidgetCore *wid = this->nested_root != nullptr ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : nullptr; + if (wid != nullptr) { wid->SetLowered(false); wid->SetDirty(this); } @@ -583,7 +583,7 @@ void Window::RaiseButtons(bool autoraise) void Window::SetWidgetDirty(byte widget_index) const { /* Sometimes this function is called before the window is even fully initialized */ - if (this->nested_array == NULL) return; + if (this->nested_array == nullptr) return; this->nested_array[widget_index]->SetDirty(this); } @@ -598,7 +598,7 @@ EventState Window::OnHotkey(int hotkey) if (hotkey < 0) return ES_NOT_HANDLED; NWidgetCore *nw = this->GetWidget(hotkey); - if (nw == NULL || nw->IsDisabled()) return ES_NOT_HANDLED; + if (nw == nullptr || nw->IsDisabled()) return ES_NOT_HANDLED; if (nw->type == WWT_EDITBOX) { if (this->IsShaded()) return ES_NOT_HANDLED; @@ -638,7 +638,7 @@ static void StartWindowSizing(Window *w, bool to_left); static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) { NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); - WidgetType widget_type = (nw != NULL) ? nw->type : WWT_EMPTY; + WidgetType widget_type = (nw != nullptr) ? nw->type : WWT_EMPTY; bool focused_widget_changed = false; /* If clicked on a window that previously did dot have focus */ @@ -649,7 +649,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) SetFocusedWindow(w); } - if (nw == NULL) return; // exit if clicked outside of widgets + if (nw == nullptr) return; // exit if clicked outside of widgets /* don't allow any interaction if the button has been disabled */ if (nw->IsDisabled()) return; @@ -688,7 +688,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) case WWT_EDITBOX: { QueryString *query = w->GetQueryString(widget_index); - if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); + if (query != nullptr) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); break; } @@ -770,7 +770,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) static void DispatchRightClickEvent(Window *w, int x, int y) { NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); - if (wid == NULL) return; + if (wid == nullptr) return; Point pt = { x, y }; @@ -783,7 +783,7 @@ static void DispatchRightClickEvent(Window *w, int x, int y) if (_settings_client.gui.right_mouse_wnd_close && w->nested_root->GetWidgetOfType(WWT_CLOSEBOX)) { delete w; } else if (_settings_client.gui.hover_delay_ms == 0 && !w->OnTooltip(pt, wid->index, TCC_RIGHT_CLICK) && wid->tool_tip != 0) { - GuiShowTooltips(w, wid->tool_tip, 0, NULL, TCC_RIGHT_CLICK); + GuiShowTooltips(w, wid->tool_tip, 0, nullptr, TCC_RIGHT_CLICK); } } @@ -798,7 +798,7 @@ static void DispatchHoverEvent(Window *w, int x, int y) NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); /* No widget to handle */ - if (wid == NULL) return; + if (wid == nullptr) return; Point pt = { x, y }; @@ -823,7 +823,7 @@ static void DispatchHoverEvent(Window *w, int x, int y) */ static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) { - if (nwid == NULL) return; + if (nwid == nullptr) return; /* Using wheel on caption/shade-box shades or unshades the window. */ if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) { @@ -842,8 +842,8 @@ static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) } /* Scroll the widget attached to the scrollbar. */ - Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : NULL); - if (sb != NULL && sb->GetCount() > sb->GetCapacity()) { + Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : nullptr); + if (sb != nullptr && sb->GetCount() > sb->GetCapacity()) { sb->UpdatePosition(wheel); w->SetDirty(); } @@ -1016,12 +1016,12 @@ void Window::ReInit(int rx, int ry) */ void Window::SetShaded(bool make_shaded) { - if (this->shade_select == NULL) return; + if (this->shade_select == nullptr) return; int desired = make_shaded ? SZSP_HORIZONTAL : 0; if (this->shade_select->shown_plane != desired) { if (make_shaded) { - if (this->nested_focus != NULL) this->UnfocusFocusedWidget(); + if (this->nested_focus != nullptr) this->UnfocusFocusedWidget(); this->unshaded_size.width = this->width; this->unshaded_size.height = this->height; this->shade_select->SetDisplayedPlane(desired); @@ -1039,7 +1039,7 @@ void Window::SetShaded(bool make_shaded) * Find the Window whose parent pointer points to this window * @param w parent Window to find child of * @param wc Window class of the window to remove; #WC_INVALID if class does not matter - * @return a Window pointer that is the child of \a w, or \c NULL otherwise + * @return a Window pointer that is the child of \a w, or \c nullptr otherwise */ static Window *FindChildWindow(const Window *w, WindowClass wc) { @@ -1048,7 +1048,7 @@ static Window *FindChildWindow(const Window *w, WindowClass wc) if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; } - return NULL; + return nullptr; } /** @@ -1058,7 +1058,7 @@ static Window *FindChildWindow(const Window *w, WindowClass wc) void Window::DeleteChildWindows(WindowClass wc) const { Window *child = FindChildWindow(this, wc); - while (child != NULL) { + while (child != nullptr) { delete child; child = FindChildWindow(this, wc); } @@ -1075,20 +1075,20 @@ Window::~Window() } /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */ - if (_mouseover_last_w == this) _mouseover_last_w = NULL; + if (_mouseover_last_w == this) _mouseover_last_w = nullptr; /* We can't scroll the window when it's closed. */ - if (_last_scroll_window == this) _last_scroll_window = NULL; + if (_last_scroll_window == this) _last_scroll_window = nullptr; /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ if (_focused_window == this) { this->OnFocusLost(); - _focused_window = NULL; + _focused_window = nullptr; } this->DeleteChildWindows(); - if (this->viewport != NULL) DeleteWindowViewport(this); + if (this->viewport != nullptr) DeleteWindowViewport(this); this->SetDirty(); @@ -1111,7 +1111,7 @@ Window::~Window() * Find a window by its class and window number * @param cls Window class * @param number Number of the window within the window class - * @return Pointer to the found window, or \c NULL if not available + * @return Pointer to the found window, or \c nullptr if not available */ Window *FindWindowById(WindowClass cls, WindowNumber number) { @@ -1120,14 +1120,14 @@ Window *FindWindowById(WindowClass cls, WindowNumber number) if (w->window_class == cls && w->window_number == number) return w; } - return NULL; + return nullptr; } /** * Find any window by its class. Useful when searching for a window that uses * the window number as a #WindowClass, like #WC_SEND_NETWORK_MSG. * @param cls Window class - * @return Pointer to the found window, or \c NULL if not available + * @return Pointer to the found window, or \c nullptr if not available */ Window *FindWindowByClass(WindowClass cls) { @@ -1136,7 +1136,7 @@ Window *FindWindowByClass(WindowClass cls) if (w->window_class == cls) return w; } - return NULL; + return nullptr; } /** @@ -1148,7 +1148,7 @@ Window *FindWindowByClass(WindowClass cls) void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) { Window *w = FindWindowById(cls, number); - if (force || w == NULL || + if (force || w == nullptr || (w->flags & WF_STICKY) == 0) { delete w; } @@ -1247,7 +1247,7 @@ Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) { Window *w = FindWindowById(cls, number); - if (w != NULL) { + if (w != nullptr) { if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded. w->SetWhiteBorder(); @@ -1360,17 +1360,17 @@ static uint GetWindowZPriority(WindowClass wc) */ static void AddWindowToZOrdering(Window *w) { - assert(w->z_front == NULL && w->z_back == NULL); + assert(w->z_front == nullptr && w->z_back == nullptr); - if (_z_front_window == NULL) { + if (_z_front_window == nullptr) { /* It's the only window. */ _z_front_window = _z_back_window = w; - w->z_front = w->z_back = NULL; + w->z_front = w->z_back = nullptr; } else { /* Search down the z-ordering for its location. */ Window *v = _z_front_window; uint last_z_priority = UINT_MAX; - while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v->window_class) > GetWindowZPriority(w->window_class))) { + while (v != nullptr && (v->window_class == WC_INVALID || GetWindowZPriority(v->window_class) > GetWindowZPriority(w->window_class))) { if (v->window_class != WC_INVALID) { /* Sanity check z-ordering, while we're at it. */ assert(last_z_priority >= GetWindowZPriority(v->window_class)); @@ -1380,15 +1380,15 @@ static void AddWindowToZOrdering(Window *w) v = v->z_back; } - if (v == NULL) { + if (v == nullptr) { /* It's the new back window. */ w->z_front = _z_back_window; - w->z_back = NULL; + w->z_back = nullptr; _z_back_window->z_back = w; _z_back_window = w; } else if (v == _z_front_window) { /* It's the new front window. */ - w->z_front = NULL; + w->z_front = nullptr; w->z_back = _z_front_window; _z_front_window->z_front = w; _z_front_window = w; @@ -1409,21 +1409,21 @@ static void AddWindowToZOrdering(Window *w) */ static void RemoveWindowFromZOrdering(Window *w) { - if (w->z_front == NULL) { + if (w->z_front == nullptr) { assert(_z_front_window == w); _z_front_window = w->z_back; } else { w->z_front->z_back = w->z_back; } - if (w->z_back == NULL) { + if (w->z_back == nullptr) { assert(_z_back_window == w); _z_back_window = w->z_front; } else { w->z_back->z_front = w->z_front; } - w->z_front = w->z_back = NULL; + w->z_front = w->z_back = nullptr; } /** @@ -1443,8 +1443,8 @@ static void BringWindowToFront(Window *w) * Initializes the data (except the position and initial size) of a new Window. * @param window_number Number being assigned to the new window * @return Window pointer of the newly created window - * @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized. - * In addition, #nested_array is either \c NULL, or already initialized. + * @pre If nested widgets are used (\a widget is \c nullptr), #nested_root and #nested_array_size must be initialized. + * In addition, #nested_array is either \c nullptr, or already initialized. */ void Window::InitializeData(WindowNumber window_number) { @@ -1453,12 +1453,12 @@ void Window::InitializeData(WindowNumber window_number) this->SetWhiteBorder(); if (this->window_desc->default_pos == WDP_CENTER) this->flags |= WF_CENTERED; this->owner = INVALID_OWNER; - this->nested_focus = NULL; + this->nested_focus = nullptr; this->window_number = window_number; this->OnInit(); /* Initialize nested widget tree. */ - if (this->nested_array == NULL) { + if (this->nested_array == nullptr) { this->nested_array = CallocT(this->nested_array_size); this->nested_root->SetupSmallestSize(this, true); } else { @@ -1475,7 +1475,7 @@ void Window::InitializeData(WindowNumber window_number) /* Give focus to the opened window unless a text box * of focused window has focus (so we don't interrupt typing). But if the new * window has a text box, then take focus anyway. */ - if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this); + if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != nullptr) SetFocusedWindow(this); /* Insert the window into the correct location in the z-ordering. */ AddWindowToZOrdering(this); @@ -1519,9 +1519,9 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) /* Think about the overlapping toolbars when determining the minimum window size */ int free_height = _screen.height; const Window *wt = FindWindowById(WC_STATUS_BAR, 0); - if (wt != NULL) free_height -= wt->height; + if (wt != nullptr) free_height -= wt->height; wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - if (wt != NULL) free_height -= wt->height; + if (wt != nullptr) free_height -= wt->height; int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); @@ -1545,10 +1545,10 @@ void Window::FindWindowPlacementAndResize(int def_width, int def_height) if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); - ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); + ny = max(ny, (wt == nullptr || this == wt || this->top == 0) ? 0 : wt->height); nx = max(nx, 0); - if (this->viewport != NULL) { + if (this->viewport != nullptr) { this->viewport->left += nx - this->left; this->viewport->top += ny - this->top; } @@ -1655,7 +1655,7 @@ static Point GetAutoPlacePosition(int width, int height) /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); - const int toolbar_y = main_toolbar != NULL ? main_toolbar->height : 0; + const int toolbar_y = main_toolbar != nullptr ? main_toolbar->height : 0; if (IsGoodAutoPlace1(rtl ? _screen.width - width : 0, toolbar_y, width, height, toolbar_y, pt)) return pt; /* Second attempt, try around all existing windows. @@ -1719,7 +1719,7 @@ restart: Point GetToolbarAlignedWindowPosition(int window_width) { const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - assert(w != NULL); + assert(w != nullptr); Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; return pt; } @@ -1749,7 +1749,7 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int int16 default_width = max(desc->GetDefaultWidth(), sm_width); int16 default_height = max(desc->GetDefaultHeight(), sm_height); - if (desc->parent_cls != WC_NONE && (w = FindWindowById(desc->parent_cls, window_number)) != NULL) { + if (desc->parent_cls != WC_NONE && (w = FindWindowById(desc->parent_cls, window_number)) != nullptr) { bool rtl = _current_text_dir == TD_RTL; if (desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) { pt.x = w->left + (rtl ? w->width - default_width : 0); @@ -1862,7 +1862,7 @@ Window::Window(WindowDesc *desc) : window_desc(desc), mouse_capture_widget(-1) * at the topmost window, obviously and work our way down to the bottom * @param x position x to query * @param y position y to query - * @return a pointer to the found window if any, NULL otherwise + * @return a pointer to the found window if any, nullptr otherwise */ Window *FindWindowFromPt(int x, int y) { @@ -1873,7 +1873,7 @@ Window *FindWindowFromPt(int x, int y) } } - return NULL; + return nullptr; } /** @@ -1883,11 +1883,11 @@ void InitWindowSystem() { IConsoleClose(); - _z_back_window = NULL; - _z_front_window = NULL; - _focused_window = NULL; - _mouseover_last_w = NULL; - _last_scroll_window = NULL; + _z_back_window = nullptr; + _z_front_window = nullptr; + _focused_window = nullptr; + _mouseover_last_w = nullptr; + _last_scroll_window = nullptr; _scrolling_viewport = false; _mouse_hovering = false; @@ -1907,14 +1907,14 @@ void UnInitWindowSystem() Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; - for (w = _z_front_window; w != NULL; /* nothing */) { + for (w = _z_front_window; w != nullptr; /* nothing */) { Window *to_del = w; w = w->z_back; free(to_del); } - _z_front_window = NULL; - _z_back_window = NULL; + _z_front_window = nullptr; + _z_back_window = nullptr; } /** @@ -1937,7 +1937,7 @@ static void DecreaseWindowCounters() /* Unclick scrollbar buttons if they are pressed. */ for (uint i = 0; i < w->nested_array_size; i++) { NWidgetBase *nwid = w->nested_array[i]; - if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { + if (nwid != nullptr && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { NWidgetScrollbar *sb = static_cast(nwid); if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); @@ -1949,8 +1949,8 @@ static void DecreaseWindowCounters() } /* Handle editboxes */ - for (SmallMap::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) { - it->second->HandleEditBox(w, it->first); + for (SmallMap::Pair &pair : w->querystrings) { + pair.second->HandleEditBox(w, pair.first); } w->OnMouseLoop(); @@ -1971,7 +1971,7 @@ static void HandlePlacePresize() if (_special_mouse_mode != WSM_PRESIZE) return; Window *w = _thd.GetCallbackWnd(); - if (w == NULL) return; + if (w == nullptr) return; Point pt = GetTileBelowCursor(); if (pt.x == -1) { @@ -1993,7 +1993,7 @@ static EventState HandleMouseDragDrop() if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move. Window *w = _thd.GetCallbackWnd(); - if (w != NULL) { + if (w != nullptr) { /* Send an event in client coordinates. */ Point pt; pt.x = _cursor.pos.x - w->left; @@ -2015,7 +2015,7 @@ static void HandleMouseOver() Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); /* We changed window, put an OnMouseOver event to the last window */ - if (_mouseover_last_w != NULL && _mouseover_last_w != w) { + if (_mouseover_last_w != nullptr && _mouseover_last_w != w) { /* Reset mouse-over coordinates of previous window */ Point pt = { -1, -1 }; _mouseover_last_w->OnMouseOver(pt, 0); @@ -2024,11 +2024,11 @@ static void HandleMouseOver() /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ _mouseover_last_w = w; - if (w != NULL) { + if (w != nullptr) { /* send an event in client coordinates. */ Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y); - if (widget != NULL) w->OnMouseOver(pt, widget->index); + if (widget != nullptr) w->OnMouseOver(pt, widget->index); } } @@ -2053,7 +2053,7 @@ enum PreventHideDirection { */ static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir) { - if (v == NULL) return; + if (v == nullptr) return; int v_bottom = v->top + v->height; int v_right = v->left + v->width; @@ -2094,7 +2094,7 @@ static void EnsureVisibleCaption(Window *w, int nx, int ny) /* Search for the title bar rectangle. */ Rect caption_rect; const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION); - if (caption != NULL) { + if (caption != nullptr) { caption_rect.left = caption->pos_x; caption_rect.right = caption->pos_x + caption->current_x; caption_rect.top = caption->pos_y; @@ -2109,7 +2109,7 @@ static void EnsureVisibleCaption(Window *w, int nx, int ny) PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); } - if (w->viewport != NULL) { + if (w->viewport != nullptr) { w->viewport->left += nx - w->left; w->viewport->top += ny - w->top; } @@ -2167,7 +2167,7 @@ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) int GetMainViewTop() { Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); - return (w == NULL) ? 0 : w->top + w->height; + return (w == nullptr) ? 0 : w->top + w->height; } /** @@ -2178,7 +2178,7 @@ int GetMainViewTop() int GetMainViewBottom() { Window *w = FindWindowById(WC_STATUS_BAR, 0); - return (w == NULL) ? _screen.height : w->top; + return (w == nullptr) ? _screen.height : w->top; } static bool _dragging_window; ///< A window is being dragged or resized. @@ -2474,12 +2474,12 @@ static EventState HandleViewportScroll() /* When we don't have a last scroll window we are starting to scroll. * When the last scroll window and this are not the same we went * outside of the window and should not left-mouse scroll anymore. */ - if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + if (_last_scroll_window == nullptr) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); - if (_last_scroll_window == NULL || !((_settings_client.gui.scroll_mode != VSM_MAP_LMB && _right_button_down) || scrollwheel_scrolling || (_settings_client.gui.scroll_mode == VSM_MAP_LMB && _left_button_down))) { + if (_last_scroll_window == nullptr || !((_settings_client.gui.scroll_mode != VSM_MAP_LMB && _right_button_down) || scrollwheel_scrolling || (_settings_client.gui.scroll_mode == VSM_MAP_LMB && _left_button_down))) { _cursor.fix_at = false; _scrolling_viewport = false; - _last_scroll_window = NULL; + _last_scroll_window = nullptr; return ES_NOT_HANDLED; } @@ -2586,7 +2586,7 @@ static bool MaybeBringWindowToFront(Window *w) EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode) { QueryString *query = this->GetQueryString(wid); - if (query == NULL) return ES_NOT_HANDLED; + if (query == nullptr) return ES_NOT_HANDLED; int action = QueryString::ACTION_NOTHING; @@ -2690,7 +2690,7 @@ void HandleKeypress(uint keycode, WChar key) Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (w->window_class == WC_MAIN_TOOLBAR) continue; - if (w->window_desc->hotkeys != NULL) { + if (w->window_desc->hotkeys != nullptr) { int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; } @@ -2699,8 +2699,8 @@ void HandleKeypress(uint keycode, WChar key) w = FindWindowById(WC_MAIN_TOOLBAR, 0); /* When there is no toolbar w is null, check for that */ - if (w != NULL) { - if (w->window_desc->hotkeys != NULL) { + if (w != nullptr) { + if (w->window_desc->hotkeys != nullptr) { int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; } @@ -2730,7 +2730,7 @@ void HandleCtrlChanged() /* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) { QueryString *query = this->GetQueryString(wid); - if (query == NULL) return; + if (query == nullptr) return; if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) { this->SetWidgetDirty(wid); @@ -2772,11 +2772,11 @@ static void HandleAutoscroll() int x = _cursor.pos.x; int y = _cursor.pos.y; Window *w = FindWindowFromPt(x, y); - if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; + if (w == nullptr || w->flags & WF_DISABLE_VP_SCROLL) return; if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; ViewPort *vp = IsPtInWindowViewport(w, x, y); - if (vp == NULL) return; + if (vp == nullptr) return; x -= vp->left; y -= vp->top; @@ -2882,23 +2882,23 @@ static void MouseLoop(MouseClick click, int mousewheel) int x = _cursor.pos.x; int y = _cursor.pos.y; Window *w = FindWindowFromPt(x, y); - if (w == NULL) return; + if (w == nullptr) return; if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return; ViewPort *vp = IsPtInWindowViewport(w, x, y); /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ - if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; + if (vp != nullptr && (_game_mode == GM_MENU || HasModalProgress())) return; if (mousewheel != 0) { /* Send mousewheel event to window, unless we're scrolling a viewport or the map */ - if (!scrollwheel_scrolling || (vp == NULL && w->window_class != WC_SMALLMAP)) w->OnMouseWheel(mousewheel); + if (!scrollwheel_scrolling || (vp == nullptr && w->window_class != WC_SMALLMAP)) w->OnMouseWheel(mousewheel); /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ - if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); + if (vp == nullptr) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); } - if (vp != NULL) { + if (vp != nullptr) { if (scrollwheel_scrolling && !(w->flags & WF_DISABLE_VP_SCROLL)) { _scrolling_viewport = true; _cursor.fix_at = true; @@ -2932,7 +2932,7 @@ static void MouseLoop(MouseClick click, int mousewheel) } } - if (vp == NULL || (w->flags & WF_DISABLE_VP_SCROLL)) { + if (vp == nullptr || (w->flags & WF_DISABLE_VP_SCROLL)) { switch (click) { case MC_LEFT: case MC_DOUBLE_LEFT: @@ -2940,7 +2940,7 @@ static void MouseLoop(MouseClick click, int mousewheel) return; default: - if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; + if (!scrollwheel_scrolling || w == nullptr || w->window_class != WC_SMALLMAP) break; /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. * Simulate a right button click so we can get started. */ FALLTHROUGH; @@ -3029,7 +3029,7 @@ void HandleMouseEvents() Blitter *blitter = BlitterFactory::GetCurrentBlitter(); _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y); _newgrf_debug_sprite_picker.click_time = _realtime_tick; - _newgrf_debug_sprite_picker.sprites.Clear(); + _newgrf_debug_sprite_picker.sprites.clear(); _newgrf_debug_sprite_picker.mode = SPM_REDRAW; MarkWholeScreenDirty(); } else { @@ -3051,7 +3051,7 @@ static void CheckSoftLimit() for (;;) { uint deletable_count = 0; - Window *w, *last_deletable = NULL; + Window *w, *last_deletable = nullptr; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; @@ -3062,7 +3062,7 @@ static void CheckSoftLimit() /* We've not reached the soft limit yet. */ if (deletable_count <= _settings_client.gui.window_soft_limit) break; - assert(last_deletable != NULL); + assert(last_deletable != nullptr); delete last_deletable; } } @@ -3079,7 +3079,7 @@ void InputLoop() CheckSoftLimit(); /* Do the actual free of the deleted windows. */ - for (Window *v = _z_front_window; v != NULL; /* nothing */) { + for (Window *v = _z_front_window; v != nullptr; /* nothing */) { Window *w = v; v = v->z_back; @@ -3127,13 +3127,11 @@ void UpdateWindows() CallWindowRealtimeTickEvent(delta_ms); -#ifdef ENABLE_NETWORK static GUITimer network_message_timer = GUITimer(1); if (network_message_timer.Elapsed(delta_ms)) { network_message_timer.SetInterval(1000); NetworkChatMessageLoop(); } -#endif Window *w; @@ -3191,7 +3189,7 @@ void UpdateWindows() FOR_ALL_WINDOWS_FROM_BACK(w) { /* Update viewport only if window is not shaded. */ - if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w); + if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w); } NetworkDrawChatMessage(); /* Redraw mouse cursor in case it was hidden */ @@ -3249,7 +3247,7 @@ void Window::InvalidateData(int data, bool gui_scope) this->SetDirty(); if (!gui_scope) { /* Schedule GUI-scope invalidation for next redraw. */ - *this->scheduled_invalidation_data.Append() = data; + this->scheduled_invalidation_data.push_back(data); } this->OnInvalidateData(data, gui_scope); } @@ -3259,10 +3257,11 @@ void Window::InvalidateData(int data, bool gui_scope) */ void Window::ProcessScheduledInvalidations() { - for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { - this->OnInvalidateData(*data, true); + for (int data : this->scheduled_invalidation_data) { + if (this->window_class == WC_INVALID) break; + this->OnInvalidateData(data, true); } - this->scheduled_invalidation_data.Clear(); + this->scheduled_invalidation_data.clear(); } /** @@ -3450,10 +3449,9 @@ void ReInitAllWindows() FOR_ALL_WINDOWS_FROM_BACK(w) { w->ReInit(); } -#ifdef ENABLE_NETWORK + void NetworkReInitChatBoxSize(); NetworkReInitChatBoxSize(); -#endif /* Make sure essential parts of all windows are visible */ RelocateAllWindows(_cur_resolution.width, _cur_resolution.height); @@ -3462,17 +3460,17 @@ void ReInitAllWindows() /** * (Re)position a window at the screen. - * @param w Window structure of the window, may also be \c NULL. + * @param w Window structure of the window, may also be \c nullptr. * @param clss The class of the window to position. * @param setting The actual setting used for the window's position. * @return X coordinate of left edge of the repositioned window. */ static int PositionWindow(Window *w, WindowClass clss, int setting) { - if (w == NULL || w->window_class != clss) { + if (w == nullptr || w->window_class != clss) { w = FindWindowById(clss, 0); } - if (w == NULL) return 0; + if (w == nullptr) return 0; int old_left = w->left; switch (setting) { @@ -3480,14 +3478,14 @@ static int PositionWindow(Window *w, WindowClass clss, int setting) case 2: w->left = _screen.width - w->width; break; default: w->left = 0; break; } - if (w->viewport != NULL) w->viewport->left += w->left - old_left; + if (w->viewport != nullptr) w->viewport->left += w->left - old_left; SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row return w->left; } /** * (Re)position main toolbar window at the screen. - * @param w Window structure of the main toolbar window, may also be \c NULL. + * @param w Window structure of the main toolbar window, may also be \c nullptr. * @return X coordinate of left edge of the repositioned toolbar window. */ int PositionMainToolbar(Window *w) @@ -3498,7 +3496,7 @@ int PositionMainToolbar(Window *w) /** * (Re)position statusbar window at the screen. - * @param w Window structure of the statusbar window, may also be \c NULL. + * @param w Window structure of the statusbar window, may also be \c nullptr. * @return X coordinate of left edge of the repositioned statusbar. */ int PositionStatusbar(Window *w) @@ -3509,7 +3507,7 @@ int PositionStatusbar(Window *w) /** * (Re)position news message window at the screen. - * @param w Window structure of the news message window, may also be \c NULL. + * @param w Window structure of the news message window, may also be \c nullptr. * @return X coordinate of left edge of the repositioned news message. */ int PositionNewsMessage(Window *w) @@ -3520,7 +3518,7 @@ int PositionNewsMessage(Window *w) /** * (Re)position network chat window at the screen. - * @param w Window structure of the network chat window, may also be \c NULL. + * @param w Window structure of the network chat window, may also be \c nullptr. * @return X coordinate of left edge of the repositioned network chat window. */ int PositionNetworkChatWindow(Window *w) @@ -3539,7 +3537,7 @@ void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { - if (w->viewport != NULL && w->viewport->follow_vehicle == from_index) { + if (w->viewport != nullptr && w->viewport->follow_vehicle == from_index) { w->viewport->follow_vehicle = to_index; w->SetDirty(); } @@ -3666,6 +3664,7 @@ WindowPopup::WindowPopup(WindowDesc *desc, WindowPopupType t): Window(desc) y = _cursor.pos.y - wid->pos_y + this->wpu_mod_y; break; } + FALLTHROUGH; // suppress warning, no idea if it's actually correct case WPUT_ORIGIN: default: x = _cursor.pos.x + this->wpu_mod_x; diff --git a/src/window_gui.h b/src/window_gui.h index 4b7b884763..98aa51a997 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -170,14 +170,14 @@ struct WindowDesc : ZeroedMemoryAllocator { WindowDesc(WindowPosition default_pos, const char *ini_key, int16 def_width_trad, int16 def_height_trad, WindowClass window_class, WindowClass parent_class, uint32 flags, - const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys = NULL); + const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys = nullptr); ~WindowDesc(); WindowPosition default_pos; ///< Preferred position of the window. @see WindowPosition() WindowClass cls; ///< Class of the window, @see WindowClass. WindowClass parent_cls; ///< Class of the parent window. @see WindowClass - const char *ini_key; ///< Key to store window defaults in openttd.cfg. \c NULL if nothing shall be stored. + const char *ini_key; ///< Key to store window defaults in openttd.cfg. \c nullptr if nothing shall be stored. uint32 flags; ///< Flags. @see WindowDefaultFlag const NWidgetPart *nwid_parts; ///< Nested widget parts describing the window. int16 nwid_length; ///< Length of the #nwid_parts array. @@ -282,7 +282,7 @@ protected: void InitializePositionSize(int x, int y, int min_width, int min_height); virtual void FindWindowPlacementAndResize(int def_width, int def_height); - SmallVector scheduled_invalidation_data; ///< Data of scheduled OnInvalidateData() calls. + std::vector scheduled_invalidation_data; ///< Data of scheduled OnInvalidateData() calls. public: Window(WindowDesc *desc); @@ -327,12 +327,12 @@ public: Owner owner; ///< The owner of the content shown in this window. Company colour is acquired from this variable. ViewportData *viewport; ///< Pointer to viewport data, if present. - const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c NULL if no nested widget has focus. + const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c nullptr if no nested widget has focus. SmallMap querystrings; ///< QueryString associated to WWT_EDITBOX widgets. NWidgetBase *nested_root; ///< Root of the nested tree. NWidgetBase **nested_array; ///< Array of pointers into the tree. Do not access directly, use #Window::GetWidget() instead. uint nested_array_size; ///< Size of the nested array. - NWidgetStacked *shade_select; ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c NULL, window cannot shade. + NWidgetStacked *shade_select; ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c nullptr, window cannot shade. Dimension unshaded_size; ///< Last known unshaded size (only valid while shaded). int mouse_capture_widget; ///< Widgetindex of current mouse capture widget (e.g. dragged scrollbar). -1 if no widget has mouse capture. @@ -395,7 +395,7 @@ public: inline void SetWidgetDisabledState(byte widget_index, bool disab_stat) { assert(widget_index < this->nested_array_size); - if (this->nested_array[widget_index] != NULL) this->GetWidget(widget_index)->SetDisabled(disab_stat); + if (this->nested_array[widget_index] != nullptr) this->GetWidget(widget_index)->SetDisabled(disab_stat); } /** @@ -434,7 +434,7 @@ public: */ inline bool IsWidgetFocused(byte widget_index) const { - return this->nested_focus != NULL && this->nested_focus->index == widget_index; + return this->nested_focus != nullptr && this->nested_focus->index == widget_index; } /** @@ -526,7 +526,7 @@ public: /** Is window shaded currently? */ inline bool IsShaded() const { - return this->shade_select != NULL && this->shade_select->shown_plane == SZSP_HORIZONTAL; + return this->shade_select != nullptr && this->shade_select->shown_plane == SZSP_HORIZONTAL; } void SetShaded(bool make_shaded); @@ -735,7 +735,7 @@ public: /** * The query window opened from this window has closed. - * @param str the new value of the string, NULL if the window + * @param str the new value of the string, nullptr if the window * was cancelled or an empty string when the default * button was pressed, i.e. StrEmpty(str). */ @@ -819,14 +819,14 @@ public: * Get the nested widget with number \a widnum from the nested widget tree. * @tparam NWID Type of the nested widget. * @param widnum Widget number of the widget to retrieve. - * @return The requested widget if it is instantiated, \c NULL otherwise. + * @return The requested widget if it is instantiated, \c nullptr otherwise. */ template inline NWID *Window::GetWidget(uint widnum) { - if (widnum >= this->nested_array_size || this->nested_array[widnum] == NULL) return NULL; + if (widnum >= this->nested_array_size || this->nested_array[widnum] == nullptr) return nullptr; NWID *nwid = dynamic_cast(this->nested_array[widnum]); - assert(nwid != NULL); + assert(nwid != nullptr); return nwid; } @@ -834,7 +834,7 @@ inline NWID *Window::GetWidget(uint widnum) template <> inline const NWidgetBase *Window::GetWidget(uint widnum) const { - if (widnum >= this->nested_array_size) return NULL; + if (widnum >= this->nested_array_size) return nullptr; return this->nested_array[widnum]; } @@ -842,7 +842,7 @@ inline const NWidgetBase *Window::GetWidget(uint widnum) const * Get the nested widget with number \a widnum from the nested widget tree. * @tparam NWID Type of the nested widget. * @param widnum Widget number of the widget to retrieve. - * @return The requested widget if it is instantiated, \c NULL otherwise. + * @return The requested widget if it is instantiated, \c nullptr otherwise. */ template inline const NWID *Window::GetWidget(uint widnum) const @@ -874,19 +874,19 @@ Window *FindWindowFromPt(int x, int y); * @param desc The pointer to the WindowDesc to be created * @param window_number the window number of the new window * @param return_existing If set, also return the window if it already existed. - * @return %Window pointer of the newly created window, or the existing one if \a return_existing is set, or \c NULL. + * @return %Window pointer of the newly created window, or the existing one if \a return_existing is set, or \c nullptr. */ template Wcls *AllocateWindowDescFront(WindowDesc *desc, int window_number, bool return_existing = false) { Wcls *w = static_cast(BringWindowToFrontById(desc->cls, window_number)); - if (w != NULL) return return_existing ? w : NULL; + if (w != nullptr) return return_existing ? w : nullptr; return new Wcls(desc, window_number); } void RelocateAllWindows(int neww, int newh); -void GuiShowTooltips(Window *parent, StringID str, uint paramcount = 0, const uint64 params[] = NULL, TooltipCloseCondition close_tooltip = TCC_HOVER); +void GuiShowTooltips(Window *parent, StringID str, uint paramcount = 0, const uint64 params[] = nullptr, TooltipCloseCondition close_tooltip = TCC_HOVER); void GuiPrepareTooltipsExtra(Window *parent); void GuiShowStationRatingTooltip(Window *parent, const Station *st, const CargoSpec *cs); @@ -894,8 +894,8 @@ void GuiShowStationRatingTooltip(Window *parent, const Station *st, const CargoS int GetWidgetFromPos(const Window *w, int x, int y); /** Iterate over all windows */ -#define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start) for (w = start; w != NULL; w = w->z_front) if (w->window_class != WC_INVALID) -#define FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, start) for (w = start; w != NULL; w = w->z_back) if (w->window_class != WC_INVALID) +#define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start) for (w = start; w != nullptr; w = w->z_front) if (w->window_class != WC_INVALID) +#define FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, start) for (w = start; w != nullptr; w = w->z_back) if (w->window_class != WC_INVALID) #define FOR_ALL_WINDOWS_FROM_BACK(w) FOR_ALL_WINDOWS_FROM_BACK_FROM(w, _z_back_window) #define FOR_ALL_WINDOWS_FROM_FRONT(w) FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, _z_front_window) diff --git a/src/zoning_cmd.cpp b/src/zoning_cmd.cpp index 91ce8216e1..5bdc9124ab 100644 --- a/src/zoning_cmd.cpp +++ b/src/zoning_cmd.cpp @@ -131,8 +131,7 @@ bool IsAreaWithinAcceptanceZoneOfStation(TileArea area) { StationFinder morestations(TileArea(TileXY(TileX(area.tile) - catchment / 2, TileY(area.tile) - catchment / 2), TileX(area.tile) + area.w + catchment, TileY(area.tile) + area.h + catchment)); - for (Station * const *st_iter = morestations.GetStations()->Begin(); st_iter != morestations.GetStations()->End(); ++st_iter) { - Station *st = *st_iter; + for (Station *st: *morestations.GetStations()) { Rect rect = st->GetCatchmentRect(); return TileArea(TileXY(rect.left, rect.top), TileXY(rect.right, rect.bottom)).Intersects(area); } @@ -151,8 +150,7 @@ bool IsTileWithinAcceptanceZoneOfStation(TileIndex tile) { StationFinder morestations(TileArea(TileXY(TileX(tile) - catchment / 2, TileY(tile) - catchment / 2), catchment, catchment)); - for (Station * const *st_iter = morestations.GetStations()->Begin(); st_iter != morestations.GetStations()->End(); ++st_iter) { - Station *st = *st_iter; + for (Station *st: *morestations.GetStations()) { Rect rect = st->GetCatchmentRect(); if ((uint)rect.left <= TileX(tile) && TileX(tile) <= (uint)rect.right && (uint)rect.top <= TileY(tile) && TileY(tile) <= (uint)rect.bottom ) @@ -211,7 +209,7 @@ SpriteID TileZoneCheckBuildEvaluation(TileIndex tile, Owner owner) { } // For provided goods StationFinder stations(TileArea(tile, 1, 1)); - if (stations.GetStations()->Length() > 0) { + if (!stations.GetStations()->empty()) { return SPR_PALETTE_ZONING_GREEN; } // For accepted goods @@ -232,7 +230,7 @@ SpriteID TileZoneCheckUnservedBuildingsEvaluation(TileIndex tile) { { StationFinder stations(TileArea(tile, 1, 1)); - if (stations.GetStations()->Length() > 0) { + if (!stations.GetStations()->empty()) { return INVALID_SPRITE_ID; } // For accepted goods @@ -251,7 +249,7 @@ SpriteID TileZoneCheckUnservedIndustriesEvaluation(TileIndex tile) { Industry *ind = Industry::GetByTile(tile); StationFinder stations(ind->location); - if (stations.GetStations()->Length() > 0){ + if (!stations.GetStations()->empty()){ return INVALID_SPRITE_ID; } diff --git a/src/zoom_func.h b/src/zoom_func.h index 0e8fa8c9ef..dff7322a03 100644 --- a/src/zoom_func.h +++ b/src/zoom_func.h @@ -23,7 +23,6 @@ */ static inline int ScaleByZoom(int value, ZoomLevel zoom) { - assert(zoom >= 0); return value << zoom; } @@ -36,7 +35,6 @@ static inline int ScaleByZoom(int value, ZoomLevel zoom) */ static inline int UnScaleByZoom(int value, ZoomLevel zoom) { - assert(zoom >= 0); return (value + (1 << zoom) - 1) >> zoom; } @@ -48,7 +46,6 @@ static inline int UnScaleByZoom(int value, ZoomLevel zoom) */ static inline int ScaleByZoomLower(int value, ZoomLevel zoom) { - assert(zoom >= 0); return value << zoom; } @@ -60,7 +57,6 @@ static inline int ScaleByZoomLower(int value, ZoomLevel zoom) */ static inline int UnScaleByZoomLower(int value, ZoomLevel zoom) { - assert(zoom >= 0); return value >> zoom; } diff --git a/src/zoom_type.h b/src/zoom_type.h index ea8302761f..47a725df2b 100644 --- a/src/zoom_type.h +++ b/src/zoom_type.h @@ -14,11 +14,11 @@ #include "core/enum_type.hpp" -static int const ZOOM_LVL_SHIFT = 2; -static int const ZOOM_LVL_BASE = 1 << ZOOM_LVL_SHIFT; +static uint const ZOOM_LVL_SHIFT = 2; +static uint const ZOOM_LVL_BASE = 1 << ZOOM_LVL_SHIFT; /** All zoom levels we know. */ -enum ZoomLevel { +enum ZoomLevel : byte { /* Our possible zoom-levels */ ZOOM_LVL_BEGIN = 0, ///< Begin for iteration. ZOOM_LVL_NORMAL = 0, ///< The normal zoom level. @@ -46,14 +46,12 @@ enum ZoomLevel { ZOOM_LVL_MIN = ZOOM_LVL_NORMAL, ///< Minimum zoom level. ZOOM_LVL_MAX = ZOOM_LVL_OUT_32X, ///< Maximum zoom level. + }; DECLARE_POSTFIX_INCREMENT(ZoomLevel) -/** Type for storing the zoom level in a byte. */ -typedef SimpleTinyEnumT ZoomLevelByte; - -extern ZoomLevelByte _gui_zoom; -extern ZoomLevelByte _font_zoom; +extern ZoomLevel _gui_zoom; +extern ZoomLevel _font_zoom; #define ZOOM_LVL_GUI (_gui_zoom) #define ZOOM_LVL_FONT (_font_zoom)
       
        +
      • m1 bit 7: Ship docking tile status
      • 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)
      • @@ -1443,8 +1462,10 @@
       
        +
      • m1 bit 7: Ship docking tile status (for aqueducts)
      • m1 bits 4..0: owner
      • m3 bits 7..4: owner of tram
      • +
      • m4: Roadtype
      • m5 bit 4: pbs reservation state for railway
      • m5 bits 7 clear: tunnel entrance/exit
      • m5 bit 7 set: bridge ramp @@ -1581,7 +1602,7 @@
      • 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 11..6: Tramtype
      • m8 bits 5..0: track type for railway
      rail XXXX XXXX XXXX XXXXOOOX XXXXXOOX XXXX OOOO XXXX OOOO OOOO OOOO OOOO OOOO XXXXOOOX XXXX XXXX XXXX XXXX XXXX XXXX XXXXOOOO OOOOOOXX XXXX XXXX XXXX OOXX XOOOXXXO XXXXOOOO OOOO OOOO OOOOOOXO XXXXOOOO XXXX XXOO OOOO
      level crossingOOOO OOOO XXXX OOOX OOXX XOOOXXXX XXXXOOOO OOOO OOXX XXXXOOXX XXXXOOOO XXXX XXXX XXXX
      road depot-inherit- -inherit- XXXX OOOOOOOO OOOO-inherit- XXOO OOXX OOOO OOOOXXXO XXXXOOOO OOOO OOOO OOOOOOXO XXXX-inherit-
      3rail station XXXX XXXX XXXX XXXXOXXX XXXXXXXX XXXX XXXX XXXX XXXX XXXX XXXX OOOO XXXX XXXX-inherit- -inherit- XXXX OOOOOOOO OOOOOOXX XXXX ~~~~ ~XXX OOXX XOOOXXOX XXXXOOOO OOOO OOOO OOOOOOOX XXXXOOOO XXXX XXOO OOOO
      docksea, shore XXXX XXXX XXXX XXXXOXXX XXXXXXXX XXXX OOOO OOOO OOOO OOOO OOOO OOOO OOOO OOOOtunnel entrance XXXX XXXX XXXX XXXXOOOX XXXXXOOX XXXX OOOO OOOO OOOO OOOO XXXX OOOOOOOO OOOOOOXX XXXX XOOX XXXX OOOO OOOOXXXX XXXXOOOO OOOO OOXX XXXXOOXX XXXXOOOO XXXX XXXX XXXX
      bridge ramp-inherit- OOOO OOOO OOOO OOOO -inherit-OOOO OOOO-inherit- -inherit- OOXX XXOO -inherit-