Merge tag '14.0-beta1' into jgrpp

# Conflicts:
#	src/3rdparty/squirrel/squirrel/sqcompiler.cpp
#	src/aircraft.h
#	src/animated_tile.h
#	src/base_consist.h
#	src/cargotype.h
#	src/company_gui.cpp
#	src/console_cmds.cpp
#	src/core/overflowsafe_type.hpp
#	src/engine_gui.cpp
#	src/industry_gui.cpp
#	src/lang/english.txt
#	src/music/extmidi.cpp
#	src/network/core/network_game_info.cpp
#	src/network/network_server.cpp
#	src/newgrf.cpp
#	src/newgrf_industries.cpp
#	src/order_base.h
#	src/order_cmd.cpp
#	src/order_gui.cpp
#	src/order_type.h
#	src/os/macosx/misc_osx.cpp
#	src/os/windows/crashlog_win.cpp
#	src/rail_gui.cpp
#	src/rail_gui.h
#	src/roadveh.h
#	src/roadveh_cmd.cpp
#	src/saveload/afterload.cpp
#	src/saveload/company_sl.cpp
#	src/saveload/saveload.cpp
#	src/saveload/saveload.h
#	src/saveload/saveload_error.hpp
#	src/script/api/script_town.cpp
#	src/settingsgen/settingsgen.cpp
#	src/ship.h
#	src/ship_cmd.cpp
#	src/smallmap_gui.cpp
#	src/spritecache.cpp
#	src/stdafx.h
#	src/strgen/strgen.cpp
#	src/strgen/strgen.h
#	src/table/settings/script_settings.ini
#	src/timetable_cmd.cpp
#	src/timetable_gui.cpp
#	src/town.h
#	src/town_cmd.cpp
#	src/town_cmd.h
#	src/town_gui.cpp
#	src/train.h
#	src/train_cmd.cpp
#	src/tree_cmd.cpp
#	src/vehicle.cpp
#	src/vehicle_base.h
#	src/vehicle_cmd.cpp
#	src/vehicle_gui.cpp
#	src/vehiclelist.cpp
#	src/waypoint_base.h
#	src/widget.cpp
pull/661/head
Jonathan G Rennison 2 months ago
commit fdd666f66a

@ -1,3 +1,285 @@
14.0-beta1 (2023-02-03)
------------------------------------------------------------------------
Feature: Order option to unbunch vehicles at depot (#11945)
Feature: Infinite money mode (#11902)
Feature: Setting to disable the loading speed penalty for trains longer than the station (#11682)
Feature: Plugin framework for Social Integration with Steam, Discord, GOG, etc (#11628)
Feature: Scalable OpenTTD TrueType font made by Zephyris (#11593)
Feature: Toyland-specific river graphics (#11523)
Feature: Add zoom level buttons to sprite aligner (#11518)
Feature: Add shading to river slopes (#11491)
Feature: Place cargo icon on cargo filter dropdowns (#11487)
Feature: Mode to display timetable in seconds (#11435)
Feature: Setting to influence how many minutes a calendar year takes (#11428)
Feature: Base graphics can offer parameters for additional settings (#11347)
Feature: Sandbox option to lock station ratings at 100% (#11346)
Feature: Setting to use real-time "wallclock" as timekeeping units (#11341)
Feature: Setting to automatically restart server based on hours played (#11142)
Feature: Add config option to set default company secondary colour for new games (#11068)
Feature: Transparency option for cost and income indicators (#11001)
Feature: Create group of vehicles from manage vehicle list button (#10890)
Feature: Show coverage highlight the same as stations when adding waypoints (#10875)
Feature: Show the number of industries already built in the Fund New Industry window (#10806)
Feature: Add search filter and name text to build waypoint window (#10786)
Feature: Setting to disallow level crossings with competitors (#10755)
Feature: Opt-in survey when leaving a game (#10719)
Feature: Replace buying/selling company shares with hostile takeovers of AI companies (#10709, #10914)
Feature: Settings to scale cargo production of towns and industries (#10606)
Feature: Separate rail/road and sea/air velocity units, and add knots (#10594)
Feature: Region-based pathfinder for ships (#10543)
Feature: Filter engine build menu by name and NewGRF extra text (#10519)
Feature: Industry directory text filter (#10518)
Feature: Ctrl+Click to reset late counter for the entire vehicle group (#10464)
Feature: Orientation of rail and road depots can be changed (#9642)
Feature: Display help and manuals in-game (#7786)
Feature: [NewGRF] Town production effect and multiplier (#11947)
Feature: [NewGRF] Randomize direction of rail vehicle on build based on probability callback (#11489)
Feature: [NewGRF] Related Act2 objects for airports and airport tiles (#11282)
Feature: [NewGRF] Allow higher max speeds for ships (#10734)
Feature: [NewGRF] Increase limit of objects/stations/roadstops per NewGRF (#10672)
Feature: [NewGRF] Road stops (#10144)
Feature: [Script] Goal destination can be updated (#10817)
Add: Argument for console command "restart" to use either current or newgame settings (#11962, #11963)
Add: {CURRENCY_SHORT} only did k / m suffix. Add bn / tn and make translatable (#11921)
Add: Show in multiplayer the amount of hours a game has been unpaused (#11886)
Add: Allow loading heightmaps from command-line (#11870)
Add: List_[scenario|heightmap] and load_[scenario|height] console commands (#11867)
Add: Latvian Lats currency (#11691)
Add: Horizontal scroll for script debug log (#11597)
Add: GUI options to select sprite font and AA mode for all fonts (#11593)
Add: Website button for basesets in Game Options window, the Game Script settings window and AI settings window (#11512)
Add: [Emscripten] Support for bootstrapping (#11109)
Add: Hotkey to focus town / industry directory filter box (#11030)
Add: Maximum number of companies allowed to the client list (#10523)
Add: Use specific error message when vehicle cannot go to station/waypoint (#10494)
Add: Show NewGRF name in NewGRF-created errors (#10457)
Add: Alternative setting for right-click close window option to exclude pinned windows (#10204)
Add: Allow autoreplace with same model vehicle (#7729)
Add: [NewGRF] Allow inspection of road tiles and airports (#11282, #11323)
Add: [NewGRF] Station variable 6B to get extended station id of nearby tiles (#10953)
Add: [NewGRF] String code "9A 21" to display force from textstack (#10782)
Add: [NewGRF] Station property 1C/1D to set name/classname (#10672)
Add: [Script] Optional filter parameter to ScriptXXXList constructors (#11698,#11663)
Add: [Script] AI/GS Time Mode to choose between economy (default) and calendar time (#11603)
Add: [Script] Allow to set max loan for each company separately (#11224)
Add: [Script] GSIndustry.GetConstructionDate() method (#11145)
Add: [Script] Game script control of industry production level and news messages (#11141)
Add: [Script] GSAsyncMode to set async mode of gamescript commands (#10913)
Add: [Script] GSCompanyMode::IsValid and IsDeity, and enforce valid company/deity mode where applicable (#10536, #10529)
Add: [Script] Allow GS to found town with random road layout (#10442)
Add: [Script] Create own Randomizer per instance (#10349)
Change: Better handle different GUI sizes for most windows, and squash inconsistencies between windows
Change: Allow configuring AI slots above the current maximum number of competitors (#11961)
Change: Forcefully enable prefixing logs with date (#11930)
Change: Position error window closer to cursor on large screens (#11923)
Change: Only open story-book in center when a GS does it (#11916)
Change: Rebrand Cheats as Sandbox Options (#11874)
Change: Make smooth-scrolling based on actual time (#11865)
Change: Set smooth-scrolling on by default (#11860)
Change: Disable building rail infrastructure if train build limit is zero (#11847)
Change: Invalidate music volume when restarting music playback on Windows (#11836)
Change: Make street lights transparent with houses (#11828)
Change: Redesign script debug window (#11782)
Change: Reorganize Settings menu items (#11683)
Change: Set amount of smoke/sparks to "realistic" by default (#11624)
Change: Show a message in livery window if vehicle type has no groups (#11617)
Change: Add distinct tooltips for vehicle group colour schemes (#11617)
Change: Move colour selection dropdowns to bottom of window (#11617)
Change: Support custom transparency remaps with 32bpp blitters (#11616)
Change: Make "middle" the default stopping location for trains in platforms (#11605)
Change: Scale sprites to requested highest resolution level (#11600)
Change: Allow opening multiple script debug windows by holding Ctrl (#11592)
Change: Don't show scoring year in high score table (#11546)
Change: Revert pressed-button content shifting introduced in r2161 (#11542)
Change: Show rating in station list even with no cargo waiting (#11540)
Change: Hide unused cargos from vehicle cargo filter (#11533)
Change: Don't restart playback when toggling playlist shuffle (#11504)
Change: Increase finance window lines (and underlines) with interface scale (#11459)
Change: Move baseset missing/corrupted files label to list item (#11455)
Change: Add horizontal scrollbar to Industry Directory window (#11434)
Change: Improve layout of airport, dock, object, road/tram stop, train station pickers (#11430)
Change: Display cargo lists in sorted cargo order (#11383)
Change: Link houses production on industry chain graph by TPE_PASSENGERS or TPE_MAIL cargo (#11378)
Change: Passenger subsidies are generated for any TPE_PASSENGER cargo type (#11378)
Change: Towns generate cargo based on town production effect (#11378)
Change: Always allow expanding towns in Scenario Editor to build new roads (#11377)
Change: Don't set vehicle on time if timetable not started (#11359)
Change: Store station blocked/wires/pylons flags in map (#11337)
Change: Recover when possible from crashes during a crash (#11238)
Change: Store crash logs in JSON format (#11232)
Change: Remove autosave from settings window; it is already in the Game Options (#11218)
Change: Enable "Forbid 90 degree turns" setting by default (#11160)
Change: Do not allow mixing road/tram types in powered road type list (#11148)
Change: Only show platform stopping location in orders when other than default (#11102)
Change: Autorail / autoroad tools can start dragging from invalid tiles (#11089)
Change: Only allow buying Exclusive Transport Rights when no one has them (#11076)
Change: Remove currency code/symbol suffix from language files (#11061)
Change: Add separate setting for server sent commands per frame limit (#11023)
Change: Cargo flow legend only shows defined cargo (#10872)
Change: Use "Via-Destination-Source" as default station cargodist display (#10851)
Change: Preserve orders and related settings where possible when moving engines around in a train (#10799)
Change: Standardise unit conversions and allow decimal places (#10795)
Change: Use separate names for default stations/roadstops (#10786)
Change: [MacOS] Require at least 10.15 to run the game (#10745)
Change: Hide all variants from UI when (display) parent is hidden (#10708)
Change: Split Game options into General, Graphics and Sound tabs (#10674)
Change: Extend entity override manager and station spec lists to support 16 bit IDs (#10672)
Change: Base autosaves intervals on real time (instead of game time) (#10655)
Change: Allow overbuilding station and waypoint tiles (#10618)
Change: Use realtime for Linkgraph update settings (#10610)
Change: Make tick length 27 milliseconds (#10607)
Change: Increase max cargo age and let min cargo payment approach zero (#10596)
Change: Show buy company dialog window even when playing in the AI company (#10459)
Change: Use HTTPS for content-service connections (#10448)
Change: Big UFO disaster targets current location of a random train (#10290)
Change: Remove land generator setting from World Generation GUI (#10093)
Change: Build signals to the next junction when dragging regardless of the Ctrl state (#9637)
Change: Allow dedicated server to use threaded saves (#10787)
Change: [NewGRF] Increase vehicle random data from 8 to 16 bits (#10701)
Change: [NewGRF] Read Action 3 IDs as extended-bytes for all features (#10672)
Change: [NewGRF] Make Action 3 debug messages more consistent (#10672)
Change: [NewGRF] Extend callback 161 (engine name) with bit 0x22 for context 'Autoreplace - Vehicles in use' (#10666)
Change: [Script] Replace easy/medium/hard values with default value (#11959)
Change: [Script] Limit total script ops that can be consumed by a list valuate (#11670)
Change: [Script] Allow GS access to ScriptGroup, ScriptGameSettings.IsDisabledVehicleType, more ScriptCompany and more ScriptOrder functions (#10642)
Change: [Script] Improve ScriptText validation error messages (#10545)
Change: [Script] Restore support of {RAW_STRING} in ScriptText (#10492)
Change: [Script] Validate ScriptText parameters type and amount (#10492)
Change: [Script] Automate the ScriptObject reference counting (#10492)
Change: [Script] Extract params info from GS strings (#10492)
Change: [Script] A ScriptText with too many parameters is now a fatal error (#10483)
Change: [Script] Log AI/GS Squirrel crashes in white text for readability (#10375)
Fix #11918: Houses should only build next to road stops, not any station type (#11919)
Fix #11827: Make text layouter aware of ligatures (#11831)
Fix #11752: Characters could be repeated when wrapping multi-line text (#11761)
Fix #11748: Decreasing service interval value sufficiently would result in it wrapping around (#11749)
Fix #11629: Crash when getting the nearest town for rotated airports (#11631)
Fix #11516: Adjust window size by interface scale during ReInit (#11517)
Fix #11515: Changing interface scale could have unintended effects on zoom level (#11615)
Fix #11442: "Default" colour in group colour window is not updated when changing master colour (#11614)
Fix #11437: Flipped shorter rail vehicles disappear in windows (#11446)
Fix #11413: Incorrect sorting by industry production (#11414)
Fix #11407: Don't steal focus from dropdown menus (#11484)
Fix #11402: Make string filter locale-aware (#11426)
Fix #11329: Don't assert vehicle list length is non-zero when only asked to set string parameter (#11330)
Fix #11315: Sort industries and cargoes by name in industry chain window (#11317)
Fix #11307: Incorrect GroupStatistics after selling leading wagon (#11311)
Fix #11261: Airport menu selectability after closing window on a class with no available airports (#11344)
Fix #11230: Sort by button in group list window could be misaligned (#11231)
Fix #11215: Assert in NewGRF parameters window (manual parameter mode) (#11217)
Fix #11203: [Linux] Crash when editing CJK characters in edit box (#11204)
Fix #11180: Aircraft crashes could point to the wrong tile (#11184)
Fix #11164: Don't create duplicate town names when using 'Many random towns' in the scenario editor (#11165)
Fix #11162: Second company colour was not consistently applied to articulated vehicles (#11163)
Fix #11115: Focus the abandon game/exit game windows (#11125)
Fix #11096: Increase priority of error and confirmation windows (#11104)
Fix #11087: Disable base graphics/sound dropdown outside main menu (#11091)
Fix #11054: Prevent translation of currency codes (#11061)
Fix #11026: Use real engine name instead of default name for filtering (#11033)
Fix #10982: No help text for gamelog command (#10984)
Fix #10880: Crash in object window due to incorrect parameter order (#10881)
Fix #10868: Crash when Script tries to load large savegame data (#11029)
Fix #10811: Allow dragging vehicle in depot to any free row (#11508)
Fix #10660: Sprite Font scale affected by viewport zoom level limits (#10668)
Fix #10619: Crash loading linkgraph for older savegames (#10620)
Fix #10600: 'Replace Vehicles' didn't show numbers >999 (#10680)
Fix #10578: Allow to select any version of AI/GS from GUI (#10604)
Fix #10522: Link graph tooltip vertical lines were not handled correctly (#10524)
Fix #10511: Don't search for depot every tick if one cannot be found (#11548)
Fix #10478: Clarify airport noise control setting texts (#11169)
Fix #10452: Prevent long stalls during river generation (#11544)
Fix #10430: Display chain window causing assert (#10431)
Fix #10343: Don't extend town-disallowed roadtypes (#10347)
Fix #10251: [MacOS] Screen looks blue-ish when using newer SDKs (#11207)
Fix #10222: Adjust line drawing algorithm (#10491)
Fix #10131: Actually cancel downloads when pressing cancel (#10485)
Fix #10118: Cycle through current signal group, not just path signals (#11798)
Fix #10439: [Script] Validate story page button colour, flags, cursor and vehicle type (#11892)
Fix #10438: [Script] Validate story page element type for ScriptStoryPage::NewElement (#11888)
Fix #9865: Removing files with the console always failed
Fix #9810: Rebuilding a through road stop costs money (#9852)
Fix #9722: Crash when pressing hotkeys early in world generation (#11858)
Fix #9697: Limit the default width of the Online Players window (#11936)
Fix #9642: Keep infrastructure totals when overbuilding road depots (#11229)
Fix #9545: Crash when all cargo types are disabled (#11432)
Fix #8846: When upgrading NewGRF presets, copy NewGRF parameters only if the NewGRF are compatible (#11348)
Fix #8253: Improve profit graph when having lots of money (#11915)
Fix #6377: Two tarballs with the same folder in them were considered as one (#11855)
Fix #5713: Ships could be sent to unreachable depots (#11768)
Fix #4575: Use Latin 'l' in English translation of zloty (#11090)
Fix #4415: Land info build date is also renovation date (#11759)
Fix: Display rank correctly with more than 15 companies in a league table (#11940)
Fix: Extra refit button when train/RV is in a depot (#11904)
Fix: Update server listing as offline when unexpected disconnect during refresh (#11891)
Fix: Horizontal scale of framerate window switched excessively (#11813)
Fix: [Linux] Various issues with resolutions and fullscreen in multi-display setups (#11778, #11779)
Fix: Build button text when train purchase window using "Engines" filter (#11755)
Fix: One-way state remained after removing road from road and tram tile (#11745)
Fix: Draw video driver info at the correct size and text wrap (#10716)
Fix: Language genders could not be applied to SCC_INDUSTRY_NAME (#11697)
Fix: Spurious cancellations of HTTP content downloads (#11668)
Fix: Calculation of initial engine age was inaccurate (#11660)
Fix: Prevent underflow if engine base life is less than 8 years (#11635)
Fix: Changing default livery did not propagate to group liveries (#11633)
Fix: Window width/height was doubly-scaled with automatic DPI switch (#11598)
Fix: Don't crash when saving a crashlog save with no main window open (#11586)
Fix: Prevent overflow when calculating max town noise (#11564)
Fix: Deleting towns did not check for waypoints referencing the town (#11513)
Fix: Invalidate playlist window when (un)shuffling playlist (#11504)
Fix: Restore original cargo legend 'blob' dimensions (#11480)
Fix: Extmidi did not move on to next song after playing ends (#11469)
Fix: Server password length in the UI was unnecessarily limited (#11408)
Fix: OpenTTD can fail to exit on an error due to mutex locks in threads (#11398)
Fix: Scale minimum width for server name by interface scale (#11381)
Fix: Server connection was not closed when relay window was closed (#11366)
Fix: Upgrading NewGRF presets could result in incomplete display of NewGRF parameters until restart (#11348)
Fix: Check for engine variant loops during NewGRF initialization (#11343)
Fix: Don't allow industries to produce invalid cargo (#11314)
Fix: Also apply cargo filters on shared groups in vehicle listing (#11294)
Fix: Only count distance traveled in vehicles for cargo payment (#11283)
Fix: Base cargo payment on load/unload tile, instead of station sign location (#11281)
Fix: Crash when opening a damaged base-graphics (#11275)
Fix: Trivial autoreplace of mixed cargo articulated engines (#11253)
Fix: [Emscripten] Config not saved on exit (#11248)
Fix: Inaccurate waiting cargo total in station window when using cargodist (#11213)
Fix: No fast forward in network was ensured only from GUI side (#11206)
Fix: Crash when not passing command-line parameter for -n (#11153)
Fix: [Bootstrap] Don't crash when failing to connect to content server (#11122)
Fix: Crash when failing to load a game into a dedicated server at startup (#11021)
Fix: Don't allow changing settings over the network that are marked as local settings (#11009)
Fix: Move no_http_content_downloads and use_relay_service to private settings (#10762)
Fix: Extra viewport could not be scrolled with right-click-close (#10644)
Fix: Specify units for value of share trading age setting (#10612)
Fix: Road type is not available before its introduction date (#10585)
Fix: Do not update a RV's Z-position when stationary while turning (#10570)
Fix: Don't (briefly) switch from title-only playlist on menu screen (#10553)
Fix: Reset content download progress to zero if falling back to TCP (#10485)
Fix: Make script goals work with the whole range of ClientIDs (#10435)
Fix: [NewGRF] Tile slope missing from road stops varact2 variable 0x42 (#11373)
Fix: [NewGRF] House class mappings were not reset between games (#11279)
Fix: [NewGRF] Profile didn't stop if there were no events yet (#10816)
Fix: [NewGRF] Support more than 256 stations/waypoints/roadstops per class (#10793)
Fix: [NewGRF] Var68 for station and roadstop was broken (#10784)
Fix: [NewGRF] Object and road stop ignore property handlers (#10525)
Fix: [Script] Apply random deviation to settings only at script start (#11944)
Fix: [Script] Improve ScriptText validation (#11721)
Fix: [Script] GSAdmin.Send() could generate invalid JSON (#11250)
Fix: [Script] Crash if squirrel compatibility scripts cannot be parsed (#11589)
Fix: [Script] Don't list unavailable road types for game scripts (#10585)
Fix: [Script] Game scripts were able to build with non-existing road types (#10539)
Fix: [Script] Inconsistent precondition failure return values (#10533)
Fix: [Script] Crash when companies disappear (#10529)
Fix: [Script] ScriptBase::Rand() return value could return negative values (#10443)
Fix: [Script] Incorrect value for GOAL_INVALID (#10436)
Fix: [Script] Extend Script::IsValidVehicle to check for primary vehicles (#10386)
Remove: "generation_seed" from config, as it was a write-only value (#11927)
Remove: Debug redirect over network (#11776)
Remove: Officially mark Vista as no longer supported (#11531)
Remove: OS/2 and SunOS ports (#11018, #11210)
Remove: Obsolete NewGRF text unprinting (#10884)
Remove: [Script] CONFIG_RANDOM from AddSetting flags (#11942)
13.4 (2023-07-29)
------------------------------------------------------------------------
Fix: Setting tree lines drawn incorrectly for RTL languages (#11070)

@ -56,24 +56,26 @@ typedef sqvector<ExpState> ExpStateVec;
class SQCompiler
{
public:
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _token(0), _fs(nullptr), _lex(_ss(v), rg, up, ThrowError, this), _debugline(0), _debugop(0)
SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _token(0), _fs(nullptr), _lex(_ss(v), rg, up), _debugline(0), _debugop(0)
{
_vm=v;
_sourcename = SQString::Create(_ss(v), sourcename);
_lineinfo = lineinfo;_raiseerror = raiseerror;
}
NORETURN static void ThrowError(void *ud, const SQChar *s) {
SQCompiler *c = (SQCompiler *)ud;
c->Error("%s", s);
}
NORETURN void Error(const SQChar *s, ...) WARN_FORMAT(2, 3)
[[noreturn]] void Error(const SQChar *s, ...) WARN_FORMAT(2, 3)
{
static SQChar temp[256];
va_list vl;
va_start(vl, s);
vseprintf(temp, lastof(temp), s, vl);
va_end(vl);
throw temp;
throw CompileException(temp);
}
[[noreturn]] void Error(const std::string &msg)
{
throw CompileException(msg);
}
void Lex(){ _token = _lex.Lex();}
void PushExpState(){ _expstates.push_back(ExpState()); }
@ -163,7 +165,7 @@ public:
_debugline = 1;
_debugop = 0;
SQFuncState funcstate(_ss(_vm), nullptr,ThrowError,this);
SQFuncState funcstate(_ss(_vm), nullptr);
funcstate._name = SQString::Create(_ss(_vm), "main");
_fs = &funcstate;
_fs->AddParameter(_fs->CreateString("this"));
@ -185,20 +187,12 @@ public:
#endif
return true;
}
catch (SQChar *compilererror) {
if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
_ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):"unknown",
_lex._currentline, _lex._currentcolumn);
}
_vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1);
return false;
}
catch (const std::string &compilererror) {
catch (const CompileException &compilererror) {
if(_raiseerror && _ss(_vm)->_compilererrorhandler) {
_ss(_vm)->_compilererrorhandler(_vm, compilererror.c_str(), type(_sourcename) == OT_STRING ? _stringval(_sourcename) : "unknown",
_ss(_vm)->_compilererrorhandler(_vm, compilererror.what(), type(_sourcename) == OT_STRING ? _stringval(_sourcename) : "unknown",
_lex._currentline, _lex._currentcolumn);
}
_vm->_lasterror = SQString::Create(_ss(_vm), compilererror);
_vm->_lasterror = SQString::Create(_ss(_vm), compilererror.what());
return false;
}
}

@ -71,12 +71,7 @@ struct SQVM;
#define TK_ENUM 323
#define TK_CONST 324
/* MSVC doesn't like NORETURN for function prototypes, but we kinda need it for GCC. */
#if defined(_MSC_VER) && !defined(__clang__)
typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s);
#else
typedef NORETURN void(*CompilerErrorFunc)(void *ud, const SQChar *s);
#endif
using CompileException = std::runtime_error;
bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo);
#endif //_SQCOMPILER_H_

@ -92,7 +92,7 @@ void DumpLiteral(SQObjectPtr &o)
}
#endif
SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed)
SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent)
{
_nliterals = 0;
_literals = SQTable::Create(ss,0);
@ -105,15 +105,13 @@ SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc
_traps = 0;
_returnexp = 0;
_varparams = false;
_errfunc = efunc;
_errtarget = ed;
_bgenerator = false;
}
void SQFuncState::Error(const SQChar *err)
{
_errfunc(_errtarget,err);
throw CompileException(err);
}
#ifdef _DEBUG_DUMP
@ -549,7 +547,7 @@ SQFunctionProto *SQFuncState::BuildProto()
SQFuncState *SQFuncState::PushChildState(SQSharedState *ss)
{
SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState));
new (child) SQFuncState(ss,this,_errfunc,_errtarget);
new (child) SQFuncState(ss,this);
_childstates.push_back(child);
return child;
}

@ -6,12 +6,12 @@
struct SQFuncState
{
SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed);
SQFuncState(SQSharedState *ss,SQFuncState *parent);
~SQFuncState();
#ifdef _DEBUG_DUMP
void Dump(SQFunctionProto *func);
#endif
void Error(const SQChar *err);
[[noreturn]] void Error(const SQChar *err);
SQFuncState *PushChildState(SQSharedState *ss);
void PopChildState();
void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);}
@ -75,9 +75,6 @@ struct SQFuncState
SQSharedState *_sharedstate;
sqvector<SQFuncState*> _childstates;
SQInteger GetConstant(const SQObject &cons);
private:
CompilerErrorFunc _errfunc;
void *_errtarget;
};

@ -35,10 +35,8 @@ void SQLexer::APPEND_CHAR(char32_t c)
}
}
SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed)
SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up)
{
_errfunc = efunc;
_errtarget = ed;
_sharedstate = ss;
_keywords = SQTable::Create(ss, 26);
ADD_KEYWORD(while, TK_WHILE);
@ -94,9 +92,9 @@ SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerE
Next();
}
NORETURN void SQLexer::Error(const SQChar *err)
[[noreturn]] void SQLexer::Error(const SQChar *err)
{
_errfunc(_errtarget,err);
throw CompileException(err);
}
void SQLexer::Next()

@ -5,8 +5,8 @@
struct SQLexer
{
~SQLexer();
SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed);
NORETURN void Error(const SQChar *err);
SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up);
[[noreturn]] void Error(const SQChar *err);
SQInteger Lex();
const SQChar *Tok2Str(SQInteger tok);
private:
@ -35,8 +35,6 @@ public:
char32_t _currdata;
SQSharedState *_sharedstate;
sqvector<SQChar> _longstr;
CompilerErrorFunc _errfunc;
void *_errtarget;
};
#endif

@ -216,7 +216,7 @@ bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result)
_RET_SUCCEED(_integer(res))
}
}
FALLTHROUGH;
[[fallthrough]];
default:
_RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 );
}
@ -288,7 +288,7 @@ void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
//else keeps going to the default
}
}
FALLTHROUGH;
[[fallthrough]];
default:
seprintf(buf, lastof(buf),"(%s : 0x%p)",GetTypeName(o),(void*)_rawval(o));
}
@ -540,7 +540,7 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
_generator(o1)->Resume(this, arg_2+1);
_FINISH(0);
}
FALLTHROUGH;
[[fallthrough]];
default:
Raise_Error("cannot iterate %s", GetTypeName(o1));
}
@ -775,7 +775,7 @@ exception_restore:
ct_stackbase = _stackbase;
goto common_call;
}
FALLTHROUGH;
[[fallthrough]];
case _OP_CALL: {
ct_tailcall = false;
ct_target = arg0;
@ -1337,7 +1337,7 @@ bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr
return true;
}
}
FALLTHROUGH;
[[fallthrough]];
case OT_USERDATA:
if(_delegable(self)->_delegate) {
SQObjectPtr t;

@ -148,20 +148,14 @@ struct AIConfigWindow : public Window {
/**
* Can the AI config in the given company slot be edited?
* @param slot The slot to query.
* @return True if and only if the given AI Config slot can e edited.
* @return True if and only if the given AI Config slot can be edited.
*/
static bool IsEditable(CompanyID slot)
{
if (_game_mode != GM_NORMAL) {
return slot > 0 && slot <= GetGameSettings().difficulty.max_no_competitors;
return slot > 0 && slot < MAX_COMPANIES;
}
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++) {
if (Company::IsValidHumanID(cid)) max_slot++;
}
return slot < max_slot;
return slot < MAX_COMPANIES && !Company::IsValidID(slot);
}
void DrawWidget(const Rect &r, WidgetID widget) const override
@ -185,7 +179,14 @@ struct AIConfigWindow : public Window {
if (this->selected_slot == i) {
tc = TC_WHITE;
} else if (IsEditable((CompanyID)i)) {
tc = TC_ORANGE;
int max_slot = GetGameSettings().difficulty.max_no_competitors;
for (const Company *c : Company::Iterate()) {
if (c->is_ai) max_slot--;
}
for (CompanyID cid = COMPANY_FIRST; cid < (CompanyID)max_slot && cid < MAX_COMPANIES; cid++) {
if (Company::IsValidHumanID(cid)) max_slot++;
}
if (i < max_slot) tc = TC_ORANGE;
} else if (Company::IsValidAiID(i)) {
tc = TC_GREEN;
}

@ -73,7 +73,7 @@ struct AircraftCache {
/**
* Aircraft, helicopters, rotors and their shadows belong to this class.
*/
struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
struct Aircraft final : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
uint16_t crashed_counter; ///< Timer for handling crash animations.
byte pos; ///< Next desired position of the aircraft.
byte previous_pos; ///< Previous desired position of the aircraft.

@ -1576,6 +1576,7 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir)
}
VehicleServiceInDepot(v);
v->LeaveUnbunchingDepot();
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
DirtyVehicleListWindowForVehicle(v);
@ -1627,6 +1628,9 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
return;
}
/* Check if we should wait here for unbunching. */
if (v->IsWaitingForUnbunching()) return;
if (!v->current_order.IsType(OT_GOTO_STATION) &&
!v->current_order.IsType(OT_GOTO_DEPOT))
return;

@ -581,6 +581,7 @@ CommandCost CopyHeadSpecificThings(Vehicle *old_head, Vehicle *new_head, DoComma
if (cost.Succeeded() && old_head != new_head && (flags & DC_EXEC) != 0) {
/* Copy other things which cannot be copied by a command and which shall not stay resetted from the build vehicle command */
new_head->CopyVehicleConfigAndStatistics(old_head);
new_head->unbunch_state = std::move(old_head->unbunch_state);
GroupStatistics::AddProfitLastYear(new_head);
/* Switch vehicle windows/news to the new vehicle, so they are not closed/deleted when the old vehicle is sold */

@ -32,7 +32,7 @@
#define MARGIN_NORMAL_THRESHOLD 4
/** The SSE4 32 bpp blitter with palette animation. */
class Blitter_32bppSSE4_Anim FINAL : public Blitter_32bppSSE2_Anim, public Blitter_32bppSSE4 {
class Blitter_32bppSSE4_Anim final : public Blitter_32bppSSE2_Anim, public Blitter_32bppSSE4 {
private:
public:

@ -14,7 +14,7 @@
#include "factory.hpp"
/** 8bpp blitter optimised for speed. */
class Blitter_8bppOptimized FINAL : public Blitter_8bppBase {
class Blitter_8bppOptimized final : public Blitter_8bppBase {
public:
/** Data stored about a (single) sprite. */
struct SpriteData {

@ -14,7 +14,7 @@
#include "factory.hpp"
/** Most trivial 8bpp blitter. */
class Blitter_8bppSimple FINAL : public Blitter_8bppBase {
class Blitter_8bppSimple final : public Blitter_8bppBase {
public:
using Blitter_8bppBase::Blitter_8bppBase;
void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override;

@ -23,6 +23,7 @@
#include "safeguards.h"
CargoSpec CargoSpec::array[NUM_CARGO];
std::array<std::vector<const CargoSpec *>, NUM_TPE> CargoSpec::town_production_cargoes{};
/**
* Bitmask of cargo types available. This includes phony cargoes like regearing cargoes.
@ -193,6 +194,7 @@ static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * c
/** Initialize the list of sorted cargo specifications. */
void InitializeSortedCargoSpecs()
{
for (auto &tpc : CargoSpec::town_production_cargoes) tpc.clear();
_sorted_cargo_specs.clear();
/* Add each cargo spec to the list, and determine the largest cargo icon size. */
for (const CargoSpec *cargo : CargoSpec::Iterate()) {
@ -211,6 +213,8 @@ void InitializeSortedCargoSpecs()
_standard_cargo_mask = 0;
uint8_t nb_standard_cargo = 0;
for (const auto &cargo : _sorted_cargo_specs) {
assert(cargo->town_production_effect != INVALID_TPE);
CargoSpec::town_production_cargoes[cargo->town_production_effect].push_back(cargo);
if (cargo->classes & CC_SPECIAL) break;
nb_standard_cargo++;
SetBit(_standard_cargo_mask, cargo->Index());

@ -22,16 +22,30 @@
typedef uint32_t CargoLabel;
/** Town growth effect when delivering cargo. */
enum TownEffect {
TE_BEGIN = 0,
TE_NONE = TE_BEGIN, ///< Cargo has no effect.
TE_PASSENGERS, ///< Cargo behaves passenger-like.
TE_MAIL, ///< Cargo behaves mail-like.
TE_GOODS, ///< Cargo behaves goods/candy-like.
TE_WATER, ///< Cargo behaves water-like.
TE_FOOD, ///< Cargo behaves food/fizzy-drinks-like.
TE_END, ///< End of town effects.
NUM_TE = TE_END, ///< Amount of town effects.
enum TownAcceptanceEffect : byte {
TAE_BEGIN = 0,
TAE_NONE = TAE_BEGIN, ///< Cargo has no effect.
TAE_PASSENGERS, ///< Cargo behaves passenger-like.
TAE_MAIL, ///< Cargo behaves mail-like.
TAE_GOODS, ///< Cargo behaves goods/candy-like.
TAE_WATER, ///< Cargo behaves water-like.
TAE_FOOD, ///< Cargo behaves food/fizzy-drinks-like.
TAE_END, ///< End of town effects.
NUM_TAE = TAE_END, ///< Amount of town effects.
};
/** Town effect when producing cargo. */
enum TownProductionEffect : byte {
TPE_NONE, ///< Town will not produce this cargo type.
TPE_PASSENGERS, ///< Cargo behaves passenger-like for production.
TPE_MAIL, ///< Cargo behaves mail-like for production.
NUM_TPE,
/**
* Invalid town production effect. Used as a sentinel to indicate if a NewGRF has explicitly set an effect.
* This does not 'exist' after cargo types are finalised.
*/
INVALID_TPE,
};
/** Cargo classes. */
@ -52,6 +66,8 @@ enum CargoClass {
static const byte INVALID_CARGO_BITNUM = 0xFF; ///< Constant representing invalid cargo
static const uint TOWN_PRODUCTION_DIVISOR = 256;
/** Specification of a cargo type. */
struct CargoSpec {
CargoLabel label; ///< Unique label of the cargo type.
@ -65,7 +81,9 @@ struct CargoSpec {
uint8_t transit_periods[2];
bool is_freight; ///< Cargo type is considered to be freight (affects train freight multiplier).
TownEffect town_effect; ///< The effect that delivering this cargo type has on towns. Also affects destination of subsidies.
TownAcceptanceEffect town_acceptance_effect; ///< The effect that delivering this cargo type has on towns. Also affects destination of subsidies.
TownProductionEffect town_production_effect{INVALID_TPE}; ///< The effect on town cargo production.
uint16_t town_production_multiplier{TOWN_PRODUCTION_DIVISOR}; ///< Town production multipler, if commanded by TownProductionEffect.
uint8_t callback_mask; ///< Bitmask of cargo callbacks that have to be called
StringID name; ///< Name of this type of cargo.
@ -181,6 +199,9 @@ struct CargoSpec {
*/
static IterateWrapper Iterate(size_t from = 0) { return IterateWrapper(from); }
/** List of cargo specs for each Town Product Effect. */
static std::array<std::vector<const CargoSpec *>, NUM_TPE> town_production_cargoes;
private:
static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs

@ -398,7 +398,7 @@ struct CompanyFinancesWindow : Window {
case WID_CF_EXPS_PRICE2:
case WID_CF_EXPS_PRICE3:
size->height = GetTotalCategoriesHeight();
FALLTHROUGH;
[[fallthrough]];
case WID_CF_BALANCE_VALUE:
case WID_CF_LOAN_VALUE:
@ -840,7 +840,7 @@ public:
size->width = 0;
break;
}
FALLTHROUGH;
[[fallthrough]];
case WID_SCL_PRI_COL_DROPDOWN: {
this->square = GetSpriteSize(SPR_SQUARE);
@ -1670,7 +1670,7 @@ public:
/* OK button */
case WID_SCMF_ACCEPT:
DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
FALLTHROUGH;
[[fallthrough]];
/* Cancel button */
case WID_SCMF_CANCEL:

@ -394,7 +394,7 @@ void IConsoleCmdExec(const std::string &command_string, const uint recurse_count
tokenstream[tstream_i++] = *++cmdptr;
break;
}
FALLTHROUGH;
[[fallthrough]];
default: // Normal character
tokenstream[tstream_i++] = *cmdptr;

@ -1358,33 +1358,39 @@ DEF_CONSOLE_CMD(ConNewGame)
DEF_CONSOLE_CMD(ConRestart)
{
if (argc == 0) {
IConsoleHelp("Restart game. Usage: 'restart'");
IConsoleHelp("Restarts a game. It tries to reproduce the exact same map as the game started with.");
IConsoleHelp("However:");
IConsoleHelp(" * restarting games started in another version might create another map due to difference in map generation");
IConsoleHelp(" * restarting games based on scenarios, loaded games or heightmaps will start a new game based on the settings stored in the scenario/savegame");
if (argc == 0 || argc > 2) {
IConsoleHelp("Restart game. Usage: 'restart [current|newgame]'.");
IConsoleHelp("Restarts a game, using either the current or newgame (default) settings.");
IConsoleHelp(" * if you started from a new game, and your current/newgame settings haven't changed, the game will be identical to when you started it.");
IConsoleHelp(" * if you started from a savegame / scenario / heightmap, the game might be different, because the current/newgame settings might differ.");
return true;
}
/* Don't copy the _newgame pointers to the real pointers, so call SwitchToMode directly */
_settings_game.game_creation.map_x = MapLogX();
_settings_game.game_creation.map_y = MapLogY();
_switch_mode = SM_RESTARTGAME;
if (argc == 1 || std::string_view(argv[1]) == "newgame") {
StartNewGameWithoutGUI(_settings_game.game_creation.generation_seed);
} else {
_settings_game.game_creation.map_x = MapLogX();
_settings_game.game_creation.map_y = MapLogY();
_switch_mode = SM_RESTARTGAME;
}
return true;
}
DEF_CONSOLE_CMD(ConReload)
{
if (argc == 0) {
IConsoleHelp("Reload game. Usage: 'reload'");
IConsoleHelp("Reloads a game.");
IConsoleHelp(" * if you started from a savegame / scenario / heightmap, that exact same savegame / scenario / heightmap will be loaded.");
IConsoleHelp(" * if you started from a new game, this acts the same as 'restart'.");
IConsoleHelp("Reload game. Usage: 'reload'.");
IConsoleHelp("Reloads a game if loaded via savegame / scenario / heightmap.");
return true;
}
if (_file_to_saveload.abstract_ftype == FT_NONE || _file_to_saveload.abstract_ftype == FT_INVALID) {
IConsolePrint(CC_ERROR, "No game loaded to reload.");
return true;
}
/* Don't copy the _newgame pointers to the real pointers, so call SwitchToMode directly */
/* Use a switch-mode to prevent copying over newgame settings to active settings. */
_settings_game.game_creation.map_x = MapLogX();
_settings_game.game_creation.map_y = MapLogY();
_switch_mode = SM_RELOADGAME;

@ -15,7 +15,7 @@
* Function to exit with an error message after malloc() or calloc() have failed
* @param size number of bytes we tried to allocate
*/
void NORETURN MallocError(size_t size)
[[noreturn]] void MallocError(size_t size)
{
error("Out of memory. Cannot allocate " PRINTF_SIZE " bytes", size);
}
@ -24,7 +24,7 @@ void NORETURN MallocError(size_t size)
* Function to exit with an error message after realloc() have failed
* @param size number of bytes we tried to allocate
*/
void NORETURN ReallocError(size_t size)
[[noreturn]] void ReallocError(size_t size)
{
error("Out of memory. Cannot reallocate " PRINTF_SIZE " bytes", size);
}

@ -17,8 +17,8 @@
* binary needlessly large.
*/
void NORETURN MallocError(size_t size);
void NORETURN ReallocError(size_t size);
[[noreturn]] void MallocError(size_t size);
[[noreturn]] void ReallocError(size_t size);
/**
* Checks whether allocating memory would overflow size_t.

@ -166,7 +166,7 @@ DEFINE_POOL_METHOD(void *)::GetNew(size_t size)
*/
DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index)
{
extern void NORETURN SlErrorCorruptFmt(const char *format, ...);
[[noreturn]] extern void SlErrorCorruptFmt(const char *format, ...);
if (index >= Tmax_size) {
SlErrorCorruptFmt("%s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size);

@ -385,4 +385,7 @@ static const int INDUSTRY_CUT_TREE_TICKS = INDUSTRY_PRODUCE_TICKS * 2; ///< cyc
/** An initial value for StateTicks when starting a new game */
static constexpr StateTicks INITIAL_STATE_TICKS_VALUE = 1 << 24;
/** Invalid state ticks value */
static constexpr StateTicks INVALID_STATE_TICKS = INT64_MIN;
#endif /* DATE_TYPE_H */

@ -23,8 +23,8 @@
*/
#define Debug(name, level, format_string, ...) do { if ((level) == 0 || _debug_ ## name ## _level >= (level)) debug_print(#name, level, fmt::format(FMT_STRING(format_string), ## __VA_ARGS__).c_str()); } while (false)
void NORETURN usererror_str(const char *msg);
void NORETURN fatalerror_str(const char *msg);
[[noreturn]] void usererror_str(const char *msg);
[[noreturn]] void fatalerror_str(const char *msg);
#define UserError(format_string, ...) usererror_str(fmt::format(FMT_STRING(format_string), ## __VA_ARGS__).c_str())
#define FatalError(format_string, ...) fatalerror_str(fmt::format(FMT_STRING(format_string), ## __VA_ARGS__).c_str())

@ -499,7 +499,7 @@ struct DepotWindow : Window {
switch (this->type) {
case VEH_TRAIN:
if (wagon) return MODE_ERROR;
FALLTHROUGH;
[[fallthrough]];
case VEH_ROAD:
if (xm <= this->flag_size.width) return MODE_START_STOP;

@ -34,7 +34,7 @@ enum DisasterSubType {
/**
* Disasters, like submarines, skyrangers and their shadows, belong to this class.
*/
struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
struct DisasterVehicle final : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
SpriteID image_override; ///< Override for the default disaster vehicle sprite.
VehicleID big_ufo_destroyer_target; ///< The big UFO that this destroyer is supposed to bomb.
byte flags; ///< Flags about the state of the vehicle, @see AirVehicleFlags

@ -1368,7 +1368,7 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, ui
/* Increase town's counter for town effects */
const CargoSpec *cs = CargoSpec::Get(cargo_type);
st->town->received[cs->town_effect].new_act += accepted_total;
st->town->received[cs->town_acceptance_effect].new_act += accepted_total;
/* Determine profit */
Money profit = GetTransportedGoodsIncome(accepted_total, distance, periods_in_transit, cargo_type);

@ -21,7 +21,7 @@
* - bulldozer (road works)
* - bubbles (industry)
*/
struct EffectVehicle FINAL : public SpecializedVehicle<EffectVehicle, VEH_EFFECT> {
struct EffectVehicle final : public SpecializedVehicle<EffectVehicle, VEH_EFFECT> {
uint16_t animation_state; ///< State primarily used to change the graphics/behaviour.
byte animation_substate; ///< Sub state to time the change of the graphics/behaviour.

@ -156,7 +156,7 @@ static DualTrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
static TrackBits MaskWireBits(TileIndex t, TrackBits tracks)
{
/* Single track bits are never masked out. */
if (likely(HasAtMostOneBit(tracks))) return tracks;
if (HasAtMostOneBit(tracks)) [[likely]] return tracks;
if (!IsPlainRailTile(t)) return tracks;

@ -127,7 +127,7 @@ struct EnginePreviewWindow : Window {
switch (widget) {
case WID_EP_YES:
DoCommandP(0, this->window_number, 0, CMD_WANT_ENGINE_PREVIEW);
FALLTHROUGH;
[[fallthrough]];
case WID_EP_NO:
if (!_shift_pressed) this->Close();
break;

@ -333,7 +333,7 @@ FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory s
case BASESET_DIR:
f = FioFOpenFile(filename, mode, OLD_GM_DIR, filesize, output_filename);
if (f != nullptr) break;
FALLTHROUGH;
[[fallthrough]];
case NEWGRF_DIR:
f = FioFOpenFile(filename, mode, OLD_DATA_DIR, filesize, output_filename);
break;
@ -1264,7 +1264,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r
switch (sd) {
case BASESET_DIR:
num += this->Scan(extension, OLD_GM_DIR, tars, recursive);
FALLTHROUGH;
[[fallthrough]];
case NEWGRF_DIR:
num += this->Scan(extension, OLD_DATA_DIR, tars, recursive);
break;

@ -886,7 +886,7 @@ public:
/* We reset the files filtered */
this->OnInvalidateData(SLIWD_FILTER_CHANGES);
FALLTHROUGH;
[[fallthrough]];
case SLIWD_SELECTION_CHANGES:
/* Selection changes */

@ -48,7 +48,7 @@ void CDECL strgen_error(const char *s, ...)
_errors++;
}
void NORETURN CDECL strgen_fatal(const char *s, ...)
[[noreturn]] void CDECL strgen_fatal(const char *s, ...)
{
char buf[1024];
va_list va;

@ -67,7 +67,7 @@ void ShowGoalsList(CompanyID company);
void ShowGoalQuestion(uint16_t id, byte type, uint32_t button_mask, const std::string &question);
/* story_gui.cpp */
void ShowStoryBook(CompanyID company, uint16_t page_id = INVALID_STORY_PAGE);
void ShowStoryBook(CompanyID company, uint16_t page_id = INVALID_STORY_PAGE, bool centered = false);
/* viewport_gui.cpp */
void ShowExtraViewportWindow(TileIndex tile = INVALID_TILE);

@ -915,14 +915,14 @@ public:
switch (cargo_suffix[j].display) {
case CSD_CARGO_AMOUNT_TEXT:
SetDParamStr(3, cargo_suffix[j].text);
FALLTHROUGH;
[[fallthrough]];
case CSD_CARGO_AMOUNT:
str = stockpiling ? STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT : STR_INDUSTRY_VIEW_ACCEPT_CARGO;
break;
case CSD_CARGO_TEXT:
SetDParamStr(3, cargo_suffix[j].text);
FALLTHROUGH;
[[fallthrough]];
case CSD_CARGO:
str = STR_INDUSTRY_VIEW_ACCEPT_CARGO;
break;
@ -2469,10 +2469,11 @@ struct CargoesRow {
if (cargo_fld->u.cargo.supp_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_produced[i] = others[--other_count];
}
} else {
/* Houses only display what is demanded. */
/* Houses only display cargo that towns produce. */
for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) {
CargoID cid = cargo_fld->u.cargo.vertical_cargoes[i];
if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->ConnectCargo(cid, true);
TownProductionEffect tpe = CargoSpec::Get(cid)->town_production_effect;
if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) cargo_fld->ConnectCargo(cid, true);
}
}
}
@ -2724,8 +2725,10 @@ struct IndustryCargoesWindow : public Window {
static bool HousesCanSupply(const CargoID *cargoes, size_t length)
{
for (size_t i = 0; i < length; i++) {
if (cargoes[i] == INVALID_CARGO) continue;
if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) return true;
CargoID cid = cargoes[i];
if (!IsValidCargoID(cid)) continue;
TownProductionEffect tpe = CargoSpec::Get(cid)->town_production_effect;
if (tpe == TPE_PASSENGERS || tpe == TPE_MAIL) return true;
}
return false;
}

@ -2,7 +2,7 @@
STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Autorenew failed on {VEHICLE}{}{STRING1}
STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}The NewGRF "{RAW_STRING}" has returned a fatal error: {}{STRING7}
STR_NEWGRF_ERROR_POPUP :{WHITE}The NewGRF "{RAW_STRING}" has returned an error: {}{STRING7}
STR_ORDER_TEXT :{STRING6} {STRING2} {STRING}
STR_ORDER_TEXT :{STRING6} {STRING2} {STRING} {STRING}
##override off
##no-translate on

@ -1100,11 +1100,11 @@ struct QueryStringWindow : public Window
switch (widget) {
case WID_QS_DEFAULT:
this->editbox.text.DeleteAll();
FALLTHROUGH;
[[fallthrough]];
case WID_QS_OK:
this->OnOk();
FALLTHROUGH;
[[fallthrough]];
case WID_QS_CANCEL:
this->Close();
@ -1287,7 +1287,7 @@ struct QueryWindow : public Window {
this->proc(this->parent, true);
this->proc = nullptr;
}
FALLTHROUGH;
[[fallthrough]];
case WKC_ESC:
this->Close();

@ -126,7 +126,7 @@ void MusicDriver_ExtMidi::DoPlay()
case -1:
DEBUG(driver, 0, "extmidi: couldn't fork: %s", strerror(errno));
FALLTHROUGH;
[[fallthrough]];
default:
this->song.clear();

@ -352,17 +352,17 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
switch (game_info_version) {
case 7:
info->ticks_playing = p->Recv_uint64();
FALLTHROUGH;
[[fallthrough]];
case 6:
newgrf_serialisation = (NewGRFSerializationType)p->Recv_uint8();
if (newgrf_serialisation >= NST_END) return;
FALLTHROUGH;
[[fallthrough]];
case 5: {
info->gamescript_version = (int)p->Recv_uint32();
info->gamescript_name = p->Recv_string(NETWORK_NAME_LENGTH);
FALLTHROUGH;
[[fallthrough]];
}
case 4: {
@ -404,19 +404,19 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
*dst = c;
dst = &c->next;
}
FALLTHROUGH;
[[fallthrough]];
}
case 3:
info->calendar_date = Clamp(p->Recv_uint32(), 0, MAX_DATE.base());
info->calendar_start = Clamp(p->Recv_uint32(), 0, MAX_DATE.base());
FALLTHROUGH;
[[fallthrough]];
case 2:
info->companies_max = p->Recv_uint8 ();
info->companies_on = p->Recv_uint8 ();
p->Recv_uint8(); // Used to contain max-spectators.
FALLTHROUGH;
[[fallthrough]];
case 1:
info->server_name = p->Recv_string(NETWORK_NAME_LENGTH);

@ -462,7 +462,7 @@ struct NetworkChatWindow : public Window {
switch (widget) {
case WID_NC_SENDBUTTON: /* Send */
SendChat(this->message_editbox.text.buf, this->dtype, this->dest);
FALLTHROUGH;
[[fallthrough]];
case WID_NC_CLOSE: /* Cancel */
this->Close();

@ -1183,7 +1183,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
/* For speaking to company or giving money, we need the company-name */
case NETWORK_ACTION_GIVE_MONEY:
if (!Company::IsValidID(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY;
FALLTHROUGH;
[[fallthrough]];
case NETWORK_ACTION_CHAT_COMPANY: {
StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;

@ -898,7 +898,7 @@ public:
return ES_HANDLED;
}
/* space is pressed and filter is focused. */
FALLTHROUGH;
[[fallthrough]];
default:
return ES_NOT_HANDLED;

@ -2145,7 +2145,7 @@ struct NetworkJoinStatusWindow : Window {
progress = 15; // We don't have the final size yet; the server is still compressing!
break;
}
FALLTHROUGH;
[[fallthrough]];
default: // Waiting is 15%, so the resting receivement of map is maximum 70%
progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total;
@ -2318,7 +2318,7 @@ struct NetworkCompanyPasswordWindow : public Window {
switch (widget) {
case WID_NCP_OK:
this->OnOk();
FALLTHROUGH;
[[fallthrough]];
case WID_NCP_CANCEL:
this->Close();

@ -1570,7 +1570,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
}
default:
DEBUG(net, 1, "Received unknown chat destination type %d; doing broadcast instead", desttype);
FALLTHROUGH;
[[fallthrough]];
case DESTTYPE_BROADCAST:
case DESTTYPE_BROADCAST_SS:
@ -1623,7 +1623,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p)
switch (action) {
case NETWORK_ACTION_GIVE_MONEY:
if (!Company::IsValidID(ci->client_playas)) break;
FALLTHROUGH;
[[fallthrough]];
case NETWORK_ACTION_CHAT:
case NETWORK_ACTION_CHAT_CLIENT:
case NETWORK_ACTION_CHAT_COMPANY:

@ -2079,7 +2079,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, cons
case A0RPI_STATION_MIN_BRIDGE_HEIGHT:
if (MappedPropertyLengthMismatch(buf, 8, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x1B: // Minimum height for a bridge above
SetBit(statspec->internal_flags, SSIF_BRIDGE_HEIGHTS_SET);
for (uint i = 0; i < 8; i++) {
@ -2257,7 +2257,7 @@ static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, const
case A0RPI_BRIDGE_MENU_ICON:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x14: // purchase sprite
bridge->sprite = buf->ReadWord();
bridge->pal = buf->ReadWord();
@ -3104,15 +3104,15 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, const G
uint8_t substitute_type = buf->ReadByte();
switch (substitute_type) {
case 0x00: cs->town_effect = TE_PASSENGERS; break;
case 0x02: cs->town_effect = TE_MAIL; break;
case 0x05: cs->town_effect = TE_GOODS; break;
case 0x09: cs->town_effect = TE_WATER; break;
case 0x0B: cs->town_effect = TE_FOOD; break;
case 0x00: cs->town_acceptance_effect = TAE_PASSENGERS; break;
case 0x02: cs->town_acceptance_effect = TAE_MAIL; break;
case 0x05: cs->town_acceptance_effect = TAE_GOODS; break;
case 0x09: cs->town_acceptance_effect = TAE_WATER; break;
case 0x0B: cs->town_acceptance_effect = TAE_FOOD; break;
default:
grfmsg(1, "CargoChangeInfo: Unknown town growth substitute value %d, setting to none.", substitute_type);
FALLTHROUGH;
case 0xFF: cs->town_effect = TE_NONE; break;
[[fallthrough]];
case 0xFF: cs->town_acceptance_effect = TAE_NONE; break;
}
break;
}
@ -3129,6 +3129,24 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, const G
cs->multiplier = std::max<uint16_t>(1u, buf->ReadWord());
break;
case 0x1E: { // Town production substitute type
uint8_t substitute_type = buf->ReadByte();
switch (substitute_type) {
case 0x00: cs->town_production_effect = TPE_PASSENGERS; break;
case 0x02: cs->town_production_effect = TPE_MAIL; break;
default:
grfmsg(1, "CargoChangeInfo: Unknown town production substitute value %u, setting to none.", substitute_type);
[[fallthrough]];
case 0xFF: cs->town_production_effect = TPE_NONE; break;
}
break;
}
case 0x1F: // Town production multiplier
cs->town_production_multiplier = std::max<uint16_t>(1U, buf->ReadWord());
break;
default:
ret = HandleAction0PropertyDefault(buf, prop);
break;
@ -4513,7 +4531,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, const
RailType resolved_rt = GetRailTypeByLabel(BSWAP32(label), false);
if (resolved_rt != INVALID_RAILTYPE) {
switch (prop) {
case 0x0F: SetBit(rti->powered_railtypes, resolved_rt); FALLTHROUGH; // Powered implies compatible.
case 0x0F: SetBit(rti->powered_railtypes, resolved_rt); [[fallthrough]]; // Powered implies compatible.
case 0x0E: SetBit(rti->compatible_railtypes, resolved_rt); break;
case 0x18: SetBit(rti->introduction_required_railtypes, resolved_rt); break;
case 0x19: SetBit(rti->introduces_railtypes, resolved_rt); break;
@ -4660,7 +4678,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, cons
break;
}
grfmsg(1, "RailTypeReserveInfo: Ignoring property 1D for rail type %u because no label was set", id + i);
FALLTHROUGH;
[[fallthrough]];
case 0x0E: // Compatible railtype list
case 0x0F: // Powered railtype list
@ -5097,7 +5115,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
switch (prop) {
case A0RPI_ROADSTOP_CLASS_ID:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x08: { // Road Stop Class ID
if (rs == nullptr) {
_cur.grffile->roadstops[id + i] = std::make_unique<RoadStopSpec>();
@ -5112,42 +5130,42 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
case A0RPI_ROADSTOP_STOP_TYPE:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x09: // Road stop type
rs->stop_type = (RoadStopAvailabilityType)buf->ReadByte();
break;
case A0RPI_ROADSTOP_STOP_NAME:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x0A: // Road Stop Name
AddStringForMapping(buf->ReadWord(), &rs->name);
break;
case A0RPI_ROADSTOP_CLASS_NAME:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x0B: // Road Stop Class name
AddStringForMapping(buf->ReadWord(), &RoadStopClass::Get(rs->cls_id)->name);
break;
case A0RPI_ROADSTOP_DRAW_MODE:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x0C: // The draw mode
rs->draw_mode = (RoadStopDrawMode)buf->ReadByte();
break;
case A0RPI_ROADSTOP_TRIGGER_CARGOES:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x0D: // Cargo types for random triggers
rs->cargo_triggers = TranslateRefitMask(buf->ReadDWord());
break;
case A0RPI_ROADSTOP_ANIMATION_INFO:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x0E: // Animation info
rs->animation.frames = buf->ReadByte();
rs->animation.status = buf->ReadByte();
@ -5155,35 +5173,35 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
case A0RPI_ROADSTOP_ANIMATION_SPEED:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x0F: // Animation speed
rs->animation.speed = buf->ReadByte();
break;
case A0RPI_ROADSTOP_ANIMATION_TRIGGERS:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x10: // Animation triggers
rs->animation.triggers = buf->ReadWord();
break;
case A0RPI_ROADSTOP_CALLBACK_MASK:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x11: // Callback mask
rs->callback_mask = buf->ReadByte();
break;
case A0RPI_ROADSTOP_GENERAL_FLAGS:
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x12: // General flags
rs->flags = (uint16_t)buf->ReadDWord(); // Future-proofing, size this as 4 bytes, but we only need two bytes' worth of flags at present
break;
case A0RPI_ROADSTOP_MIN_BRIDGE_HEIGHT:
if (MappedPropertyLengthMismatch(buf, 6, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x13: // Minimum height for a bridge above
SetBit(rs->internal_flags, RSIF_BRIDGE_HEIGHTS_SET);
for (uint i = 0; i < 6; i++) {
@ -5193,7 +5211,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
case A0RPI_ROADSTOP_DISALLOWED_BRIDGE_PILLARS:
if (MappedPropertyLengthMismatch(buf, 6, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x14: // Disallowed bridge pillars
SetBit(rs->internal_flags, RSIF_BRIDGE_DISALLOWED_PILLARS_SET);
for (uint i = 0; i < 6; i++) {
@ -5203,7 +5221,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
case A0RPI_ROADSTOP_COST_MULTIPLIERS:
if (MappedPropertyLengthMismatch(buf, 2, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x15: // Cost multipliers
rs->build_cost_multiplier = buf->ReadByte();
rs->clear_cost_multiplier = buf->ReadByte();
@ -5211,7 +5229,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
case A0RPI_ROADSTOP_HEIGHT:
if (MappedPropertyLengthMismatch(buf, 1, mapping_entry)) break;
FALLTHROUGH;
[[fallthrough]];
case 0x16: // Height
rs->height = buf->ReadByte();
break;
@ -5284,7 +5302,7 @@ static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, Grf
case CIR_UNKNOWN:
grfmsg(0, "%s: Unknown property 0x%02X of feature %s, disabling", caller, property, GetFeatureString(feature));
FALLTHROUGH;
[[fallthrough]];
case CIR_INVALID_ID: {
/* No debug message for an invalid ID, as it has already been output */
@ -10837,6 +10855,14 @@ static void FinaliseEngineArray()
void FinaliseCargoArray()
{
for (CargoSpec &cs : CargoSpec::array) {
if (cs.town_production_effect == INVALID_TPE) {
/* Set default town production effect by cargo label. */
switch (cs.label) {
case 'PASS': cs.town_production_effect = TPE_PASSENGERS; break;
case 'MAIL': cs.town_production_effect = TPE_MAIL; break;
default: cs.town_production_effect = TPE_NONE; break;
}
}
if (!cs.IsValid()) {
cs.name = cs.name_single = cs.units_volume = STR_NEWGRF_INVALID_CARGO;
cs.quantifier = STR_NEWGRF_INVALID_CARGO_QUANTITY;

@ -189,7 +189,7 @@ struct AirportResolverObject : public ResolverObject {
{
TownScopeResolver *tsr = this->GetTown();
if (tsr != nullptr) return tsr;
FALLTHROUGH;
[[fallthrough]];
}
default: return ResolverObject::GetScope(scope, relative);
}

@ -1070,7 +1070,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
break;
}
/* With double click, continue */
FALLTHROUGH;
[[fallthrough]];
}
case WID_NS_REMOVE: { // Remove GRF
@ -1128,7 +1128,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
break;
}
/* With double click, continue */
FALLTHROUGH;
[[fallthrough]];
}
case WID_NS_ADD:
@ -1284,7 +1284,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
}
this->avails.ForceRebuild();
FALLTHROUGH;
[[fallthrough]];
case GOID_NEWGRF_CURRENT_LOADED:
this->modified = false;
@ -1293,7 +1293,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback {
case GOID_NEWGRF_LIST_EDITED:
this->preset = -1;
FALLTHROUGH;
[[fallthrough]];
case GOID_NEWGRF_CHANGES_MADE:
UpdateScrollBars();

@ -129,7 +129,7 @@ uint32_t IndustriesScopeResolver::GetCountAndDistanceOfClosestInstance(byte para
case 0xFFFFFFFF: // current grf
GrfID = GetIndustrySpec(this->industry->type)->grf_prop.grffile->grfid;
FALLTHROUGH;
[[fallthrough]];
default: // use the grfid specified in register 100h
SetBit(param_setID, 7); // bit 7 means it is not an old type

@ -72,7 +72,7 @@ struct IndustriesResolverObject : public ResolverObject {
TownScopeResolver *tsr = this->GetTown();
if (tsr != nullptr) return tsr;
}
FALLTHROUGH;
[[fallthrough]];
default:
return ResolverObject::GetScope(scope, relative);

@ -243,7 +243,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint32_t local_id, uint32_t
case 0xFFFFFFFF: // current grf
grf_id = grfid;
FALLTHROUGH;
[[fallthrough]];
default: // use the grfid specified in register 100h
idx = _object_mngr.GetID(local_id, grf_id);

@ -184,7 +184,7 @@ struct ObjectResolverObject : public ResolverObject {
case VSG_SCOPE_PARENT: {
TownScopeResolver *tsr = this->GetTown();
if (tsr != nullptr) return tsr;
FALLTHROUGH;
[[fallthrough]];
}
default:

@ -124,7 +124,7 @@ struct RoadStopResolverObject : public ResolverObject {
case VSG_SCOPE_PARENT: {
TownScopeResolver *tsr = this->GetTown();
if (tsr != nullptr) return tsr;
FALLTHROUGH;
[[fallthrough]];
}
default: return ResolverObject::GetScope(scope, relative);
}

@ -76,7 +76,7 @@ struct StationResolverObject : public ResolverObject {
case VSG_SCOPE_PARENT: {
TownScopeResolver *tsr = this->GetTown();
if (tsr != nullptr) return tsr;
FALLTHROUGH;
[[fallthrough]];
}
default:

@ -99,14 +99,14 @@
case 0xC9: return GB(ClampTo<uint16_t>(this->t->supplied[CT_MAIL].old_act), 8, 8);
case 0xCA: return this->t->GetPercentTransported(CT_PASSENGERS);
case 0xCB: return this->t->GetPercentTransported(CT_MAIL);
case 0xCC: return this->t->received[TE_FOOD].new_act;
case 0xCD: return GB(this->t->received[TE_FOOD].new_act, 8, 8);
case 0xCE: return this->t->received[TE_WATER].new_act;
case 0xCF: return GB(this->t->received[TE_WATER].new_act, 8, 8);
case 0xD0: return this->t->received[TE_FOOD].old_act;
case 0xD1: return GB(this->t->received[TE_FOOD].old_act, 8, 8);
case 0xD2: return this->t->received[TE_WATER].old_act;
case 0xD3: return GB(this->t->received[TE_WATER].old_act, 8, 8);
case 0xCC: return this->t->received[TAE_FOOD].new_act;
case 0xCD: return GB(this->t->received[TAE_FOOD].new_act, 8, 8);
case 0xCE: return this->t->received[TAE_WATER].new_act;
case 0xCF: return GB(this->t->received[TAE_WATER].new_act, 8, 8);
case 0xD0: return this->t->received[TAE_FOOD].old_act;
case 0xD1: return GB(this->t->received[TAE_FOOD].old_act, 8, 8);
case 0xD2: return this->t->received[TAE_WATER].old_act;
case 0xD3: return GB(this->t->received[TAE_WATER].old_act, 8, 8);
case 0xD4: return this->t->road_build_months;
case 0xD5: return this->t->fund_buildings_months;
case A2VRI_TOWNS_HOUSE_COUNT: return this->t->cache.num_houses;

@ -129,7 +129,7 @@ extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMP
extern void OSOpenBrowser(const std::string &url);
extern void RebuildTownCaches(bool cargo_update_required, bool old_map_position);
extern void ShowOSErrorBox(const char *buf, bool system);
extern void NORETURN DoOSAbort();
[[noreturn]] extern void DoOSAbort();
extern std::string _config_file;
extern uint64_t _station_tile_cache_hash;
@ -143,7 +143,7 @@ std::mutex _music_driver_mutex;
static std::string _music_driver_params;
static std::atomic<bool> _music_inited;
void NORETURN usererror_str(const char *msg)
[[noreturn]] void usererror_str(const char *msg)
{
ShowOSErrorBox(msg, false);
if (VideoDriver::GetInstance() != nullptr) VideoDriver::GetInstance()->Stop();
@ -176,7 +176,7 @@ void CDECL usererror(const char *s, ...)
usererror_str(buf);
}
static void NORETURN fatalerror_common(const char *msg)
[[noreturn]] static void fatalerror_common(const char *msg)
{
if (VideoDriver::GetInstance() == nullptr || VideoDriver::GetInstance()->HasGUI()) {
ShowOSErrorBox(msg, true);

@ -380,7 +380,7 @@ public:
/** What caused us going to the depot? */
inline OrderDepotTypeFlags GetDepotOrderType() const { return (OrderDepotTypeFlags)GB(this->flags, 0, 3); }
/** What are we going to do when in the depot. */
inline OrderDepotActionFlags GetDepotActionType() const { return (OrderDepotActionFlags)GB(this->flags, 4, 3); }
inline OrderDepotActionFlags GetDepotActionType() const { return (OrderDepotActionFlags)GB(this->flags, 3, 4); }
/** Extra depot flags. */
inline OrderDepotExtraFlags GetDepotExtraFlags() const { return (OrderDepotExtraFlags)GB(this->flags, 8, 8); }
/** What waypoint flags? */
@ -445,7 +445,7 @@ public:
/** Set the cause to go to the depot. */
inline void SetDepotOrderType(OrderDepotTypeFlags depot_order_type) { SB(this->flags, 0, 3, depot_order_type); }
/** Set what we are going to do in the depot. */
inline void SetDepotActionType(OrderDepotActionFlags depot_service_type) { SB(this->flags, 4, 3, depot_service_type); }
inline void SetDepotActionType(OrderDepotActionFlags depot_service_type) { SB(this->flags, 3, 4, depot_service_type); }
/** Set what we are going to do in the depot. */
inline void SetDepotExtraFlags(OrderDepotExtraFlags depot_extra_flags) { SB(this->flags, 8, 8, depot_extra_flags); }
/** Set waypoint flags. */

@ -1083,11 +1083,21 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s
/* Filter invalid load/unload types. */
switch (new_order.GetLoadType()) {
case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
case OLFB_CARGO_TYPE_LOAD:
if (allow_load_by_cargo_type) break;
return CMD_ERROR;
default: return CMD_ERROR;
case OLF_LOAD_IF_POSSIBLE:
case OLFB_NO_LOAD:
break;
case OLFB_FULL_LOAD:
case OLF_FULL_LOAD_ANY:
if (v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
break;
default:
return CMD_ERROR;
}
switch (new_order.GetUnloadType()) {
case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
@ -1103,7 +1113,7 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s
case OSL_PLATFORM_MIDDLE:
case OSL_PLATFORM_THROUGH:
if (v->type != VEH_TRAIN) return CMD_ERROR;
FALLTHROUGH;
[[fallthrough]];
case OSL_PLATFORM_FAR_END:
break;
@ -1207,6 +1217,7 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s
VehicleOrderID skip_to = new_order.GetConditionSkipToOrder();
if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order).
if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR;
if (v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_CONDITIONAL);
OrderConditionComparator occ = new_order.GetConditionComparator();
if (occ >= OCC_END) return CMD_ERROR;
@ -1267,7 +1278,7 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s
case OCV_LOAD_PERCENTAGE:
case OCV_RELIABILITY:
if (new_order.GetConditionValue() > 100) return CMD_ERROR;
FALLTHROUGH;
[[fallthrough]];
default:
if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR;
@ -1389,6 +1400,7 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
u->cur_implicit_order_index = cur;
}
}
if (u->cur_timetable_order_index != INVALID_VEH_ORDER_ID && sel_ord <= u->cur_timetable_order_index) {
uint cur = u->cur_timetable_order_index + 1;
/* Check if we don't go out of bound */
@ -1396,6 +1408,10 @@ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord)
u->cur_timetable_order_index = cur;
}
}
/* Unbunching data is no longer valid. */
u->ResetDepotUnbunching();
/* Update any possible open window of the vehicle */
InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 16));
}
@ -1543,6 +1559,8 @@ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
}
}
/* Unbunching data is no longer valid. */
u->ResetDepotUnbunching();
if (u->cur_timetable_order_index != INVALID_VEH_ORDER_ID) {
if (sel_ord < u->cur_timetable_order_index) {
@ -1611,6 +1629,9 @@ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
v->UpdateRealOrderIndex();
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
/* Unbunching data is no longer valid. */
v->ResetDepotUnbunching();
InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
v->ClearSeparation();
@ -1696,6 +1717,9 @@ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint3
} else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) {
u->cur_implicit_order_index++;
}
/* Unbunching data is no longer valid. */
u->ResetDepotUnbunching();
u->cur_timetable_order_index = INVALID_VEH_ORDER_ID;
@ -1915,10 +1939,27 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return CMD_ERROR;
if ((data > OLFB_NO_LOAD && data != OLFB_CARGO_TYPE_LOAD) || data == 1) return CMD_ERROR;
if (data == order->GetLoadType()) return CMD_ERROR;
if ((data & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) && v->HasUnbunchingOrder()) return_cmd_error(STR_ERROR_UNBUNCHING_NO_FULL_LOAD);
break;
case MOF_DEPOT_ACTION:
if (data >= DA_END) return CMD_ERROR;
/* Check if we are allowed to add unbunching. We are always allowed to remove it. */
if (data == DA_UNBUNCH) {
/* Only one unbunching order is allowed in a vehicle's orders. If this order already has an unbunching action, no error is needed. */
if (v->HasUnbunchingOrder() && !(order->GetDepotActionType() & ODATFB_UNBUNCH)) return_cmd_error(STR_ERROR_UNBUNCHING_ONLY_ONE_ALLOWED);
for (Order *o : v->Orders()) {
/* We don't allow unbunching if the vehicle has a conditional order. */
if (o->IsType(OT_CONDITIONAL)) return_cmd_error(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_CONDITIONAL);
/* We don't allow unbunching if the vehicle has a full load order. */
if (o->IsType(OT_GOTO_STATION) && o->GetLoadType() & (OLFB_FULL_LOAD | OLF_FULL_LOAD_ANY)) return_cmd_error(STR_ERROR_UNBUNCHING_NO_UNBUNCHING_FULL_LOAD);
if (o->IsType(OT_GOTO_STATION) && o->GetLoadType() == OLFB_CARGO_TYPE_LOAD) {
}
}
}
break;
case MOF_COND_VARIABLE:
@ -2153,7 +2194,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
break;
case MOF_DEPOT_ACTION: {
OrderDepotActionFlags base_order_action_type = order->GetDepotActionType() & ~(ODATFB_HALT | ODATFB_SELL);
OrderDepotActionFlags base_order_action_type = order->GetDepotActionType() & ~(ODATFB_HALT | ODATFB_SELL | ODATFB_UNBUNCH);
switch (data) {
case DA_ALWAYS_GO:
order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
@ -2178,6 +2219,11 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
order->SetRefit(CARGO_NO_REFIT);
break;
case DA_UNBUNCH:
order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE));
order->SetDepotActionType((OrderDepotActionFlags)(base_order_action_type | ODATFB_UNBUNCH));
break;
default:
NOT_REACHED();
}
@ -2261,7 +2307,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
case OCV_LOAD_PERCENTAGE:
case OCV_RELIABILITY:
if (order->GetConditionValue() > 100) order->SetConditionValue(100);
FALLTHROUGH;
[[fallthrough]];
default:
if (old_var_was_cargo || old_var_was_slot || old_var_was_counter || old_var_was_time || old_var_was_tt) order->SetConditionValue(0);
@ -2421,6 +2467,10 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
(u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_GOTO_WAYPOINT))) {
u->current_order.SetRoadVehTravelDirection((DiagDirection)data);
}
/* Unbunching data is no longer valid. */
u->ResetDepotUnbunching();
InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS);
}
CheckMarkDirtyViewportRoutePaths(v);
@ -2951,6 +3001,9 @@ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indic
}
}
/* Unbunching data is no longer valid. */
v->ResetDepotUnbunching();
if (reset_order_indices) {
v->cur_implicit_order_index = v->cur_real_order_index = 0;
v->cur_timetable_order_index = INVALID_VEH_ORDER_ID;

@ -775,6 +775,7 @@ static const StringID _order_depot_action_dropdown[] = {
STR_ORDER_DROP_GO_ALWAYS_DEPOT,
STR_ORDER_DROP_SERVICE_DEPOT,
STR_ORDER_DROP_HALT_DEPOT,
STR_ORDER_DROP_UNBUNCH,
STR_ORDER_DROP_SELL_DEPOT,
INVALID_STRING_ID
};
@ -785,6 +786,8 @@ static int DepotActionStringIndex(const Order *order)
return DA_SELL;
} else if (order->GetDepotActionType() & ODATFB_HALT) {
return DA_STOP;
} else if (order->GetDepotActionType() & ODATFB_UNBUNCH) {
return DA_SERVICE;
} else if (order->GetDepotOrderType() & ODTFB_SERVICE) {
return DA_SERVICE;
} else {
@ -869,11 +872,12 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
SetDParam(7, STR_EMPTY);
SetDParam(10, STR_EMPTY);
SetDParam(11, STR_EMPTY);
/* Check range for aircraft. */
if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0 && order->IsGotoOrder()) {
const Order *next = order->next != nullptr ? order->next : v->GetFirstOrder();
if (GetOrderDistance(order, next, v) > Aircraft::From(v)->acache.cached_max_range_sqr) SetDParam(10, STR_ORDER_OUT_OF_RANGE);
if (GetOrderDistance(order, next, v) > Aircraft::From(v)->acache.cached_max_range_sqr) SetDParam(11, STR_ORDER_OUT_OF_RANGE);
}
bool timetable_wait_time_valid = false;
@ -976,6 +980,12 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
}
timetable_wait_time_valid = !(order->GetDepotActionType() & ODATFB_HALT);
}
/* Do not show unbunching in the depot in the timetable window. */
if (!timetable && (order->GetDepotActionType() & ODATFB_UNBUNCH)) {
SetDParam(10, STR_ORDER_WAIT_TO_UNBUNCH);
}
break;
case OT_GOTO_WAYPOINT: {
@ -1910,6 +1920,9 @@ public:
{
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_O_SCROLLBAR);
if (NWidgetCore *nwid = this->GetWidget<NWidgetCore>(WID_O_DEPOT_ACTION); nwid != nullptr) {
nwid->tool_tip = STR_ORDER_TRAIN_DEPOT_ACTION_TOOLTIP + v->type;
}
this->GetWidget<NWidgetStacked>(WID_O_SEL_OCCUPANCY)->SetDisplayedPlane(_settings_client.gui.show_order_occupancy_by_default ? 0 : SZSP_NONE);
this->SetWidgetLoweredState(WID_O_OCCUPANCY_TOGGLE, _settings_client.gui.show_order_occupancy_by_default);
this->current_aux_plane = SZSP_NONE;
@ -2035,7 +2048,7 @@ public:
case VIWD_AUTOREPLACE:
/* Autoreplace replaced the vehicle */
this->vehicle = Vehicle::Get(this->window_number);
FALLTHROUGH;
[[fallthrough]];
case VIWD_CONSIST_CHANGED:
/* Vehicle composition was changed. */
@ -2145,7 +2158,6 @@ public:
/* First row. */
this->RaiseWidget(WID_O_FULL_LOAD);
this->RaiseWidget(WID_O_UNLOAD);
this->RaiseWidget(WID_O_SERVICE);
/* Selection widgets. */
/* Train or road vehicle. */
@ -2266,7 +2278,6 @@ public:
this->SetWidgetDisabledState(WID_O_REFIT,
(order->GetDepotOrderType() & ODTFB_SERVICE) || (order->GetDepotActionType() & ODATFB_HALT) ||
(!this->can_do_refit && !order->IsRefit()));
this->SetWidgetLoweredState(WID_O_SERVICE, order->GetDepotOrderType() & ODTFB_SERVICE);
break;
case OT_CONDITIONAL: {
@ -2665,6 +2676,30 @@ public:
SetDParam(0, this->vehicle->index);
break;
case WID_O_DEPOT_ACTION: {
VehicleOrderID sel = this->OrderGetSel();
const Order *order = this->vehicle->GetOrder(sel);
if (order == nullptr || !order->IsType(OT_GOTO_DEPOT)) {
/* We can't leave this param unset or the undefined behavior can cause a crash. */
SetDParam(0, STR_EMPTY);
break;
};
/* Select the current action selected in the dropdown. The flags don't match the dropdown so we can't just use an index. */
if (order->GetDepotActionType() & ODATFB_SELL) {
SetDParam(0, STR_ORDER_DROP_SELL_DEPOT);
} else if (order->GetDepotOrderType() & ODTFB_SERVICE) {
SetDParam(0, STR_ORDER_DROP_SERVICE_DEPOT);
} else if (order->GetDepotActionType() & ODATFB_HALT) {
SetDParam(0, STR_ORDER_DROP_HALT_DEPOT);
} else if (order->GetDepotActionType() & ODATFB_UNBUNCH) {
SetDParam(0, STR_ORDER_DROP_UNBUNCH);
} else {
SetDParam(0, STR_ORDER_DROP_GO_ALWAYS_DEPOT);
}
break;
}
case WID_O_OCCUPANCY_TOGGLE:
const_cast<Vehicle *>(this->vehicle)->RecalculateOrderOccupancyAverage();
if (this->vehicle->order_occupancy_average >= 16) {
@ -2985,13 +3020,9 @@ public:
this->OrderClick_Refit(0, false);
break;
case WID_O_SERVICE:
if (this->GetWidget<NWidgetLeaf>(widget)->ButtonHit(pt)) {
this->OrderClick_Service(-1);
} else {
ShowDropDownMenu(this, _order_depot_action_dropdown, DepotActionStringIndex(this->vehicle->GetOrder(this->OrderGetSel())),
WID_O_SERVICE, 0, _settings_client.gui.show_depot_sell_gui ? 0 : (1 << DA_SELL), 0, DDSF_LOST_FOCUS);
}
case WID_O_DEPOT_ACTION:
ShowDropDownMenu(this, _order_depot_action_dropdown, DepotActionStringIndex(this->vehicle->GetOrder(this->OrderGetSel())),
WID_O_DEPOT_ACTION, 0, _settings_client.gui.show_depot_sell_gui ? 0 : (1 << DA_SELL), 0, DDSF_LOST_FOCUS);
break;
case WID_O_REFIT_DROPDOWN:
@ -3375,7 +3406,7 @@ public:
}
break;
case WID_O_SERVICE:
case WID_O_DEPOT_ACTION:
this->OrderClick_Service(index);
break;
@ -3785,8 +3816,8 @@ static constexpr NWidgetPart _nested_orders_train_widgets[] = {
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_MIDDLE),
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_UNLOAD), SetMinimalSize(93, 12), SetFill(1, 0),
SetDataTip(STR_ORDER_TOGGLE_UNLOAD, STR_ORDER_TOOLTIP_UNLOAD), SetResize(1, 0),
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_SERVICE), SetMinimalSize(93, 12), SetFill(1, 0),
SetDataTip(STR_NULL, STR_NULL), SetResize(1, 0),
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_DEPOT_ACTION), SetMinimalSize(93, 12), SetFill(1, 0),
SetDataTip(STR_JUST_STRING, STR_NULL), SetResize(1, 0),
EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_RIGHT),
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(93, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(),
@ -3932,8 +3963,8 @@ static constexpr NWidgetPart _nested_orders_widgets[] = {
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_REFIT), SetMinimalSize(186, 12), SetFill(1, 0),
SetDataTip(STR_ORDER_REFIT, STR_ORDER_REFIT_TOOLTIP), SetResize(1, 0),
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_SERVICE), SetMinimalSize(124, 12), SetFill(1, 0),
SetDataTip(STR_NULL, STR_NULL), SetResize(1, 0),
NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_DEPOT_ACTION), SetMinimalSize(124, 12), SetFill(1, 0),
SetDataTip(STR_JUST_STRING, STR_NULL), SetResize(1, 0),
EndContainer(),
/* Buttons for setting a condition. */

@ -140,6 +140,7 @@ enum OrderDepotActionFlags {
ODATFB_HALT = 1 << 0, ///< Service the vehicle and then halt it.
ODATFB_NEAREST_DEPOT = 1 << 1, ///< Send the vehicle to the nearest depot.
ODATFB_SELL = 1 << 2, ///< Sell the vehicle on arrival at the depot.
ODATFB_UNBUNCH = 1 << 3, ///< Service the vehicle and then unbunch it.
};
DECLARE_ENUM_AS_BIT_SET(OrderDepotActionFlags)
@ -247,6 +248,7 @@ enum OrderDepotAction {
DA_ALWAYS_GO, ///< Always go to the depot
DA_SERVICE, ///< Service only if needed
DA_STOP, ///< Go to the depot and stop there
DA_UNBUNCH, ///< Go to the depot and unbunch
DA_SELL, ///< Go to the depot and sell vehicle
DA_END
};

@ -237,7 +237,7 @@ void ShowOSErrorBox(const char *buf, bool)
}
}
void NORETURN DoOSAbort()
[[noreturn]] void DoOSAbort()
{
abort();
}

@ -56,7 +56,7 @@
#pragma GCC diagnostic ignored "-Wclobbered"
#endif
static void NORETURN ImmediateExitProcess(uint exit_code)
static [[noreturn]] void ImmediateExitProcess(uint exit_code)
{
/* TerminateProcess may fail in some special edge cases, fall back to ExitProcess in this case */
TerminateProcess(GetCurrentProcess(), exit_code);

@ -64,7 +64,7 @@ void ShowOSErrorBox(const char *buf, bool system)
MessageBox(GetActiveWindow(), OTTD2FS(buf).c_str(), L"Error!", MB_ICONSTOP | MB_TASKMODAL);
}
void NORETURN DoOSAbort()
[[noreturn]] void DoOSAbort()
{
RaiseException(0xE1212012, 0, 0, nullptr);

@ -150,7 +150,7 @@ public:
* waypoint. */
Yapf().DisableCache(true);
}
FALLTHROUGH;
[[fallthrough]];
case OT_GOTO_STATION:
m_destTile = CalcClosestStationTile(v->current_order.GetDestination(), v->tile, v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT);
@ -162,7 +162,7 @@ public:
if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
m_any_depot = true;
}
FALLTHROUGH;
[[fallthrough]];
default:
m_destTile = v->dest_tile;

@ -876,7 +876,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32_t p1,
_rail_track_endtile = tile;
return_cmd_error(STR_ERROR_ALREADY_BUILT);
}
FALLTHROUGH;
[[fallthrough]];
}
default: {
@ -1478,7 +1478,7 @@ static void ReReserveTrainPath(Train *v)
* - p1 = (bit 4) - 0 = signals, 1 = semaphores
* - p1 = (bit 5-7) - type of the signal, for valid values see enum SignalType in rail_map.h
* - p1 = (bit 8) - convert the present signal type and variant
* - p1 = (bit 9-14)- cycle through which signal set?
* - p1 = (bit 9-10)- cycle through which signal sets?
* - p1 = (bit 15-16)-cycle the signal direction this many times
* - p1 = (bit 17) - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type
* - p1 = (bit 18) - permit creation of/conversion to bidirectionally signalled bridges/tunnels
@ -1498,7 +1498,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t p
bool convert_signal = HasBit(p1, 8); // convert button pressed
uint num_dir_cycle = GB(p1, 15, 2);
uint which_signals = GB(p1, 9, 6);
SignalCycleGroups which_signals = (SignalCycleGroups)GB(p1, 9, 2);
uint signal_style = GB(p1, 19, 4);
if (signal_style > _num_new_signal_styles || !HasBit(_enabled_new_signal_styles_mask, signal_style)) return CMD_ERROR;
@ -1757,10 +1757,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t p
} else {
if (_ctrl_pressed && GetSignalStyle(tile, track) != 0) {
SignalType new_sigtype = GetSignalType(tile, track);
do {
new_sigtype = NextSignalType(new_sigtype, which_signals);
} while (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsSignalTypeUnsuitableForRealisticBraking(new_sigtype));
SignalType new_sigtype = NextSignalType(GetSignalType(tile, track), which_signals);
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsSignalTypeUnsuitableForRealisticBraking(new_sigtype)) return CMD_ERROR;
if (!is_style_usable(GetSignalVariant(tile, track), GetSignalStyle(tile, track), 1 << new_sigtype)) return_cmd_error(STR_ERROR_UNSUITABLE_SIGNAL_TYPE);
}
@ -1842,9 +1840,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32_t p
if (sigtype == SIGTYPE_NO_ENTRY) CycleSignalSide(tile, track);
do {
sigtype = NextSignalType(sigtype, which_signals);
} while (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsSignalTypeUnsuitableForRealisticBraking(sigtype));
sigtype = NextSignalType(sigtype, which_signals);
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC && IsSignalTypeUnsuitableForRealisticBraking(sigtype)) return CMD_ERROR;
SetSignalType(tile, track, sigtype);
if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) {
@ -4065,13 +4062,13 @@ static void DrawTile_Track(TileInfo *ti, DrawTileProcParams params)
switch (GetRailDepotDirection(ti->tile)) {
case DIAGDIR_NE:
if (!IsInvisibilitySet(TO_BUILDINGS)) break;
FALLTHROUGH;
[[fallthrough]];
case DIAGDIR_SW:
DrawGroundSprite(ground + RTO_X, PAL_NONE);
break;
case DIAGDIR_NW:
if (!IsInvisibilitySet(TO_BUILDINGS)) break;
FALLTHROUGH;
[[fallthrough]];
case DIAGDIR_SE:
DrawGroundSprite(ground + RTO_Y, PAL_NONE);
break;
@ -4085,13 +4082,13 @@ static void DrawTile_Track(TileInfo *ti, DrawTileProcParams params)
switch (GetRailDepotDirection(ti->tile)) {
case DIAGDIR_NE:
if (!IsInvisibilitySet(TO_BUILDINGS)) break;
FALLTHROUGH;
[[fallthrough]];
case DIAGDIR_SW:
DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH);
break;
case DIAGDIR_NW:
if (!IsInvisibilitySet(TO_BUILDINGS)) break;
FALLTHROUGH;
[[fallthrough]];
case DIAGDIR_SE:
DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH);
break;
@ -4105,13 +4102,13 @@ static void DrawTile_Track(TileInfo *ti, DrawTileProcParams params)
switch (GetRailDepotDirection(ti->tile)) {
case DIAGDIR_NE:
if (!IsInvisibilitySet(TO_BUILDINGS)) break;
FALLTHROUGH;
[[fallthrough]];
case DIAGDIR_SW:
DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
break;
case DIAGDIR_NW:
if (!IsInvisibilitySet(TO_BUILDINGS)) break;
FALLTHROUGH;
[[fallthrough]];
case DIAGDIR_SE:
DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
break;

@ -283,12 +283,14 @@ static void GenericPlaceSignals(TileIndex tile)
uint32_t p1 = track;
/* Which signals should we cycle through? */
uint8_t cycle_types;
if (_settings_client.gui.cycle_signal_types == SIGNAL_CYCLE_ALL && (_settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL || _settings_game.vehicle.train_braking_model == TBM_REALISTIC)) {
cycle_types = SIGNAL_CYCLE_ALL;
SignalCycleGroups cycle_types;
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC) {
cycle_types = SCG_BLOCK | SCG_PBS;
} else if (_settings_client.gui.cycle_signal_types == SIGNAL_CYCLE_ALL) {
cycle_types = SCG_PBS;
if (_settings_client.gui.signal_gui_mode == SIGNAL_GUI_ALL) cycle_types |= SCG_BLOCK;
} else {
cycle_types = SIGNAL_CYCLE_PATH;
cycle_types = SCG_CURRENT_GROUP;
}
if (w != nullptr) {
@ -297,7 +299,7 @@ static void GenericPlaceSignals(TileIndex tile)
SB(p1, 4, 1, _cur_signal_variant);
SB(p1, 5, 3, _cur_signal_type);
SB(p1, 8, 1, _convert_signal_button);
SB(p1, 9, 6, cycle_types);
SB(p1, 9, 2, cycle_types);
SB(p1, 19, 4, _cur_signal_style);
if (_cur_signal_type == SIGTYPE_NO_ENTRY) SB(p1, 15, 2, 1); // reverse default signal direction
} else {
@ -305,7 +307,7 @@ static void GenericPlaceSignals(TileIndex tile)
SB(p1, 4, 1, (CalTime::CurYear() < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
SB(p1, 5, 3, GetDefaultSignalType());
SB(p1, 8, 1, 0);
SB(p1, 9, 6, cycle_types);
SB(p1, 9, 2, cycle_types);
}
SB(p1, 18, 1, _settings_client.gui.adv_sig_bridge_tun_modes);
SB(p1, 23, 5, Clamp<int>(_settings_client.gui.drag_signals_density, 1, 16));
@ -2757,7 +2759,7 @@ static void SetDefaultRailGui()
if (count[rt] > 0) break;
/* No rail, just get the first available one */
FALLTHROUGH;
[[fallthrough]];
}
case 0: {
/* Use first available type */

@ -18,8 +18,8 @@ enum SignalGUISettings : uint8_t {
/** Settings for which signals are cycled through by control-clicking on the signal with the signal tool. */
enum SignalCycleSettings : uint8_t {
SIGNAL_CYCLE_PATH = 0, ///< Cycle through path signals only.
SIGNAL_CYCLE_ALL = 1, ///< Cycle through all signals visible.
SIGNAL_CYCLE_GROUP = 0, ///< Cycle through current signal group (block or path) only.
SIGNAL_CYCLE_ALL = 1, ///< Cycle through all signals visible to the player.
};
#endif /* RAIL_GUI_TYPE_H */

@ -139,7 +139,7 @@ enum RoadVehicleFlags {
/**
* Buses, trucks and trams belong to this class.
*/
struct RoadVehicle FINAL : public GroundVehicle<RoadVehicle, VEH_ROAD> {
struct RoadVehicle final : public GroundVehicle<RoadVehicle, VEH_ROAD> {
byte state; ///< @see RoadVehicleStates
byte frame;
uint16_t blocked_ctr;

@ -427,7 +427,12 @@ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32_t p1, uin
if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
if (flags & DC_EXEC) v->reverse_ctr = 180;
if (flags & DC_EXEC) {
v->reverse_ctr = 180;
/* Unbunching data is no longer valid. */
v->ResetDepotUnbunching();
}
return CommandCost();
}
@ -1338,6 +1343,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
if (RoadVehFindCloseTo(v, x, y, v->direction, false) != nullptr) return true;
VehicleServiceInDepot(v);
v->LeaveUnbunchingDepot();
StartRoadVehSound(v);
@ -2154,7 +2160,11 @@ static bool RoadVehController(RoadVehicle *v)
v->HandleWaiting(false, true);
if (v->current_order.IsType(OT_WAITING)) return true;
if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
if (v->IsInDepot()) {
/* Check if we should wait here for unbunching. */
if (v->IsWaitingForUnbunching()) return true;
if (RoadVehLeaveDepot(v, true)) return true;
}
int j;
{

@ -175,7 +175,7 @@ static void ConvertTownOwner()
if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) {
_m[tile].m3 = OWNER_TOWN;
}
FALLTHROUGH;
[[fallthrough]];
case MP_TUNNELBRIDGE:
if (_m[tile].m1 & 0x80) SetTileOwner(tile, OWNER_TOWN);
@ -2150,7 +2150,21 @@ bool AfterLoadGame()
v->current_order.SetLoadType(OLFB_NO_LOAD);
}
}
} else if (SlXvIsFeaturePresent(XSLFI_JOKERPP, 1, SL_JOKER_1_23)) {
}
if (IsSavegameVersionBefore(SLV_DEPOT_UNBUNCHING) && SlXvIsFeatureMissing(XSLFI_DEPOT_UNBUNCHING)) {
/* OrderDepotActionFlags were moved, instead of starting at bit 4 they now start at bit 3. */
for (Order *order : Order::Iterate()) {
if (!order->IsType(OT_GOTO_DEPOT)) continue;
OrderDepotActionFlags flags = (OrderDepotActionFlags)(order->GetDepotActionType() >> 1);
if (((flags & (1 << 2)) != 0) && SlXvIsFeatureMissing(XSLFI_DEPOT_UNBUNCHING)) {
flags ^= (ODATFB_SELL | ODATFB_UNBUNCH); // Unbunch moved from bit 2 to bit 3
}
order->SetDepotActionType(flags);
}
}
if (SlXvIsFeaturePresent(XSLFI_JOKERPP, 1, SL_JOKER_1_23)) {
for (Order *order : Order::Iterate()) {
if (order->IsType(OT_CONDITIONAL) && order->GetConditionVariable() == OCV_SLOT_OCCUPANCY) {
order->GetXDataRef() = order->GetConditionValue();
@ -2656,15 +2670,15 @@ bool AfterLoadGame()
s->remaining = 12 - s->remaining; // convert "age" to "remaining"
s->awarded = INVALID_COMPANY; // not awarded to anyone
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
switch (cs->town_effect) {
case TE_PASSENGERS:
case TE_MAIL:
switch (cs->town_acceptance_effect) {
case TAE_PASSENGERS:
case TAE_MAIL:
/* Town -> Town */
s->src_type = s->dst_type = SourceType::Town;
if (Town::IsValidID(s->src) && Town::IsValidID(s->dst)) continue;
break;
case TE_GOODS:
case TE_FOOD:
case TAE_GOODS:
case TAE_FOOD:
/* Industry -> Town */
s->src_type = SourceType::Industry;
s->dst_type = SourceType::Town;
@ -2682,9 +2696,9 @@ bool AfterLoadGame()
* Town -> Town subsidies are converted using simple heuristic */
s->remaining = 24 - s->remaining; // convert "age of awarded subsidy" to "remaining"
const CargoSpec *cs = CargoSpec::Get(s->cargo_type);
switch (cs->town_effect) {
case TE_PASSENGERS:
case TE_MAIL: {
switch (cs->town_acceptance_effect) {
case TAE_PASSENGERS:
case TAE_MAIL: {
/* Town -> Town */
const Station *ss = Station::GetIfValid(s->src);
const Station *sd = Station::GetIfValid(s->dst);
@ -3258,12 +3272,12 @@ bool AfterLoadGame()
/* Set the default cargo requirement for town growth */
switch (_settings_game.game_creation.landscape) {
case LT_ARCTIC:
if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER;
if (FindFirstCargoWithTownAcceptanceEffect(TAE_FOOD) != nullptr) t->goal[TAE_FOOD] = TOWN_GROWTH_WINTER;
break;
case LT_TROPIC:
if (FindFirstCargoWithTownEffect(TE_FOOD) != nullptr) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT;
if (FindFirstCargoWithTownEffect(TE_WATER) != nullptr) t->goal[TE_WATER] = TOWN_GROWTH_DESERT;
if (FindFirstCargoWithTownAcceptanceEffect(TAE_FOOD) != nullptr) t->goal[TAE_FOOD] = TOWN_GROWTH_DESERT;
if (FindFirstCargoWithTownAcceptanceEffect(TAE_WATER) != nullptr) t->goal[TAE_WATER] = TOWN_GROWTH_DESERT;
break;
}
}
@ -3366,12 +3380,6 @@ bool AfterLoadGame()
}
}
if (IsSavegameVersionBefore(SLV_178)) {
extern uint8_t _old_diff_level;
/* Initialise script settings profile */
_settings_game.script.settings_profile = IsInsideMM(_old_diff_level, SP_BEGIN, SP_END) ? _old_diff_level : (uint)SP_MEDIUM;
}
/* Station blocked, wires and pylon flags need to be stored in the map.
* This is done here as the SLV_182 check below needs the blocked status. */
UpdateStationTileCacheFlags(SlXvIsFeatureMissing(XSLFI_STATION_TILE_CACHE_FLAGS));
@ -3657,6 +3665,23 @@ bool AfterLoadGame()
_old_timetable_start_subticks_map.clear();
}
if (!IsSavegameVersionBefore(SLV_DEPOT_UNBUNCHING)) {
for (Vehicle *v : Vehicle::Iterate()) {
if (v->unbunch_state != nullptr) {
if (v->unbunch_state->depot_unbunching_last_departure > 0) {
v->unbunch_state->depot_unbunching_last_departure += _state_ticks.base() - _tick_counter;
} else {
v->unbunch_state->depot_unbunching_last_departure = INVALID_STATE_TICKS;
}
if (v->unbunch_state->depot_unbunching_next_departure > 0) {
v->unbunch_state->depot_unbunching_next_departure += _state_ticks.base() - _tick_counter;
} else {
v->unbunch_state->depot_unbunching_next_departure = INVALID_STATE_TICKS;
}
}
}
}
if (SlXvIsFeaturePresent(XSLFI_SPRINGPP, 1, 1)) {
/*
* Cost scaling changes:

@ -164,7 +164,7 @@ const SaveLoadCompat _settings_sl_compat[] = {
SLC_VAR("economy.initial_city_size"),
SLC_VAR("economy.mod_road_rebuild"),
SLC_NULL(1, SL_MIN_VERSION, SLV_107),
SLC_VAR("script.settings_profile"),
SLC_NULL(1, SLV_178, SLV_TABLE_CHUNKS),
SLC_VAR("ai.ai_in_multiplayer"),
SLC_VAR("ai.ai_disable_veh_train"),
SLC_VAR("ai.ai_disable_veh_roadveh"),

@ -1830,7 +1830,7 @@ void ChunkHandler::LoadCheck(size_t len) const
case CH_TABLE:
case CH_SPARSE_TABLE:
SlTableHeader({});
FALLTHROUGH;
[[fallthrough]];
case CH_ARRAY:
case CH_SPARSE_ARRAY:
SlSkipArray();

@ -85,7 +85,7 @@ public:
void Load(Town *t) const override
{
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TE_END : SlGetStructListLength(TE_END);
size_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? (size_t)TAE_END : SlGetStructListLength(TAE_END);
for (size_t i = 0; i < length; i++) {
SlObject(&t->received[i], this->GetLoadDescription());
}
@ -150,12 +150,12 @@ static const SaveLoad _town_desc[] = {
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_9),
SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, SLV_9, SLV_165),
SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_FOOD].old_act, "received[TE_FOOD].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_WATER].old_act, "received[TE_WATER].old_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_FOOD].new_act, "received[TE_FOOD].new_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDVARNAME(Town, received[TAE_WATER].new_act, "received[TE_WATER].new_act", SLE_UINT16, SL_MIN_VERSION, SLV_165),
SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, SLV_165, SL_MAX_VERSION),
SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TAE, SLV_165, SL_MAX_VERSION),
SLE_CONDSSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_168, SL_MAX_VERSION),

@ -44,6 +44,7 @@ static uint32_t _cargo_source_xy;
static uint16_t _cargo_count;
static uint16_t _cargo_paid_for;
static Money _cargo_feeder_share;
static VehicleUnbunchState _unbunch_state;
class SlVehicleCommon : public DefaultSaveLoadHandler<SlVehicleCommon, Vehicle> {
public:
@ -180,6 +181,10 @@ public:
SLE_CONDVAR(Vehicle, current_order_time, SLE_FILE_I32 | SLE_VAR_U32, SLV_TIMETABLE_TICKS_TYPE, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, last_loading_tick, SLE_FILE_U64 | SLE_VAR_I64, SLV_LAST_LOADING_TICK, SL_MAX_VERSION),
SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, SLV_67, SL_MAX_VERSION),
SLEG_CONDVAR("depot_unbunching_last_departure", _unbunch_state.depot_unbunching_last_departure, SLE_UINT64, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION),
SLEG_CONDVAR("depot_unbunching_next_departure", _unbunch_state.depot_unbunching_next_departure, SLE_UINT64, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION),
SLEG_CONDVAR("round_trip_time", _unbunch_state.round_trip_time, SLE_INT32, SLV_DEPOT_UNBUNCHING, SL_MAX_VERSION),
};
#if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
return description;
@ -535,6 +540,11 @@ struct VEHSChunkHandler : ChunkHandler {
v->cargo.Append(cp);
}
if (!IsSavegameVersionBefore(SLV_DEPOT_UNBUNCHING) && _unbunch_state.depot_unbunching_last_departure > 0) {
v->unbunch_state.reset(new VehicleUnbunchState(_unbunch_state));
_unbunch_state = {};
}
#if 0
/* Old savegames used 'last_station_visited = 0xFF' */
if (IsSavegameVersionBefore(SLV_5) && v->last_station_visited == 0xFF) {

@ -33,6 +33,7 @@
* \li AISubsidyList accepts an optional filter function
* \li AITownList accepts an optional filter function
* \li AIVehicleList accepts an optional filter function
* \li AIInfo::AddSettings easy_value / medium_value / hard_value are replaced with default_value
*
* \b 13.0
*

@ -99,6 +99,7 @@
* \li GSSubsidyList accepts an optional filter function
* \li GSTownList accepts an optional filter function
* \li GSVehicleList accepts an optional filter function
* \li GSInfo::AddSettings easy_value / medium_value / hard_value are replaced with default_value
*
* \b 13.0
*

@ -24,7 +24,7 @@
/* static */ bool ScriptCargo::IsValidTownEffect(TownEffect towneffect_type)
{
return (towneffect_type >= (TownEffect)TE_BEGIN && towneffect_type < (TownEffect)TE_END);
return (towneffect_type >= (TownEffect)TAE_BEGIN && towneffect_type < (TownEffect)TAE_END);
}
/* static */ std::optional<std::string> ScriptCargo::GetName(CargoID cargo_type)
@ -66,7 +66,7 @@
{
if (!IsValidCargo(cargo_type)) return TE_NONE;
return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_effect;
return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_acceptance_effect;
}
/* static */ Money ScriptCargo::GetCargoIncome(CargoID cargo_type, SQInteger distance, SQInteger days_in_transit)

@ -43,12 +43,12 @@ public:
*/
enum TownEffect {
/* Note: these values represent part of the in-game TownEffect enum */
TE_NONE = ::TE_NONE, ///< This cargo has no effect on a town
TE_PASSENGERS = ::TE_PASSENGERS, ///< This cargo supplies passengers to a town
TE_MAIL = ::TE_MAIL, ///< This cargo supplies mail to a town
TE_GOODS = ::TE_GOODS, ///< This cargo supplies goods to a town
TE_WATER = ::TE_WATER, ///< This cargo supplies water to a town
TE_FOOD = ::TE_FOOD, ///< This cargo supplies food to a town
TE_NONE = ::TAE_NONE, ///< This cargo has no effect on a town
TE_PASSENGERS = ::TAE_PASSENGERS, ///< This cargo supplies passengers to a town
TE_MAIL = ::TAE_MAIL, ///< This cargo supplies mail to a town
TE_GOODS = ::TAE_GOODS, ///< This cargo supplies goods to a town
TE_WATER = ::TAE_WATER, ///< This cargo supplies water to a town
TE_FOOD = ::TAE_FOOD, ///< This cargo supplies food to a town
};
/**

@ -38,7 +38,7 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S
case TEXT_TAB_SPECIAL:
if (index < 0xE4) break; // Player name
FALLTHROUGH;
[[fallthrough]];
case TEXT_TAB_TOWN:
if (index < 0xC0) break; // Town name

@ -222,18 +222,8 @@ public:
* - max_value The maximum value of this setting. Required for integer
* settings and not allowed for boolean settings. The value will be
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - easy_value The default value if the easy difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32_t), MAX(int32_t)] (inclusive).
* - medium_value The default value if the medium difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32_t), MAX(int32_t)] (inclusive).
* - hard_value The default value if the hard difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32_t), MAX(int32_t)] (inclusive).
* - custom_value The default value if the custom difficulty level
* is selected. Required. The value will be clamped in the range
* [MIN(int32_t), MAX(int32_t)] (inclusive).
* - default_value The default value. Required. The value will be
* clamped in the range [MIN(int32_t), MAX(int32_t)] (inclusive).
* - random_deviation If this property has a nonzero value, then the
* actual value of the setting in game will be randomised in the range
* [user_configured_value - random_deviation, user_configured_value + random_deviation] (inclusive).

@ -148,13 +148,13 @@ void CargoCollector::Update(StationID from, StationID via, uint amount)
switch (Tselector) {
case ScriptStationList_Cargo::CS_VIA_BY_FROM:
if (via != this->other_station) return;
FALLTHROUGH;
[[fallthrough]];
case ScriptStationList_Cargo::CS_BY_FROM:
key = from;
break;
case ScriptStationList_Cargo::CS_FROM_BY_VIA:
if (from != this->other_station) return;
FALLTHROUGH;
[[fallthrough]];
case ScriptStationList_Cargo::CS_BY_VIA:
key = via;
break;

@ -20,7 +20,7 @@ ScriptTownList::ScriptTownList(HSQUIRRELVM vm)
ScriptTownEffectList::ScriptTownEffectList()
{
for (int i = TE_BEGIN; i < TE_END; i++) {
for (int i = TAE_BEGIN; i < TAE_END; i++) {
this->AddItem(i);
}
}

@ -37,10 +37,7 @@ struct ScriptConfigItem {
std::string description; ///< The description of the configuration setting.
int min_value = 0; ///< The minimal value this configuration setting can have.
int max_value = 1; ///< The maximal value this configuration setting can have.
int custom_value = 0; ///< The default value on custom difficulty setting.
int easy_value = 0; ///< The default value on easy difficulty setting.
int medium_value = 0; ///< The default value on medium difficulty setting.
int hard_value = 0; ///< The default value on hard difficulty setting.
int default_value = 0; ///< The default value of this configuration setting.
int random_deviation = 0; ///< The maximum random deviation from the default value.
int step_size = 1; ///< The step size in the gui.
ScriptConfigFlags flags = SCRIPTCONFIG_NONE; ///< Flags for the configuration setting.

@ -87,6 +87,10 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
ScriptConfigItem config;
uint items = 0;
int easy_value = INT32_MIN;
int medium_value = INT32_MIN;
int hard_value = INT32_MIN;
/* Read the table, and find all properties we care about */
sq_pushnull(vm);
while (SQ_SUCCEEDED(sq_next(vm, -2))) {
@ -122,28 +126,30 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
} else if (key == "easy_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.easy_value = ClampTo<int32_t>(res);
easy_value = ClampTo<int32_t>(res);
items |= 0x010;
} else if (key == "medium_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.medium_value = ClampTo<int32_t>(res);
medium_value = ClampTo<int32_t>(res);
items |= 0x020;
} else if (key == "hard_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.hard_value = ClampTo<int32_t>(res);
hard_value = ClampTo<int32_t>(res);
items |= 0x040;
} else if (key == "custom_value") {
// No longer parsed.
} else if (key == "default_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.default_value = ClampTo<int32_t>(res);
items |= 0x080;
} else if (key == "random_deviation") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.random_deviation = ClampTo<int32_t>(abs(res));
items |= 0x200;
} else if (key == "custom_value") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
config.custom_value = ClampTo<int32_t>(res);
items |= 0x080;
} else if (key == "step_size") {
SQInteger res;
if (SQ_FAILED(sq_getinteger(vm, -1, &res))) return SQ_ERROR;
@ -162,6 +168,28 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
}
sq_pop(vm, 1);
/* Check if default_value is set. Although required, this was changed with
* 14.0, and as such, older AIs don't use it yet. So we convert the older
* values into a default_value. */
if ((items & 0x080) == 0) {
/* Easy/medium/hard should all three be defined. */
if ((items & 0x010) == 0 || (items & 0x020) == 0 || (items & 0x040) == 0) {
this->engine->ThrowError("please define all properties of a setting (min/max not allowed for booleans)");
return SQ_ERROR;
}
config.default_value = medium_value;
/* If not boolean and no random deviation set, calculate it based on easy/hard difference. */
if ((config.flags & SCRIPTCONFIG_BOOLEAN) == 0 && (items & 0x200) == 0) {
config.random_deviation = abs(hard_value - easy_value) / 2;
items |= 0x200;
}
items |= 0x080;
} else {
/* For compatibility, also act like the default sets the easy/medium/hard. */
items |= 0x010 | 0x020 | 0x040;
}
/* Don't allow both random_deviation and SCRIPTCONFIG_BOOLEAN to
* be set for the same config item. */
if ((items & 0x200) != 0 && (config.flags & SCRIPTCONFIG_BOOLEAN) != 0) {
@ -252,14 +280,7 @@ int ScriptInfo::GetSettingDefaultValue(const std::string &name) const
{
for (const auto &item : this->config_list) {
if (item.name != name) continue;
/* The default value depends on the difficulty level */
switch (GetGameSettings().script.settings_profile) {
case SP_EASY: return item.easy_value;
case SP_MEDIUM: return item.medium_value;
case SP_HARD: return item.hard_value;
case SP_CUSTOM: return item.custom_value;
default: NOT_REACHED();
}
return item.default_value;
}
/* There is no such setting */

@ -315,7 +315,7 @@ static int ParseIntList(const char *p, T *items, size_t maxitems)
/* Do not accept multiple commas between numbers */
if (!comma) return -1;
comma = false;
FALLTHROUGH;
[[fallthrough]];
case ' ':
p++;

@ -2695,7 +2695,6 @@ static SettingsContainer &GetSettingsTree()
{
SettingsPage *npc = ai->Add(new SettingsPage(STR_CONFIG_SETTING_AI_NPC));
{
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"));

@ -565,7 +565,6 @@ struct AISettings {
/** Settings related to scripts. */
struct ScriptSettings {
uint8_t settings_profile; ///< difficulty profile to set initial settings of scripts, esp. random AIs
uint32_t script_max_opcode_till_suspend; ///< max opcode calls till scripts will suspend
uint32_t script_max_memory_megabytes; ///< limit on memory a single script instance may have allocated
};

@ -28,7 +28,7 @@
* @param s Format string.
* @note Function does not return.
*/
void NORETURN CDECL error(const char *s, ...)
[[noreturn]] void CDECL error(const char *s, ...)
{
char buf[1024];
va_list va;

@ -31,7 +31,7 @@ static_assert((SHIP_PATH_CACHE_LENGTH & SHIP_PATH_CACHE_MASK) == 0, ""); // Must
/**
* All ships have this type.
*/
struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
struct Ship final : public SpecializedVehicle<Ship, VEH_SHIP> {
TrackBits state; ///< The "track" the ship is following.
ShipPathCache cached_path; ///< Cached path.
Direction rotation; ///< Visible direction.

@ -451,6 +451,9 @@ static bool CheckShipLeaveDepot(Ship *v)
return true;
}
/* Check if we should wait here for unbunching. */
if (v->IsWaitingForUnbunching()) return true;
/* We are leaving a depot, but have to go to the exact same one; re-enter */
if (v->current_order.IsType(OT_GOTO_DEPOT) &&
IsShipDepotTile(v->tile) && GetDepotIndex(v->tile) == v->current_order.GetDestination()) {
@ -498,8 +501,9 @@ static bool CheckShipLeaveDepot(Ship *v)
v->UpdateViewport(true, true);
SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
v->PlayLeaveStationSound();
VehicleServiceInDepot(v);
v->LeaveUnbunchingDepot();
v->PlayLeaveStationSound();
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
DirtyVehicleListWindowForVehicle(v);

@ -68,6 +68,35 @@ static const TrackdirBits _enterdir_to_trackdirbits[DIAGDIR_END] = {
TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S
};
SignalType NextSignalType(SignalType cur, SignalCycleGroups which_signals)
{
if (_settings_game.vehicle.train_braking_model == TBM_REALISTIC) {
switch (cur) {
case SIGTYPE_PBS: return SIGTYPE_PBS_ONEWAY;
case SIGTYPE_PBS_ONEWAY: return SIGTYPE_BLOCK;
default: return SIGTYPE_PBS;
}
}
if (which_signals == SCG_CURRENT_GROUP) which_signals = IsPbsSignal(cur) ? SCG_PBS : SCG_BLOCK;
bool pbs = which_signals & SCG_PBS;
bool block = which_signals & SCG_BLOCK;
switch(cur) {
case SIGTYPE_BLOCK: return block ? SIGTYPE_ENTRY : SIGTYPE_PBS;
case SIGTYPE_ENTRY: return block ? SIGTYPE_EXIT : SIGTYPE_PBS;
case SIGTYPE_EXIT: return block ? SIGTYPE_COMBO : SIGTYPE_PBS;
case SIGTYPE_COMBO: return pbs ? SIGTYPE_PBS : SIGTYPE_BLOCK;
case SIGTYPE_PROG: return pbs ? SIGTYPE_PBS : SIGTYPE_BLOCK;
case SIGTYPE_PBS: return pbs ? SIGTYPE_PBS_ONEWAY : SIGTYPE_BLOCK;
case SIGTYPE_PBS_ONEWAY: return block ? SIGTYPE_BLOCK : SIGTYPE_PBS;
case SIGTYPE_NO_ENTRY: return pbs ? SIGTYPE_PBS : SIGTYPE_BLOCK;
default:
DEBUG(map, 0, "Attempt to cycle from signal type %d", cur);
return SIGTYPE_BLOCK; // Fortunately mostly harmless
}
}
/**
* Set containing 'items' items of 'tile and Tdir'
* No tree structure is used because it would cause
@ -956,7 +985,7 @@ static SigSegState UpdateSignalsInBuffer(Owner owner)
break;
}
}
FALLTHROUGH;
[[fallthrough]];
case MP_RAILWAY:
if (IsRailDepotTile(tile)) {
@ -965,7 +994,7 @@ static SigSegState UpdateSignalsInBuffer(Owner owner)
_tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside
break;
}
FALLTHROUGH;
[[fallthrough]];
case MP_STATION:
case MP_ROAD:
@ -975,7 +1004,7 @@ static SigSegState UpdateSignalsInBuffer(Owner owner)
_tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir));
break;
}
FALLTHROUGH;
[[fallthrough]];
default:
/* jump to next tile */

@ -129,25 +129,7 @@ inline bool IsSignalSpritePBS(SignalType type)
return type >= SIGTYPE_FIRST_PBS_SPRITE;
}
inline SignalType NextSignalType(SignalType cur, uint which_signals)
{
bool pbs = true;
bool block = (which_signals == SIGNAL_CYCLE_ALL);
switch(cur) {
case SIGTYPE_BLOCK: return block ? SIGTYPE_ENTRY : SIGTYPE_PBS;
case SIGTYPE_ENTRY: return block ? SIGTYPE_EXIT : SIGTYPE_PBS;
case SIGTYPE_EXIT: return block ? SIGTYPE_COMBO : SIGTYPE_PBS;
case SIGTYPE_COMBO: return pbs ? SIGTYPE_PBS : SIGTYPE_BLOCK;
case SIGTYPE_PROG: return pbs ? SIGTYPE_PBS : SIGTYPE_BLOCK;
case SIGTYPE_PBS: return pbs ? SIGTYPE_PBS_ONEWAY : SIGTYPE_BLOCK;
case SIGTYPE_PBS_ONEWAY: return block ? SIGTYPE_BLOCK : SIGTYPE_PBS;
case SIGTYPE_NO_ENTRY: return pbs ? SIGTYPE_PBS : SIGTYPE_BLOCK;
default:
DEBUG(map, 0, "Attempt to cycle from signal type %d", cur);
return SIGTYPE_BLOCK; // Fortunately mostly harmless
}
}
SignalType NextSignalType(SignalType cur, SignalCycleGroups which_signals);
/** State of the signal segment */
enum SigSegState {

@ -66,6 +66,14 @@ enum SignalState {
SIGNAL_STATE_MAX = SIGNAL_STATE_GREEN,
};
/** Signal groups to cycle through. */
enum SignalCycleGroups : uint8_t {
SCG_CURRENT_GROUP = 0,
SCG_BLOCK = 1 << 0,
SCG_PBS = 1 << 1,
};
DECLARE_ENUM_AS_BIT_SET(SignalCycleGroups)
static const int SIGNAL_DIRTY_LEFT = 14 * ZOOM_LVL_BASE;
static const int SIGNAL_DIRTY_RIGHT = 14 * ZOOM_LVL_BASE;
static const int SIGNAL_DIRTY_TOP = 30 * ZOOM_LVL_BASE;

@ -522,7 +522,7 @@ struct SignWindow : Window, SignList {
case WID_QES_OK:
if (RenameSign(this->cur_sign, this->name_editbox.text.buf)) break;
FALLTHROUGH;
[[fallthrough]];
case WID_QES_CANCEL:
this->Close();

@ -196,7 +196,7 @@ void AfterLoadCompanyStats()
}
}
}
FALLTHROUGH;
[[fallthrough]];
case MP_OBJECT:
if (GetWaterClass(tile) == WATER_CLASS_CANAL) {

@ -209,6 +209,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_NEWGRF_LAST_SERVICE, XSCF_NULL, 1, 1, "slv_newgrf_last_service", nullptr, nullptr, nullptr },
{ XSLFI_CARGO_TRAVELLED, XSCF_NULL, 1, 1, "slv_cargo_travelled", nullptr, nullptr, nullptr },
{ XSLFI_SHIP_ACCELERATION, XSCF_NULL, 1, 1, "slv_ship_acceleration", nullptr, nullptr, nullptr },
{ XSLFI_DEPOT_UNBUNCHING, XSCF_NULL, 1, 1, "slv_depot_unbunching", nullptr, nullptr, "VUBS" },
{ XSLFI_TABLE_PATS, XSCF_NULL, 1, 1, "table_pats", nullptr, nullptr, nullptr },
{ XSLFI_TABLE_MISC_SL, XSCF_NULL, 1, 1, "table_misc_sl", nullptr, nullptr, nullptr },

@ -158,6 +158,7 @@ enum SlXvFeatureIndex {
XSLFI_NEWGRF_LAST_SERVICE, ///< See: SLV_NEWGRF_LAST_SERVICE (PR #11124)
XSLFI_CARGO_TRAVELLED, ///< See: SLV_CARGO_TRAVELLED (PR #11283)
XSLFI_SHIP_ACCELERATION, ///< See: SLV_SHIP_ACCELERATION (PR #10734)
XSLFI_DEPOT_UNBUNCHING, ///< See: SLV_DEPOT_UNBUNCHING (PR #11945)
XSLFI_TABLE_PATS, ///< Use upstream table format for PATS
XSLFI_TABLE_MISC_SL, ///< Use upstream table format for miscellaneous chunks, so far: DATE, VIEW, MAPS

@ -600,10 +600,10 @@ static const OldChunks town_chunk[] = {
OCL_NULL( 2 ), ///< pct_pass_transported / pct_mail_transported, now computed on the fly
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_FOOD].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_WATER].new_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_FOOD].old_act ),
OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TAE_WATER].old_act ),
OCL_SVAR( OC_UINT8, Town, road_build_months ),
OCL_SVAR( OC_UINT8, Town, fund_buildings_months ),

@ -412,7 +412,7 @@ struct ThreadSlErrorException {
* @note This function does never return as it throws an exception to
* break out of all the saveload code.
*/
void NORETURN SlError(StringID string, std::string extra_msg)
[[noreturn]] void SlError(StringID string, std::string extra_msg)
{
if (IsNonMainThread() && IsNonGameThread() && _sl.action != SLA_SAVE) {
throw ThreadSlErrorException{ string, std::move(extra_msg) };
@ -442,7 +442,7 @@ void NORETURN SlError(StringID string, std::string extra_msg)
/**
* As SlError, except that it takes a format string and additional parameters
*/
void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...)
[[noreturn]] void CDECL SlErrorFmt(StringID string, const char *msg, ...)
{
va_list va;
va_start(va, msg);
@ -458,7 +458,7 @@ void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...)
* @note This function does never return as it throws an exception to
* break out of all the saveload code.
*/
void NORETURN SlErrorCorrupt(std::string msg)
[[noreturn]] void SlErrorCorrupt(std::string msg)
{
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, std::move(msg));
}
@ -470,7 +470,7 @@ void NORETURN SlErrorCorrupt(std::string msg)
* @note This function does never return as it throws an exception to
* break out of all the saveload code.
*/
void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...)
[[noreturn]] void CDECL SlErrorCorruptFmt(const char *format, ...)
{
va_list va;
va_start(va, format);

@ -1067,7 +1067,7 @@ inline void SlLoadTableOrRiffFiltered(const NamedSaveLoadTable &slt)
SlLoadTableOrRiffFiltered(SlTableHeaderOrRiff(slt));
}
void NORETURN CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3);
[[noreturn]] void CDECL SlErrorFmt(StringID string, const char *msg, ...) WARN_FORMAT(2, 3);
bool SaveloadCrashWithMissingNewGRFs();

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save