diff --git a/changelog.txt b/changelog.txt index b4eba4995e..93f314b3df 100644 --- a/changelog.txt +++ b/changelog.txt @@ -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) diff --git a/src/3rdparty/squirrel/squirrel/sqcompiler.cpp b/src/3rdparty/squirrel/squirrel/sqcompiler.cpp index 57ca40ac06..e30495f65c 100644 --- a/src/3rdparty/squirrel/squirrel/sqcompiler.cpp +++ b/src/3rdparty/squirrel/squirrel/sqcompiler.cpp @@ -56,24 +56,26 @@ typedef sqvector 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; } } diff --git a/src/3rdparty/squirrel/squirrel/sqcompiler.h b/src/3rdparty/squirrel/squirrel/sqcompiler.h index 08946fb60c..cdb6b1d65c 100644 --- a/src/3rdparty/squirrel/squirrel/sqcompiler.h +++ b/src/3rdparty/squirrel/squirrel/sqcompiler.h @@ -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_ diff --git a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp index 7111a79e90..7719133cd1 100644 --- a/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp +++ b/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp @@ -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; } diff --git a/src/3rdparty/squirrel/squirrel/sqfuncstate.h b/src/3rdparty/squirrel/squirrel/sqfuncstate.h index c0bf1e5e9e..739eb16261 100644 --- a/src/3rdparty/squirrel/squirrel/sqfuncstate.h +++ b/src/3rdparty/squirrel/squirrel/sqfuncstate.h @@ -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 _childstates; SQInteger GetConstant(const SQObject &cons); -private: - CompilerErrorFunc _errfunc; - void *_errtarget; }; diff --git a/src/3rdparty/squirrel/squirrel/sqlexer.cpp b/src/3rdparty/squirrel/squirrel/sqlexer.cpp index e91e9ecc52..96e43f4af7 100644 --- a/src/3rdparty/squirrel/squirrel/sqlexer.cpp +++ b/src/3rdparty/squirrel/squirrel/sqlexer.cpp @@ -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() diff --git a/src/3rdparty/squirrel/squirrel/sqlexer.h b/src/3rdparty/squirrel/squirrel/sqlexer.h index 3a4e76b339..9ce9469b24 100644 --- a/src/3rdparty/squirrel/squirrel/sqlexer.h +++ b/src/3rdparty/squirrel/squirrel/sqlexer.h @@ -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 _longstr; - CompilerErrorFunc _errfunc; - void *_errtarget; }; #endif diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp index ad914ee57e..de686e1927 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.cpp +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -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; diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index d4d5a7e192..28c2f8adc1 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -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; } diff --git a/src/aircraft.h b/src/aircraft.h index d45d63cc5f..aa48b98869 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -73,7 +73,7 @@ struct AircraftCache { /** * Aircraft, helicopters, rotors and their shadows belong to this class. */ -struct Aircraft FINAL : public SpecializedVehicle { +struct Aircraft final : public SpecializedVehicle { 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. diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index a331f35972..8827197ef6 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -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; diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 958f3d18e4..ec1c8e94b9 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -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 */ diff --git a/src/blitter/32bpp_anim_sse4.hpp b/src/blitter/32bpp_anim_sse4.hpp index e5a143e394..66960f2dc3 100644 --- a/src/blitter/32bpp_anim_sse4.hpp +++ b/src/blitter/32bpp_anim_sse4.hpp @@ -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: diff --git a/src/blitter/8bpp_optimized.hpp b/src/blitter/8bpp_optimized.hpp index 62cc2e9ef5..17579f5740 100644 --- a/src/blitter/8bpp_optimized.hpp +++ b/src/blitter/8bpp_optimized.hpp @@ -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 { diff --git a/src/blitter/8bpp_simple.hpp b/src/blitter/8bpp_simple.hpp index 2803537a31..83abef641e 100644 --- a/src/blitter/8bpp_simple.hpp +++ b/src/blitter/8bpp_simple.hpp @@ -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; diff --git a/src/cargotype.cpp b/src/cargotype.cpp index 591dec97ce..894b685096 100644 --- a/src/cargotype.cpp +++ b/src/cargotype.cpp @@ -23,6 +23,7 @@ #include "safeguards.h" CargoSpec CargoSpec::array[NUM_CARGO]; +std::array, 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()); diff --git a/src/cargotype.h b/src/cargotype.h index 5386d34949..0756b49ca9 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -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, NUM_TPE> town_production_cargoes; + private: static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs diff --git a/src/company_gui.cpp b/src/company_gui.cpp index fc56f07edb..352d095968 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -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: diff --git a/src/console.cpp b/src/console.cpp index cc86a8f725..43fd18063c 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -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; diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index a7de3ed67b..5a3ecfd54e 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -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; diff --git a/src/core/alloc_func.cpp b/src/core/alloc_func.cpp index 86ba76623f..637e815a21 100644 --- a/src/core/alloc_func.cpp +++ b/src/core/alloc_func.cpp @@ -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); } diff --git a/src/core/alloc_func.hpp b/src/core/alloc_func.hpp index 94a05b6477..e4dd366faa 100644 --- a/src/core/alloc_func.hpp +++ b/src/core/alloc_func.hpp @@ -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. diff --git a/src/core/pool_func.hpp b/src/core/pool_func.hpp index b84dd067fa..a2cbb3af73 100644 --- a/src/core/pool_func.hpp +++ b/src/core/pool_func.hpp @@ -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); diff --git a/src/date_type.h b/src/date_type.h index ea6c1eb62f..9bd4f75f41 100644 --- a/src/date_type.h +++ b/src/date_type.h @@ -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 */ diff --git a/src/debug_fmt.h b/src/debug_fmt.h index b2a81c524d..cb965dd61a 100644 --- a/src/debug_fmt.h +++ b/src/debug_fmt.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()) diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index 86e44feef9..6c79ad497e 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -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; diff --git a/src/disaster_vehicle.h b/src/disaster_vehicle.h index 35bced0bda..3a55b0db55 100644 --- a/src/disaster_vehicle.h +++ b/src/disaster_vehicle.h @@ -34,7 +34,7 @@ enum DisasterSubType { /** * Disasters, like submarines, skyrangers and their shadows, belong to this class. */ -struct DisasterVehicle FINAL : public SpecializedVehicle { +struct DisasterVehicle final : public SpecializedVehicle { 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 diff --git a/src/economy.cpp b/src/economy.cpp index 6da700532c..1cb9e404d2 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -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); diff --git a/src/effectvehicle_base.h b/src/effectvehicle_base.h index 5164f36454..a5d95c9561 100644 --- a/src/effectvehicle_base.h +++ b/src/effectvehicle_base.h @@ -21,7 +21,7 @@ * - bulldozer (road works) * - bubbles (industry) */ -struct EffectVehicle FINAL : public SpecializedVehicle { +struct EffectVehicle final : public SpecializedVehicle { 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. diff --git a/src/elrail.cpp b/src/elrail.cpp index 2b05835773..4a39b11f0f 100644 --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -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; diff --git a/src/engine_gui.cpp b/src/engine_gui.cpp index 8b7a0e896f..592113845f 100644 --- a/src/engine_gui.cpp +++ b/src/engine_gui.cpp @@ -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; diff --git a/src/fileio.cpp b/src/fileio.cpp index 23ddecb220..d353fc6869 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -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; diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 2ac1913941..dd9e383eed 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -886,7 +886,7 @@ public: /* We reset the files filtered */ this->OnInvalidateData(SLIWD_FILTER_CHANGES); - FALLTHROUGH; + [[fallthrough]]; case SLIWD_SELECTION_CHANGES: /* Selection changes */ diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 21002efd5a..4a3c00281e 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -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; diff --git a/src/gui.h b/src/gui.h index e7c1a19332..656c20a32d 100644 --- a/src/gui.h +++ b/src/gui.h @@ -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); diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index d08d47e6f6..475b398e53 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -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; } diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index 310f634de9..7f82a2bbf0 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -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 diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 65e4a5b941..64b0a8a95a 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -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(); diff --git a/src/music/extmidi.cpp b/src/music/extmidi.cpp index 1ab8ff42ed..e40d565e02 100644 --- a/src/music/extmidi.cpp +++ b/src/music/extmidi.cpp @@ -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(); diff --git a/src/network/core/network_game_info.cpp b/src/network/core/network_game_info.cpp index fe95d61999..fd823aa326 100644 --- a/src/network/core/network_game_info.cpp +++ b/src/network/core/network_game_info.cpp @@ -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); diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index b6802e9f8c..92bf9f608d 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -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(); diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 35278796a3..3aa375f58c 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -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; diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index c73499bd30..d79f6c5570 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -898,7 +898,7 @@ public: return ES_HANDLED; } /* space is pressed and filter is focused. */ - FALLTHROUGH; + [[fallthrough]]; default: return ES_NOT_HANDLED; diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 4b9dc4fdf9..872550efb4 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -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(); diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 2ea4180029..cf57175cd6 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -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: diff --git a/src/newgrf.cpp b/src/newgrf.cpp index e1a7b0b166..1667fef6d8 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -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(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(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(); @@ -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; diff --git a/src/newgrf_airport.h b/src/newgrf_airport.h index c2425f317e..0517e35dfa 100644 --- a/src/newgrf_airport.h +++ b/src/newgrf_airport.h @@ -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); } diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 38e3247d90..ab5cbb60f0 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -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(); diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 1fbd0c14d3..e1b7805826 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -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 diff --git a/src/newgrf_industries.h b/src/newgrf_industries.h index 5d5a05dfa6..ef658b6e63 100644 --- a/src/newgrf_industries.h +++ b/src/newgrf_industries.h @@ -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); diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index 0bacda3648..7192bbc1ad 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -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); diff --git a/src/newgrf_object.h b/src/newgrf_object.h index 6e2d1b4d51..669bdd0596 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -184,7 +184,7 @@ struct ObjectResolverObject : public ResolverObject { case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); if (tsr != nullptr) return tsr; - FALLTHROUGH; + [[fallthrough]]; } default: diff --git a/src/newgrf_roadstop.h b/src/newgrf_roadstop.h index 70bb099c09..a664d9c30c 100644 --- a/src/newgrf_roadstop.h +++ b/src/newgrf_roadstop.h @@ -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); } diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 9912e03624..f8ce650ae9 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -76,7 +76,7 @@ struct StationResolverObject : public ResolverObject { case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); if (tsr != nullptr) return tsr; - FALLTHROUGH; + [[fallthrough]]; } default: diff --git a/src/newgrf_town.cpp b/src/newgrf_town.cpp index abec5c22fc..665b21e07b 100644 --- a/src/newgrf_town.cpp +++ b/src/newgrf_town.cpp @@ -99,14 +99,14 @@ case 0xC9: return GB(ClampTo(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; diff --git a/src/openttd.cpp b/src/openttd.cpp index 51559beb8f..c68536eacf 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -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 _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); diff --git a/src/order_base.h b/src/order_base.h index 51d88a8b9c..13644f2db3 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -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. */ diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 88914778a6..61354a49b7 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -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; diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 6f22a0b7c4..2ddd5007bd 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -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(WID_O_DEPOT_ACTION); nwid != nullptr) { + nwid->tool_tip = STR_ORDER_TRAIN_DEPOT_ACTION_TOOLTIP + v->type; + } this->GetWidget(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(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(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. */ diff --git a/src/order_type.h b/src/order_type.h index 0c6626d304..8d2d36ebed 100644 --- a/src/order_type.h +++ b/src/order_type.h @@ -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 }; diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index 8963cb61a0..5902486c67 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -237,7 +237,7 @@ void ShowOSErrorBox(const char *buf, bool) } } -void NORETURN DoOSAbort() +[[noreturn]] void DoOSAbort() { abort(); } diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index e43729b9fb..9029204486 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -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); diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index fd9a12c94a..fcadf10784 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -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); diff --git a/src/pathfinder/yapf/yapf_destrail.hpp b/src/pathfinder/yapf/yapf_destrail.hpp index 3b5a2fb58b..e4bb15f0e8 100644 --- a/src/pathfinder/yapf/yapf_destrail.hpp +++ b/src/pathfinder/yapf/yapf_destrail.hpp @@ -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; diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 5f28637b2b..ba2c985081 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -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; diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 0d48096857..82a1d59a79 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -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(_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 */ diff --git a/src/rail_gui_type.h b/src/rail_gui_type.h index f1f1f1b804..eadb9ceb65 100644 --- a/src/rail_gui_type.h +++ b/src/rail_gui_type.h @@ -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 */ diff --git a/src/roadveh.h b/src/roadveh.h index 69cfe6a025..d3f8ecbc1e 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -139,7 +139,7 @@ enum RoadVehicleFlags { /** * Buses, trucks and trams belong to this class. */ -struct RoadVehicle FINAL : public GroundVehicle { +struct RoadVehicle final : public GroundVehicle { byte state; ///< @see RoadVehicleStates byte frame; uint16_t blocked_ctr; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 0e1e20f901..093d0a0f25 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -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; { diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index edb25f4577..2ed2fd8813 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -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: diff --git a/src/saveload/compat/settings_sl_compat.h b/src/saveload/compat/settings_sl_compat.h index 36b9976dfd..f286ce6fd8 100644 --- a/src/saveload/compat/settings_sl_compat.h +++ b/src/saveload/compat/settings_sl_compat.h @@ -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"), diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index e41cff950f..00b2c01559 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -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(); diff --git a/src/saveload/town_sl.cpp b/src/saveload/town_sl.cpp index 19e3da4574..474528b65a 100644 --- a/src/saveload/town_sl.cpp +++ b/src/saveload/town_sl.cpp @@ -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), diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index 45a2fa5cf6..d0d40c5e74 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -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 { 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) { diff --git a/src/script/api/ai_changelog.hpp b/src/script/api/ai_changelog.hpp index 4bc5b5d18b..96f4bc32a6 100644 --- a/src/script/api/ai_changelog.hpp +++ b/src/script/api/ai_changelog.hpp @@ -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 * diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index 44d9ac0308..810bea83e2 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -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 * diff --git a/src/script/api/script_cargo.cpp b/src/script/api/script_cargo.cpp index e137a6766b..c00c7df464 100644 --- a/src/script/api/script_cargo.cpp +++ b/src/script/api/script_cargo.cpp @@ -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 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) diff --git a/src/script/api/script_cargo.hpp b/src/script/api/script_cargo.hpp index ffbf488845..5ad4b5851e 100644 --- a/src/script/api/script_cargo.hpp +++ b/src/script/api/script_cargo.hpp @@ -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 }; /** diff --git a/src/script/api/script_error.cpp b/src/script/api/script_error.cpp index 3d365c23bb..1d18ef112a 100644 --- a/src/script/api/script_error.cpp +++ b/src/script/api/script_error.cpp @@ -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 diff --git a/src/script/api/script_info_docs.hpp b/src/script/api/script_info_docs.hpp index 7a884dc824..8278f39f19 100644 --- a/src/script/api/script_info_docs.hpp +++ b/src/script/api/script_info_docs.hpp @@ -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). diff --git a/src/script/api/script_stationlist.cpp b/src/script/api/script_stationlist.cpp index 8f6a24db46..26c0ca1e1b 100644 --- a/src/script/api/script_stationlist.cpp +++ b/src/script/api/script_stationlist.cpp @@ -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; diff --git a/src/script/api/script_townlist.cpp b/src/script/api/script_townlist.cpp index ec9a81f3f4..e9ef63e9ac 100644 --- a/src/script/api/script_townlist.cpp +++ b/src/script/api/script_townlist.cpp @@ -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); } } diff --git a/src/script/script_config.hpp b/src/script/script_config.hpp index ab9a7def51..b81b50966b 100644 --- a/src/script/script_config.hpp +++ b/src/script/script_config.hpp @@ -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. diff --git a/src/script/script_info.cpp b/src/script/script_info.cpp index 10031519d6..21807aaff4 100644 --- a/src/script/script_info.cpp +++ b/src/script/script_info.cpp @@ -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(res); + easy_value = ClampTo(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(res); + medium_value = ClampTo(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(res); + hard_value = ClampTo(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(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(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(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 */ diff --git a/src/settings.cpp b/src/settings.cpp index 7ec3439623..7abc3faf0d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -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++; diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 421f1db65c..6e75182de4 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -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")); diff --git a/src/settings_type.h b/src/settings_type.h index b04c369261..52d35b9bcc 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -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 }; diff --git a/src/settingsgen/settingsgen.cpp b/src/settingsgen/settingsgen.cpp index d9146da017..60b61364c7 100644 --- a/src/settingsgen/settingsgen.cpp +++ b/src/settingsgen/settingsgen.cpp @@ -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; diff --git a/src/ship.h b/src/ship.h index 6ccd4329d1..9a43e7b644 100644 --- a/src/ship.h +++ b/src/ship.h @@ -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 { +struct Ship final : public SpecializedVehicle { TrackBits state; ///< The "track" the ship is following. ShipPathCache cached_path; ///< Cached path. Direction rotation; ///< Visible direction. diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index fa102b9b05..0ac0967800 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -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); diff --git a/src/signal.cpp b/src/signal.cpp index f8bdba199d..53daf1bdf2 100644 --- a/src/signal.cpp +++ b/src/signal.cpp @@ -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 */ diff --git a/src/signal_func.h b/src/signal_func.h index b350d9f8c0..35cb55fc06 100644 --- a/src/signal_func.h +++ b/src/signal_func.h @@ -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 { diff --git a/src/signal_type.h b/src/signal_type.h index fe0f0817c4..d55bc710fa 100644 --- a/src/signal_type.h +++ b/src/signal_type.h @@ -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; diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 5eed6ac481..7d5884243d 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -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(); diff --git a/src/sl/company_sl.cpp b/src/sl/company_sl.cpp index db2bde4971..cfd25c5a56 100644 --- a/src/sl/company_sl.cpp +++ b/src/sl/company_sl.cpp @@ -196,7 +196,7 @@ void AfterLoadCompanyStats() } } } - FALLTHROUGH; + [[fallthrough]]; case MP_OBJECT: if (GetWaterClass(tile) == WATER_CLASS_CANAL) { diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 5fdd73d213..06db27cd25 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -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 }, diff --git a/src/sl/extended_ver_sl.h b/src/sl/extended_ver_sl.h index cbe6926248..c829605a92 100644 --- a/src/sl/extended_ver_sl.h +++ b/src/sl/extended_ver_sl.h @@ -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 diff --git a/src/sl/oldloader_sl.cpp b/src/sl/oldloader_sl.cpp index 3f69b1d60f..2a836ee071 100644 --- a/src/sl/oldloader_sl.cpp +++ b/src/sl/oldloader_sl.cpp @@ -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 ), diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 95e6a8fa5a..8b1c81294a 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -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); diff --git a/src/sl/saveload.h b/src/sl/saveload.h index 7892bdaa62..1a5502e3f2 100644 --- a/src/sl/saveload.h +++ b/src/sl/saveload.h @@ -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(); diff --git a/src/sl/saveload_common.h b/src/sl/saveload_common.h index c355b0768c..36e86f7453 100644 --- a/src/sl/saveload_common.h +++ b/src/sl/saveload_common.h @@ -385,6 +385,7 @@ enum SaveLoadVersion : uint16_t { SLV_CALENDAR_SUB_DATE_FRACT, ///< 328 PR#11428 Add sub_date_fract to measure calendar days. SLV_SHIP_ACCELERATION, ///< 329 PR#10734 Start using Vehicle's acceleration field for ships too. SLV_MAX_LOAN_FOR_COMPANY, ///< 330 PR#11224 Separate max loan for each company. + SLV_DEPOT_UNBUNCHING, ///< 331 PR#11945 Allow unbunching shared order vehicles at a depot. SL_MAX_VERSION, ///< Highest possible saveload version @@ -429,9 +430,9 @@ void SlSkipBytes(size_t length); size_t SlGetBytesRead(); size_t SlGetBytesWritten(); -void NORETURN SlError(StringID string, std::string extra_msg = {}); -void NORETURN SlErrorCorrupt(std::string msg); -void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2); +[[noreturn]] void SlError(StringID string, std::string extra_msg = {}); +[[noreturn]] void SlErrorCorrupt(std::string msg); +[[noreturn]] void CDECL SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2); bool SaveLoadFileTypeIsScenario(); diff --git a/src/sl/town_sl.cpp b/src/sl/town_sl.cpp index a4ad9fb4b7..8e1a9c066b 100644 --- a/src/sl/town_sl.cpp +++ b/src/sl/town_sl.cpp @@ -212,14 +212,14 @@ static const SaveLoad _town_desc[] = { SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), ///< pct_pass_transported / pct_mail_transported, now computed on the fly SLE_CONDNULL_X(3, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - 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[TAE_FOOD].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), + SLE_CONDVAR(Town, received[TAE_WATER].old_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - 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_CONDVAR(Town, received[TAE_FOOD].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), + SLE_CONDVAR(Town, received[TAE_WATER].new_act, SLE_UINT16, SL_MIN_VERSION, SLV_165), SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), - 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), @@ -307,7 +307,7 @@ static void RealSave_Town(Town *t) for (CargoID i = 0; i < NUM_CARGO; i++) { SlObjectSaveFiltered(&t->supplied[i], _filtered_town_supplied_desc); } - for (int i = TE_BEGIN; i < NUM_TE; i++) { + for (int i = TAE_BEGIN; i < NUM_TAE; i++) { SlObjectSaveFiltered(&t->received[i], _filtered_town_received_desc); } } @@ -335,11 +335,11 @@ static void Load_TOWN() SlObjectLoadFiltered(&t->supplied[i], _filtered_town_supplied_desc); } if (SlXvIsFeaturePresent(XSLFI_SPRINGPP)) { - for (int i = TE_BEGIN; i < NUM_TE; i++) { + for (int i = TAE_BEGIN; i < NUM_TAE; i++) { SlObject(&t->received[i], _town_received_desc_spp); } } else { - for (int i = TE_BEGIN; i < NUM_TE; i++) { + for (int i = TAE_BEGIN; i < NUM_TAE; i++) { SlObjectLoadFiltered(&t->received[i], _filtered_town_received_desc); } } diff --git a/src/sl/vehicle_sl.cpp b/src/sl/vehicle_sl.cpp index fe9933057d..bfdd6b0185 100644 --- a/src/sl/vehicle_sl.cpp +++ b/src/sl/vehicle_sl.cpp @@ -1606,12 +1606,45 @@ void Load_VLKA() } } +const SaveLoadTable GetVehicleUnbunchStateDescription() +{ + static const SaveLoad _vehicle_unbunch_state_desc[] = { + SLE_VAR(VehicleUnbunchState, depot_unbunching_last_departure, SLE_INT64), + SLE_VAR(VehicleUnbunchState, depot_unbunching_next_departure, SLE_INT64), + SLE_VAR(VehicleUnbunchState, round_trip_time, SLE_INT32), + }; + + return _vehicle_unbunch_state_desc; +} + +void Save_VUBS() +{ + for (Vehicle *v : Vehicle::Iterate()) { + if (v->unbunch_state != nullptr) { + SlSetArrayIndex(v->index); + SlObject(v->unbunch_state.get(), GetVehicleUnbunchStateDescription()); + } + } +} + +void Load_VUBS() +{ + int index; + while ((index = SlIterateArray()) != -1) { + Vehicle *v = Vehicle::GetIfValid(index); + assert(v != nullptr); + v->unbunch_state.reset(new VehicleUnbunchState()); + SlObject(v->unbunch_state.get(), GetVehicleUnbunchStateDescription()); + } +} + static const ChunkHandler veh_chunk_handlers[] = { { 'VEHS', Save_VEHS, Load_VEHS, Ptrs_VEHS, nullptr, CH_SPARSE_ARRAY }, { 'VEOX', Save_VEOX, Load_VEOX, nullptr, nullptr, CH_SPARSE_ARRAY }, { 'VESR', Save_VESR, Load_VESR, nullptr, nullptr, CH_SPARSE_ARRAY }, { 'VENC', Save_VENC, Load_VENC, nullptr, nullptr, CH_RIFF, Special_VENC }, { 'VLKA', Save_VLKA, Load_VLKA, nullptr, nullptr, CH_SPARSE_ARRAY }, + { 'VUBS', Save_VUBS, Load_VUBS, nullptr, nullptr, CH_SPARSE_ARRAY }, }; extern const ChunkHandlerTable _veh_chunk_handlers(veh_chunk_handlers); diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 7394c3a46a..4649d0efe6 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -469,7 +469,7 @@ static inline uint32_t GetSmallMapRoutesPixels(TileIndex tile, TileType t) const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return ApplyMask(cs->default_colour, &andor); } - FALLTHROUGH; + [[fallthrough]]; } default: @@ -1253,11 +1253,11 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) { legend_colour = _smallmap_industry_highlight_state ? PC_WHITE : PC_BLACK; } - FALLTHROUGH; + [[fallthrough]]; case SMT_LINKSTATS: SetDParam(0, tbl->legend); - FALLTHROUGH; + [[fallthrough]]; case SMT_OWNER: if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) { @@ -1272,7 +1272,7 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() } break; } - FALLTHROUGH; + [[fallthrough]]; default: if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); diff --git a/src/spritecache.cpp b/src/spritecache.cpp index aa67650971..fce164bd08 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -930,7 +930,7 @@ static void *HandleInvalidSpriteRequest(SpriteID sprite, SpriteType requested, S switch (requested) { case SpriteType::Normal: if (sprite == SPR_IMG_QUERY) usererror("Uhm, would you be so kind not to load a NewGRF that makes the 'query' sprite a non-normal sprite?"); - FALLTHROUGH; + [[fallthrough]]; case SpriteType::Font: return GetRawSprite(SPR_IMG_QUERY, SpriteType::Normal, UINT8_MAX, allocator); case SpriteType::Recolour: diff --git a/src/spriteloader/grf.hpp b/src/spriteloader/grf.hpp index 500e988365..868cb01577 100644 --- a/src/spriteloader/grf.hpp +++ b/src/spriteloader/grf.hpp @@ -13,7 +13,7 @@ #include "spriteloader.hpp" /** Sprite loader for graphics coming from a (New)GRF. */ -class SpriteLoaderGrf FINAL : public SpriteLoader { +class SpriteLoaderGrf final : public SpriteLoader { byte container_ver; public: SpriteLoaderGrf(byte container_ver) : container_ver(container_ver) {} diff --git a/src/station_base.h b/src/station_base.h index f1a059a2d8..75e36435e9 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -872,7 +872,7 @@ struct IndustryCompare { typedef btree::btree_set IndustryList; /** Station data structure */ -struct Station FINAL : SpecializedStation { +struct Station final : SpecializedStation { public: RoadStop *GetPrimaryRoadStop(RoadStopType type) const { diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index a338e2173e..95a317c8fd 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3880,7 +3880,7 @@ static void TileLoop_Station(TileIndex tile) case STATION_DOCK: if (!IsTileFlat(tile)) break; // only handle water part - FALLTHROUGH; + [[fallthrough]]; case STATION_OILRIG: //(station part) case STATION_BUOY: diff --git a/src/stdafx.h b/src/stdafx.h index e4d373e1cf..202f0d319a 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -70,7 +70,6 @@ /* Stuff for GCC */ #if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) -# define NORETURN __attribute__ ((noreturn)) # define CDECL # define __int64 long long /* Warn about functions using 'printf' format syntax. First argument determines which parameter @@ -81,18 +80,6 @@ # define WARN_FORMAT(string, args) __attribute__ ((format (printf, string, args))) # endif #define WARN_TIME_FORMAT(string) __attribute__ ((format (strftime, string, 0))) - #define FINAL final - - /* Use fallthrough attribute where supported */ -# if __GNUC__ >= 7 -# if __cplusplus > 201402L // C++17 -# define FALLTHROUGH [[fallthrough]] -# else -# define FALLTHROUGH __attribute__((fallthrough)) -# endif -# else -# define FALLTHROUGH -# endif #endif /* __GNUC__ || __clang__ */ #if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 1) @@ -101,13 +88,6 @@ # define NOACCESS(args) #endif -/* [[nodiscard]] on constructors doesn't work in GCC older than 10.1. */ -#if __GNUC__ < 10 || (__GNUC__ == 10 && __GNUC_MINOR__ < 1) -# define NODISCARD -#else -# define NODISCARD [[nodiscard]] -#endif - #if defined(__MINGW32__) # include // alloca() #endif @@ -159,7 +139,6 @@ # endif # include // alloca() -# define NORETURN __declspec(noreturn) # if (_MSC_VER < 1900) # define inline __forceinline # endif @@ -167,14 +146,6 @@ # define CDECL _cdecl # define WARN_FORMAT(string, args) # define WARN_TIME_FORMAT(string) -# define FINAL final - - /* fallthrough attribute, VS 2017 */ -# if (_MSC_VER >= 1910) || defined(__clang__) -# define FALLTHROUGH [[fallthrough]] -# else -# define FALLTHROUGH -# endif # if defined(_WIN32) && !defined(_WIN64) # if !defined(_W64) @@ -439,11 +410,11 @@ typedef uint64_t unaligned_uint64; /* For the FMT library we only want to use the headers, not link to some library. */ #define FMT_HEADER_ONLY -void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); -void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); -void NORETURN CDECL assert_msg_error(int line, const char *file, const char *expr, const char *extra, const char *str, ...) WARN_FORMAT(5, 6); -void NORETURN assert_str_error(int line, const char *file, const char *expr, const char *str); -void NORETURN assert_str_error(int line, const char *file, const char *expr, const std::string &str); +[[noreturn]] void CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); +[[noreturn]] void CDECL error(const char *str, ...) WARN_FORMAT(1, 2); +[[noreturn]] void CDECL assert_msg_error(int line, const char *file, const char *expr, const char *extra, const char *str, ...) WARN_FORMAT(5, 6); +[[noreturn]] void assert_str_error(int line, const char *file, const char *expr, const char *str); +[[noreturn]] void assert_str_error(int line, const char *file, const char *expr, const std::string &str); const char *assert_tile_info(uint32_t tile); #define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__) diff --git a/src/story.cpp b/src/story.cpp index 2cdea2287d..0d92002c9b 100644 --- a/src/story.cpp +++ b/src/story.cpp @@ -400,7 +400,7 @@ CommandCost CmdShowStoryPage(TileIndex tile, DoCommandFlag flags, uint32_t p1, u if (flags & DC_EXEC) { StoryPage *g = StoryPage::Get(page_id); - if ((g->company != INVALID_COMPANY && g->company == _local_company) || (g->company == INVALID_COMPANY && Company::IsValidID(_local_company))) ShowStoryBook(_local_company, page_id); + if ((g->company != INVALID_COMPANY && g->company == _local_company) || (g->company == INVALID_COMPANY && Company::IsValidID(_local_company))) ShowStoryBook(_local_company, page_id, true); } return CommandCost(); diff --git a/src/story_gui.cpp b/src/story_gui.cpp index f01f29c391..318d1266db 100644 --- a/src/story_gui.cpp +++ b/src/story_gui.cpp @@ -972,7 +972,14 @@ static constexpr NWidgetPart _nested_story_book_widgets[] = { }; static WindowDesc _story_book_desc(__FILE__, __LINE__, - WDP_CENTER, "view_story", 400, 300, + WDP_AUTO, "view_story", 400, 300, + WC_STORY_BOOK, WC_NONE, + 0, + std::begin(_nested_story_book_widgets), std::end(_nested_story_book_widgets) +); + +static WindowDesc _story_book_gs_desc(__FILE__, __LINE__, + WDP_CENTER, "view_story_gs", 400, 300, WC_STORY_BOOK, WC_NONE, 0, std::begin(_nested_story_book_widgets), std::end(_nested_story_book_widgets) @@ -1044,11 +1051,12 @@ static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor) * Raise or create the story book window for \a company, at page \a page_id. * @param company 'Owner' of the story book, may be #INVALID_COMPANY. * @param page_id Page to open, may be #INVALID_STORY_PAGE. + * @param centered Whether to open the window centered. */ -void ShowStoryBook(CompanyID company, uint16_t page_id) +void ShowStoryBook(CompanyID company, uint16_t page_id, bool centered) { if (!Company::IsValidID(company)) company = (CompanyID)INVALID_COMPANY; - StoryBookWindow *w = AllocateWindowDescFront(&_story_book_desc, company, true); + StoryBookWindow *w = AllocateWindowDescFront(centered ? &_story_book_gs_desc : &_story_book_desc, company, true); if (page_id != INVALID_STORY_PAGE) w->SetSelectedPage(page_id); } diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index b4f2a0df72..81fa7264da 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -66,7 +66,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; @@ -80,7 +80,7 @@ void NORETURN CDECL strgen_fatal(const char *s, ...) throw std::exception(); } -void NORETURN CDECL error(const char *s, ...) +[[noreturn]] void CDECL error(const char *s, ...) { char buf[1024]; va_list va; diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index 75d46587a7..0c79a141de 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -167,7 +167,7 @@ ParsedCommandStruct ExtractCommandString(const char *s, bool warnings); void CDECL strgen_warning(const char *s, ...) WARN_FORMAT(1, 2); void CDECL strgen_error(const char *s, ...) WARN_FORMAT(1, 2); -void NORETURN CDECL strgen_fatal(const char *s, ...) WARN_FORMAT(1, 2); +[[noreturn]] void CDECL strgen_fatal(const char *s, ...) WARN_FORMAT(1, 2); char *ParseWord(char **buf); extern const char *_file; diff --git a/src/subsidy.cpp b/src/subsidy.cpp index a688b09098..fd3c37ae93 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -293,9 +293,13 @@ bool FindSubsidyPassengerRoute() { if (!Subsidy::CanAllocateItem()) return false; + /* Pick a random TPE_PASSENGER type */ + uint32_t r = RandomRange(static_cast(CargoSpec::town_production_cargoes[TPE_PASSENGERS].size())); + CargoID cid = CargoSpec::town_production_cargoes[TPE_PASSENGERS][r]->Index(); + const Town *src = Town::GetRandom(); if (src->cache.population < SUBSIDY_PAX_MIN_POPULATION || - src->GetPercentTransported(CT_PASSENGERS) > SUBSIDY_MAX_PCT_TRANSPORTED) { + src->GetPercentTransported(cid) > SUBSIDY_MAX_PCT_TRANSPORTED) { return false; } @@ -305,9 +309,9 @@ bool FindSubsidyPassengerRoute() } if (DistanceManhattan(src->xy, dst->xy) > SUBSIDY_MAX_DISTANCE) return false; - if (CheckSubsidyDuplicate(CT_PASSENGERS, SourceType::Town, src->index, SourceType::Town, dst->index)) return false; + if (CheckSubsidyDuplicate(cid, SourceType::Town, src->index, SourceType::Town, dst->index)) return false; - CreateSubsidy(CT_PASSENGERS, SourceType::Town, src->index, SourceType::Town, dst->index); + CreateSubsidy(cid, SourceType::Town, src->index, SourceType::Town, dst->index); return true; } @@ -339,7 +343,9 @@ bool FindSubsidyTownCargoRoute() } /* Passenger subsidies are not handled here. */ - town_cargo_produced[CT_PASSENGERS] = 0; + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) { + town_cargo_produced[cs->Index()] = 0; + } uint8_t cargo_count = town_cargo_produced.GetCount(); diff --git a/src/table/cargo_const.h b/src/table/cargo_const.h index 9d5c4ef0fe..f182e039df 100644 --- a/src/table/cargo_const.h +++ b/src/table/cargo_const.h @@ -36,62 +36,62 @@ * @param td1 CargoSpec->transit_periods[0]. * @param td2 CargoSpec->transit_periods[1]. * @param freight Cargo type is considered to be freight (affects train freight multiplier). - * @param te The effect that delivering this cargo type has on towns. Also affects destination of subsidies. + * @param tae The effect that delivering this cargo type has on towns. * @param str_plural The name suffix used to populate CargoSpec->name, CargoSpec->quantifier, * CargoSpec->abbrev and CargoSpec->sprite. See above for more detailed information. * @param str_singular The name suffix used to populate CargoSpec->name_single. See above for more information. * @param str_volume Name of a single unit of cargo of this type. * @param classes Classes of this cargo type. @see CargoClass */ -#define MK(bt, label, colour, weight, mult, ip, td1, td2, freight, te, str_plural, str_singular, str_volume, classes) \ - {label, bt, colour, colour, weight, mult, classes, ip, {td1, td2}, freight, te, 0, \ +#define MK(bt, label, colour, weight, mult, ip, td1, td2, freight, tae, str_plural, str_singular, str_volume, classes) \ + {label, bt, colour, colour, weight, mult, classes, ip, {td1, td2}, freight, tae, INVALID_TPE, TOWN_PRODUCTION_DIVISOR, 0, \ MK_STR_CARGO_PLURAL(str_plural), MK_STR_CARGO_SINGULAR(str_singular), str_volume, MK_STR_QUANTITY(str_plural), MK_STR_ABBREV(str_plural), \ MK_SPRITE(str_plural), nullptr, nullptr, 0} /** Cargo types available by default. */ static const CargoSpec _default_cargo[] = { - MK( 0, 'PASS', 152, 1, 0x400, 3185, 0, 24, false, TE_PASSENGERS, PASSENGERS, PASSENGER, STR_PASSENGERS, CC_PASSENGERS), - MK( 1, 'COAL', 6, 16, 0x100, 5916, 7, 255, true, TE_NONE, COAL, COAL, STR_TONS, CC_BULK), - MK( 2, 'MAIL', 15, 4, 0x200, 4550, 20, 90, false, TE_MAIL, MAIL, MAIL, STR_BAGS, CC_MAIL), + MK( 0, 'PASS', 152, 1, 0x400, 3185, 0, 24, false, TAE_PASSENGERS, PASSENGERS, PASSENGER, STR_PASSENGERS, CC_PASSENGERS), + MK( 1, 'COAL', 6, 16, 0x100, 5916, 7, 255, true, TAE_NONE, COAL, COAL, STR_TONS, CC_BULK), + MK( 2, 'MAIL', 15, 4, 0x200, 4550, 20, 90, false, TAE_MAIL, MAIL, MAIL, STR_BAGS, CC_MAIL), /* Oil in temperate and arctic */ - MK( 3, 'OIL_', 174, 16, 0x100, 4437, 25, 255, true, TE_NONE, OIL, OIL, STR_LITERS, CC_LIQUID), + MK( 3, 'OIL_', 174, 16, 0x100, 4437, 25, 255, true, TAE_NONE, OIL, OIL, STR_LITERS, CC_LIQUID), /* Oil in subtropic */ - MK( 3, 'OIL_', 174, 16, 0x100, 4892, 25, 255, true, TE_NONE, OIL, OIL, STR_LITERS, CC_LIQUID), - MK( 4, 'LVST', 208, 3, 0x100, 4322, 4, 18, true, TE_NONE, LIVESTOCK, LIVESTOCK, STR_ITEMS, CC_PIECE_GOODS), - MK( 5, 'GOOD', 194, 8, 0x200, 6144, 5, 28, true, TE_GOODS, GOODS, GOODS, STR_CRATES, CC_EXPRESS), - MK( 6, 'GRAI', 191, 16, 0x100, 4778, 4, 40, true, TE_NONE, GRAIN, GRAIN, STR_TONS, CC_BULK), - MK( 6, 'WHEA', 191, 16, 0x100, 4778, 4, 40, true, TE_NONE, WHEAT, WHEAT, STR_TONS, CC_BULK), - MK( 6, 'MAIZ', 191, 16, 0x100, 4322, 4, 40, true, TE_NONE, MAIZE, MAIZE, STR_TONS, CC_BULK), + MK( 3, 'OIL_', 174, 16, 0x100, 4892, 25, 255, true, TAE_NONE, OIL, OIL, STR_LITERS, CC_LIQUID), + MK( 4, 'LVST', 208, 3, 0x100, 4322, 4, 18, true, TAE_NONE, LIVESTOCK, LIVESTOCK, STR_ITEMS, CC_PIECE_GOODS), + MK( 5, 'GOOD', 194, 8, 0x200, 6144, 5, 28, true, TAE_GOODS, GOODS, GOODS, STR_CRATES, CC_EXPRESS), + MK( 6, 'GRAI', 191, 16, 0x100, 4778, 4, 40, true, TAE_NONE, GRAIN, GRAIN, STR_TONS, CC_BULK), + MK( 6, 'WHEA', 191, 16, 0x100, 4778, 4, 40, true, TAE_NONE, WHEAT, WHEAT, STR_TONS, CC_BULK), + MK( 6, 'MAIZ', 191, 16, 0x100, 4322, 4, 40, true, TAE_NONE, MAIZE, MAIZE, STR_TONS, CC_BULK), /* Wood in temperate and arctic */ - MK( 7, 'WOOD', 84, 16, 0x100, 5005, 15, 255, true, TE_NONE, WOOD, WOOD, STR_TONS, CC_PIECE_GOODS), + MK( 7, 'WOOD', 84, 16, 0x100, 5005, 15, 255, true, TAE_NONE, WOOD, WOOD, STR_TONS, CC_PIECE_GOODS), /* Wood in subtropic */ - MK( 7, 'WOOD', 84, 16, 0x100, 7964, 15, 255, true, TE_NONE, WOOD, WOOD, STR_TONS, CC_PIECE_GOODS), - MK( 8, 'IORE', 184, 16, 0x100, 5120, 9, 255, true, TE_NONE, IRON_ORE, IRON_ORE, STR_TONS, CC_BULK), - MK( 9, 'STEL', 10, 16, 0x100, 5688, 7, 255, true, TE_NONE, STEEL, STEEL, STR_TONS, CC_PIECE_GOODS), - MK( 10, 'VALU', 202, 2, 0x100, 7509, 1, 32, true, TE_NONE, VALUABLES, VALUABLES, STR_BAGS, CC_ARMOURED), - MK( 10, 'GOLD', 202, 8, 0x100, 5802, 10, 40, true, TE_NONE, GOLD, GOLD, STR_BAGS, CC_ARMOURED), - MK( 10, 'DIAM', 202, 2, 0x100, 5802, 10, 255, true, TE_NONE, DIAMONDS, DIAMOND, STR_BAGS, CC_ARMOURED), - MK( 11, 'PAPR', 10, 16, 0x100, 5461, 7, 60, true, TE_NONE, PAPER, PAPER, STR_TONS, CC_PIECE_GOODS), - MK( 12, 'FOOD', 48, 16, 0x100, 5688, 0, 30, true, TE_FOOD, FOOD, FOOD, STR_TONS, CC_EXPRESS | CC_REFRIGERATED), - MK( 13, 'FRUT', 208, 16, 0x100, 4209, 0, 15, true, TE_NONE, FRUIT, FRUIT, STR_TONS, CC_BULK | CC_REFRIGERATED), - MK( 14, 'CORE', 184, 16, 0x100, 4892, 12, 255, true, TE_NONE, COPPER_ORE, COPPER_ORE, STR_TONS, CC_BULK), - MK( 15, 'WATR', 10, 16, 0x100, 4664, 20, 80, true, TE_WATER, WATER, WATER, STR_LITERS, CC_LIQUID), - MK( 16, 'RUBR', 6, 16, 0x100, 4437, 2, 20, true, TE_NONE, RUBBER, RUBBER, STR_LITERS, CC_LIQUID), - MK( 17, 'SUGR', 6, 16, 0x100, 4437, 20, 255, true, TE_NONE, SUGAR, SUGAR, STR_TONS, CC_BULK), - MK( 18, 'TOYS', 174, 2, 0x100, 5574, 25, 255, true, TE_NONE, TOYS, TOY, STR_ITEMS, CC_PIECE_GOODS), - MK( 19, 'BATT', 208, 4, 0x100, 4322, 2, 30, true, TE_NONE, BATTERIES, BATTERY, STR_ITEMS, CC_PIECE_GOODS), - MK( 20, 'SWET', 194, 5, 0x200, 6144, 8, 40, true, TE_GOODS, SWEETS, SWEETS, STR_BAGS, CC_EXPRESS), - MK( 21, 'TOFF', 191, 16, 0x100, 4778, 14, 60, true, TE_NONE, TOFFEE, TOFFEE, STR_TONS, CC_BULK), - MK( 22, 'COLA', 84, 16, 0x100, 4892, 5, 75, true, TE_NONE, COLA, COLA, STR_LITERS, CC_LIQUID), - MK( 23, 'CTCD', 184, 16, 0x100, 5005, 10, 25, true, TE_NONE, CANDYFLOSS, CANDYFLOSS, STR_TONS, CC_BULK), - MK( 24, 'BUBL', 10, 1, 0x100, 5077, 20, 80, true, TE_NONE, BUBBLES, BUBBLE, STR_ITEMS, CC_PIECE_GOODS), - MK( 25, 'PLST', 202, 16, 0x100, 4664, 30, 255, true, TE_NONE, PLASTIC, PLASTIC, STR_LITERS, CC_LIQUID), - MK( 26, 'FZDR', 48, 2, 0x100, 6250, 30, 50, true, TE_FOOD, FIZZY_DRINKS, FIZZY_DRINK, STR_ITEMS, CC_PIECE_GOODS), + MK( 7, 'WOOD', 84, 16, 0x100, 7964, 15, 255, true, TAE_NONE, WOOD, WOOD, STR_TONS, CC_PIECE_GOODS), + MK( 8, 'IORE', 184, 16, 0x100, 5120, 9, 255, true, TAE_NONE, IRON_ORE, IRON_ORE, STR_TONS, CC_BULK), + MK( 9, 'STEL', 10, 16, 0x100, 5688, 7, 255, true, TAE_NONE, STEEL, STEEL, STR_TONS, CC_PIECE_GOODS), + MK( 10, 'VALU', 202, 2, 0x100, 7509, 1, 32, true, TAE_NONE, VALUABLES, VALUABLES, STR_BAGS, CC_ARMOURED), + MK( 10, 'GOLD', 202, 8, 0x100, 5802, 10, 40, true, TAE_NONE, GOLD, GOLD, STR_BAGS, CC_ARMOURED), + MK( 10, 'DIAM', 202, 2, 0x100, 5802, 10, 255, true, TAE_NONE, DIAMONDS, DIAMOND, STR_BAGS, CC_ARMOURED), + MK( 11, 'PAPR', 10, 16, 0x100, 5461, 7, 60, true, TAE_NONE, PAPER, PAPER, STR_TONS, CC_PIECE_GOODS), + MK( 12, 'FOOD', 48, 16, 0x100, 5688, 0, 30, true, TAE_FOOD, FOOD, FOOD, STR_TONS, CC_EXPRESS | CC_REFRIGERATED), + MK( 13, 'FRUT', 208, 16, 0x100, 4209, 0, 15, true, TAE_NONE, FRUIT, FRUIT, STR_TONS, CC_BULK | CC_REFRIGERATED), + MK( 14, 'CORE', 184, 16, 0x100, 4892, 12, 255, true, TAE_NONE, COPPER_ORE, COPPER_ORE, STR_TONS, CC_BULK), + MK( 15, 'WATR', 10, 16, 0x100, 4664, 20, 80, true, TAE_WATER, WATER, WATER, STR_LITERS, CC_LIQUID), + MK( 16, 'RUBR', 6, 16, 0x100, 4437, 2, 20, true, TAE_NONE, RUBBER, RUBBER, STR_LITERS, CC_LIQUID), + MK( 17, 'SUGR', 6, 16, 0x100, 4437, 20, 255, true, TAE_NONE, SUGAR, SUGAR, STR_TONS, CC_BULK), + MK( 18, 'TOYS', 174, 2, 0x100, 5574, 25, 255, true, TAE_NONE, TOYS, TOY, STR_ITEMS, CC_PIECE_GOODS), + MK( 19, 'BATT', 208, 4, 0x100, 4322, 2, 30, true, TAE_NONE, BATTERIES, BATTERY, STR_ITEMS, CC_PIECE_GOODS), + MK( 20, 'SWET', 194, 5, 0x200, 6144, 8, 40, true, TAE_GOODS, SWEETS, SWEETS, STR_BAGS, CC_EXPRESS), + MK( 21, 'TOFF', 191, 16, 0x100, 4778, 14, 60, true, TAE_NONE, TOFFEE, TOFFEE, STR_TONS, CC_BULK), + MK( 22, 'COLA', 84, 16, 0x100, 4892, 5, 75, true, TAE_NONE, COLA, COLA, STR_LITERS, CC_LIQUID), + MK( 23, 'CTCD', 184, 16, 0x100, 5005, 10, 25, true, TAE_NONE, CANDYFLOSS, CANDYFLOSS, STR_TONS, CC_BULK), + MK( 24, 'BUBL', 10, 1, 0x100, 5077, 20, 80, true, TAE_NONE, BUBBLES, BUBBLE, STR_ITEMS, CC_PIECE_GOODS), + MK( 25, 'PLST', 202, 16, 0x100, 4664, 30, 255, true, TAE_NONE, PLASTIC, PLASTIC, STR_LITERS, CC_LIQUID), + MK( 26, 'FZDR', 48, 2, 0x100, 6250, 30, 50, true, TAE_FOOD, FIZZY_DRINKS, FIZZY_DRINK, STR_ITEMS, CC_PIECE_GOODS), /* Void slot in temperate */ - MK(0xFF, 0, 1, 0, 0x100, 5688, 0, 30, true, TE_NONE, NOTHING, NOTHING, STR_TONS, CC_NOAVAILABLE), + MK(0xFF, 0, 1, 0, 0x100, 5688, 0, 30, true, TAE_NONE, NOTHING, NOTHING, STR_TONS, CC_NOAVAILABLE), /* Void slot in arctic */ - MK(0xFF, 0, 184, 0, 0x100, 5120, 9, 255, true, TE_NONE, NOTHING, NOTHING, STR_TONS, CC_NOAVAILABLE), + MK(0xFF, 0, 184, 0, 0x100, 5120, 9, 255, true, TAE_NONE, NOTHING, NOTHING, STR_TONS, CC_NOAVAILABLE), }; diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 5f18e1902b..51add6ec21 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -1334,7 +1334,8 @@ class NIHCargo : public NIHelper { seprintf(buffer, lastof(buffer), " Initial payment: %d, Current payment: " OTTD_PRINTF64 ", Transit periods: (%u, %u)", spec->initial_payment, (int64_t)spec->current_payment, spec->transit_periods[0], spec->transit_periods[1]); output.print(buffer); - seprintf(buffer, lastof(buffer), " Freight: %s, Town effect: %u", spec->is_freight ? "yes" : "no", spec->town_effect); + seprintf(buffer, lastof(buffer), " Freight: %s, Town acceptance effect: %u, Town production effect: %u", + spec->is_freight ? "yes" : "no", spec->town_acceptance_effect, spec->town_production_effect); output.print(buffer); } diff --git a/src/table/settings/gui_settings.ini b/src/table/settings/gui_settings.ini index 60171b390b..654ab051fa 100644 --- a/src/table/settings/gui_settings.ini +++ b/src/table/settings/gui_settings.ini @@ -1054,9 +1054,9 @@ cat = SC_EXPERT var = gui.cycle_signal_types type = SLE_UINT8 flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC | SF_GUI_DROPDOWN -def = 0 -min = 0 -max = 1 +def = SIGNAL_CYCLE_GROUP +min = SIGNAL_CYCLE_GROUP +max = SIGNAL_CYCLE_ALL interval = 1 str = STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES strhelp = STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT diff --git a/src/table/settings/script_settings.ini b/src/table/settings/script_settings.ini index ba67187162..c59c77e8e2 100644 --- a/src/table/settings/script_settings.ini +++ b/src/table/settings/script_settings.ini @@ -8,7 +8,6 @@ ; and in the savegame PATS chunk. [pre-amble] -static constexpr std::initializer_list _settings_profiles{"easy", "medium", "hard"}; static void ScriptMaxOpsChange(int32_t new_value); static bool CheckScriptMaxMemoryChange(int32_t &new_value); @@ -48,17 +47,6 @@ patxname = nullptr enumlist = -[SDT_OMANY] -var = script.settings_profile -type = SLE_UINT8 -from = SLV_178 -flags = SF_GUI_DROPDOWN -def = SP_EASY -min = SP_EASY -max = SP_HARD -full = _settings_profiles -cat = SC_BASIC - [SDT_VAR] var = script.script_max_opcode_till_suspend type = SLE_UINT32 diff --git a/src/table/settings_compat.h b/src/table/settings_compat.h index 69f295a137..c1b7ec79f4 100644 --- a/src/table/settings_compat.h +++ b/src/table/settings_compat.h @@ -304,7 +304,7 @@ static std::initializer_list _settings_compat{ SLCX_XREF("economy.sharing_payment_in_debt", SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CHILLPP, SL_CHILLPP_232)), SLCX_XREF("economy.day_length_factor", SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), SLCX_NULL(1, SL_MIN_VERSION, SLV_107), // previously ai-new setting - SLCX_VAR("script.settings_profile"), + SLCX_NULL(1, SLV_178, SLV_TABLE_CHUNKS), // previously script.settings_profile SLCX_VAR("ai.ai_in_multiplayer"), SLCX_VAR("ai.ai_disable_veh_train"), SLCX_VAR("ai.ai_disable_veh_roadveh"), diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp index 7beaef0c6f..141469eca6 100644 --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -89,7 +89,7 @@ static void GenerateRockyArea(TileIndex end, TileIndex start) switch (GetTileType(tile)) { case MP_TREES: if (GetTreeGround(tile) == TREE_GROUND_SHORE) continue; - FALLTHROUGH; + [[fallthrough]]; case MP_CLEAR: MakeClear(tile, CLEAR_ROCKS, 3); diff --git a/src/timer/timer.h b/src/timer/timer.h index b2af446ec7..7a20dc3888 100644 --- a/src/timer/timer.h +++ b/src/timer/timer.h @@ -31,7 +31,7 @@ public: * * @param period The period of the timer. */ - NODISCARD BaseTimer(const TPeriod period) : + [[nodiscard]] BaseTimer(const TPeriod period) : period(period) { TimerManager::RegisterTimer(*this); @@ -85,7 +85,7 @@ public: * @param interval The interval between each callback. * @param callback The callback to call when the interval has passed. */ - NODISCARD IntervalTimer(const TPeriod interval, std::function callback) : + [[nodiscard]] IntervalTimer(const TPeriod interval, std::function callback) : BaseTimer(interval), callback(callback) { @@ -128,7 +128,7 @@ public: * @param callback The callback to call when the timeout has passed. * @param start Whether to start the timer immediately. If false, you can call Reset() to start it. */ - NODISCARD TimeoutTimer(const TPeriod timeout, std::function callback, bool start = false) : + [[nodiscard]] TimeoutTimer(const TPeriod timeout, std::function callback, bool start = false) : BaseTimer(timeout), fired(!start), callback(callback) diff --git a/src/timetable_cmd.cpp b/src/timetable_cmd.cpp index 283e6c082b..d2ea1b25de 100644 --- a/src/timetable_cmd.cpp +++ b/src/timetable_cmd.cpp @@ -320,6 +320,12 @@ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32_t p1, default: break; } + + /* Unbunching data is no longer valid for any vehicle in this shared order group. */ + Vehicle *u = v->FirstShared(); + for (; u != nullptr; u = u->NextShared()) { + u->ResetDepotUnbunching(); + } } return CommandCost(); @@ -406,6 +412,9 @@ CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32_t p1 if (u->lateness_counter > most_late) { most_late = u->lateness_counter; } + + /* Unbunching data is no longer valid. */ + u->ResetDepotUnbunching(); } if (most_late > 0) { for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) { @@ -418,6 +427,8 @@ CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32_t p1 } } else { v->lateness_counter = 0; + /* Unbunching data is no longer valid. */ + v->ResetDepotUnbunching(); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } } @@ -486,12 +497,12 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32_t p CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; - StateTicks start_date_scaled = (StateTicks)p3; + StateTicks start_state_tick = (StateTicks)p3; /* Don't let a timetable start more than 15 unscaled years into the future... */ - if (start_date_scaled - _state_ticks > 15 * DAY_TICKS * DAYS_IN_LEAP_YEAR) return CMD_ERROR; + if (start_state_tick - _state_ticks > 15 * DAY_TICKS * DAYS_IN_LEAP_YEAR) return CMD_ERROR; /* ...or 1 unscaled year in the past. */ - if (_state_ticks - start_date_scaled > DAY_TICKS * DAYS_IN_LEAP_YEAR) return CMD_ERROR; + if (_state_ticks - start_state_tick > DAY_TICKS * DAYS_IN_LEAP_YEAR) return CMD_ERROR; if (timetable_all && !v->orders->IsCompleteTimetable()) return CommandCost(STR_ERROR_TIMETABLE_INCOMPLETE); @@ -521,7 +532,11 @@ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32_t p w->lateness_counter = 0; ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED); /* Do multiplication, then division to reduce rounding errors. */ - w->timetable_start = start_date_scaled + ((idx * total_duration) / num_vehs); + w->timetable_start = start_state_tick + ((idx * total_duration) / num_vehs); + + /* Unbunching data is no longer valid. */ + v->ResetDepotUnbunching(); + ++idx; } diff --git a/src/timetable_gui.cpp b/src/timetable_gui.cpp index b5ff85d519..510db28482 100644 --- a/src/timetable_gui.cpp +++ b/src/timetable_gui.cpp @@ -407,7 +407,7 @@ struct TimetableWindow : GeneralVehicleWindow { this->deparr_time_width = GetStringBoundingBox(STR_JUST_TT_TIME).width + 4; this->deparr_abbr_width = std::max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_ABBREVIATION).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_ABBREVIATION).width); size->width = this->deparr_abbr_width + WidgetDimensions::scaled.hsep_wide + this->deparr_time_width + padding.width; - FALLTHROUGH; + [[fallthrough]]; case WID_VT_ARRIVAL_DEPARTURE_SELECTION: case WID_VT_TIMETABLE_PANEL: diff --git a/src/town.h b/src/town.h index 1db79ba205..666e17e4f9 100644 --- a/src/town.h +++ b/src/town.h @@ -105,8 +105,8 @@ struct Town : TownPool::PoolItem<&_town_pool> { uint8_t town_label_rating; ///< Label dependent on _local_company rating. TransportedCargoStat supplied[NUM_CARGO]; ///< Cargo statistics about supplied cargo. - TransportedCargoStat received[NUM_TE]; ///< Cargo statistics about received cargotypes. - uint32_t goal[NUM_TE]; ///< Amount of cargo required for the town to grow. + TransportedCargoStat received[NUM_TAE]; ///< Cargo statistics about received cargotypes. + uint32_t goal[NUM_TAE]; ///< Amount of cargo required for the town to grow. std::string text; ///< General text with additional information. @@ -271,7 +271,7 @@ HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile); void SetTownRatingTestMode(bool mode); uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t); bool GenerateTowns(TownLayout layout); -const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect); +const CargoSpec *FindFirstCargoWithTownAcceptanceEffect(TownAcceptanceEffect effect); /** Town actions of a company. */ enum TownActions { diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 081aaa6826..a8be80a09c 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -679,6 +679,50 @@ static void TownGenerateCargo(Town *t, CargoID ct, uint amount, StationFinder &s t->supplied[ct].new_act += MoveGoodsToStation(ct, amount, SourceType::Town, t->index, stations.GetStations()); } +/** + * Generate cargo for a house using the original algorithm. + * @param t The current town. + * @param tpe The town production effect. + * @param rate The town's product rate for this production. + * @param stations Available stations for this house. + */ +static void TownGenerateCargoOriginal(Town *t, TownProductionEffect tpe, uint8_t rate, StationFinder &stations) +{ + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) { + uint32_t r = Random(); + if (GB(r, 0, 8) < rate) { + CargoID cid = cs->Index(); + uint amt = (GB(r, 0, 8) * cs->town_production_multiplier / TOWN_PRODUCTION_DIVISOR) / 8 + 1; + + TownGenerateCargo(t, cid, amt, stations, true); + } + } +} + +/** + * Generate cargo for a house using the binominal algorithm. + * @param t The current town. + * @param tpe The town production effect. + * @param rate The town's product rate for this production. + * @param stations Available stations for this house. + */ +static void TownGenerateCargoBinominal(Town *t, TownProductionEffect tpe, uint8_t rate, StationFinder &stations) +{ + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) { + CargoID cid = cs->Index(); + uint32_t r = Random(); + + /* Make a bitmask with up to 32 bits set, one for each potential pax. */ + int genmax = (rate + 7) / 8; + uint32_t genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1); + + /* Mask random value by potential pax and count number of actual pax. */ + uint amt = CountBits(r & genmask) * cs->town_production_multiplier / TOWN_PRODUCTION_DIVISOR; + + TownGenerateCargo(t, cid, amt, stations, true); + } +} + /** * Tile callback function. * @@ -733,15 +777,8 @@ static void TileLoop_Town(TileIndex tile) switch (_settings_game.economy.town_cargogen_mode) { case TCGM_ORIGINAL: /* Original (quadratic) cargo generation algorithm */ - if (GB(r, 0, 8) < hs->population) { - uint amt = GB(r, 0, 8) / 8 + 1; - TownGenerateCargo(t, CT_PASSENGERS, amt, stations, true); - } - - if (GB(r, 8, 8) < hs->mail_generation) { - uint amt = GB(r, 8, 8) / 8 + 1; - TownGenerateCargo(t, CT_MAIL, amt, stations, true); - } + TownGenerateCargoOriginal(t, TPE_PASSENGERS, hs->population, stations); + TownGenerateCargoOriginal(t, TPE_MAIL, hs->mail_generation, stations); break; case TCGM_BITCOUNT: @@ -749,20 +786,8 @@ static void TileLoop_Town(TileIndex tile) /* Reduce generation rate to a 1/4, using tile bits to spread out distribution. * As tick counter is incremented by 256 between each call, we ignore the lower 8 bits. */ if (GB(_tick_counter, 8, 2) == GB(tile, 0, 2)) { - /* Make a bitmask with up to 32 bits set, one for each potential pax */ - int genmax = (hs->population + 7) / 8; - uint32_t genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1); - /* Mask random value by potential pax and count number of actual pax */ - uint amt = CountBits(r & genmask); - /* Adjust and apply */ - TownGenerateCargo(t, CT_PASSENGERS, amt, stations, true); - - /* Do the same for mail, with a fresh random */ - r = Random(); - genmax = (hs->mail_generation + 7) / 8; - genmask = (genmax >= 32) ? 0xFFFFFFFF : ((1 << genmax) - 1); - amt = CountBits(r & genmask); - TownGenerateCargo(t, CT_MAIL, amt, stations, true); + TownGenerateCargoBinominal(t, TPE_PASSENGERS, hs->population, stations); + TownGenerateCargoBinominal(t, TPE_MAIL, hs->mail_generation, stations); } break; @@ -866,10 +891,14 @@ void AddProducedHouseCargo(HouseID house_id, TileIndex tile, CargoArray &produce } } else { if (hs->population > 0) { - produced[CT_PASSENGERS]++; + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) { + produced[cs->Index()]++; + } } if (hs->mail_generation > 0) { - produced[CT_MAIL]++; + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_MAIL]) { + produced[cs->Index()]++; + } } } } @@ -1797,7 +1826,7 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t case TL_3X3_GRID: // Use 2x2 grid afterwards! GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir)); - FALLTHROUGH; + [[fallthrough]]; case TL_2X2_GRID: rcmd = GetTownRoadGridElement(t1, tile, target_dir); @@ -1806,7 +1835,7 @@ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection t case TL_BETTER_ROADS: // Use original afterwards! GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir)); - FALLTHROUGH; + [[fallthrough]]; case TL_ORIGINAL: /* Allow a house at the edge. 60% chance or @@ -2155,8 +2184,8 @@ void UpdateTownRadii() void UpdateTownMaxPass(Town *t) { - t->supplied[CT_PASSENGERS].old_max = t->cache.population >> 3; - t->supplied[CT_MAIL].old_max = t->cache.population >> 4; + t->supplied[CT_PASSENGERS].old_max = _town_cargo_scaler.Scale(t->cache.population >> 3); + t->supplied[CT_MAIL].old_max = _town_cargo_scaler.Scale(t->cache.population >> 4); } static void UpdateTownGrowthRate(Town *t); @@ -2192,12 +2221,12 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32_t townnameparts, TownSi /* 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; } @@ -3280,10 +3309,10 @@ CommandCost CmdRenameTownNonAdmin(TileIndex tile, DoCommandFlag flags, uint32_t * @param effect Town effect of interest * @return first active cargo slot with that effect */ -const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect) +const CargoSpec *FindFirstCargoWithTownAcceptanceEffect(TownAcceptanceEffect effect) { for (const CargoSpec *cs : CargoSpec::Iterate()) { - if (cs->town_effect == effect) return cs; + if (cs->town_acceptance_effect == effect) return cs; } return nullptr; } @@ -3294,7 +3323,7 @@ const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect) * @param flags Type of operation. * @param p1 various bitstuffed elements * - p1 = (bit 0 - 15) - Town ID to cargo game of. - * - p1 = (bit 16 - 23) - TownEffect to change the game of. + * - p1 = (bit 16 - 23) - TownAcceptanceEffect to change the game of. * @param p2 The new goal value. * @param text Unused. * @return Empty cost or an error. @@ -3303,19 +3332,19 @@ CommandCost CmdTownCargoGoal(TileIndex tile, DoCommandFlag flags, uint32_t p1, u { if (_current_company != OWNER_DEITY) return CMD_ERROR; - TownEffect te = (TownEffect)GB(p1, 16, 8); - if (te < TE_BEGIN || te >= TE_END) return CMD_ERROR; + TownAcceptanceEffect tae = (TownAcceptanceEffect)GB(p1, 16, 8); + if (tae < TAE_BEGIN || tae >= TAE_END) return CMD_ERROR; uint16_t index = GB(p1, 0, 16); Town *t = Town::GetIfValid(index); if (t == nullptr) return CMD_ERROR; - /* Validate if there is a cargo which is the requested TownEffect */ - const CargoSpec *cargo = FindFirstCargoWithTownEffect(te); + /* Validate if there is a cargo which is the requested TownAcceptanceEffect */ + const CargoSpec *cargo = FindFirstCargoWithTownAcceptanceEffect(tae); if (cargo == nullptr) return CMD_ERROR; if (flags & DC_EXEC) { - t->goal[te] = p2; + t->goal[tae] = p2; UpdateTownGrowth(t); InvalidateWindowData(WC_TOWN_VIEW, index); } @@ -4195,7 +4224,7 @@ static void UpdateTownGrowth(Town *t) if (t->fund_buildings_months == 0) { /* Check if all goals are reached for this town to grow (given we are not funding it) */ - for (int i = TE_BEGIN; i < TE_END; i++) { + for (int i = TAE_BEGIN; i < TAE_END; i++) { switch (t->goal[i]) { case TOWN_GROWTH_WINTER: if (TileHeight(t->xy) >= GetSnowLine() && t->received[i].old_act == 0 && t->cache.population > 90) return; @@ -4291,7 +4320,7 @@ Town *ClosestTownFromTile(TileIndex tile, uint threshold) return town; } - FALLTHROUGH; + [[fallthrough]]; case MP_HOUSE: return Town::GetByTile(tile); diff --git a/src/town_gui.cpp b/src/town_gui.cpp index 0ed4f4e631..164f13e526 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -436,7 +436,7 @@ public: } /* When double-clicking, continue */ if (click_count == 1 || y < 0) break; - FALLTHROUGH; + [[fallthrough]]; } case WID_TA_EXECUTE: @@ -592,20 +592,21 @@ public: DrawString(tr, STR_TOWN_VIEW_POPULATION_HOUSES); tr.top += GetCharacterHeight(FS_NORMAL); - SetDParam(0, 1 << CT_PASSENGERS); - SetDParam(1, this->town->supplied[CT_PASSENGERS].old_act); - SetDParam(2, this->town->supplied[CT_PASSENGERS].old_max); - DrawString(tr, STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX); - tr.top += GetCharacterHeight(FS_NORMAL); + StringID str_last_period = EconTime::UsingWallclockUnits() ? STR_TOWN_VIEW_CARGO_LAST_MINUTE_MAX : STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX; - SetDParam(0, 1 << CT_MAIL); - SetDParam(1, this->town->supplied[CT_MAIL].old_act); - SetDParam(2, this->town->supplied[CT_MAIL].old_max); - DrawString(tr, STR_TOWN_VIEW_CARGO_LAST_MONTH_MAX); - tr.top += GetCharacterHeight(FS_NORMAL); + for (auto tpe : {TPE_PASSENGERS, TPE_MAIL}) { + for (const CargoSpec *cs : CargoSpec::town_production_cargoes[tpe]) { + CargoID cid = cs->Index(); + SetDParam(0, 1ULL << cid); + SetDParam(1, this->town->supplied[cid].old_act); + SetDParam(2, this->town->supplied[cid].old_max); + DrawString(tr, str_last_period); + tr.top += GetCharacterHeight(FS_NORMAL); + } + } bool first = true; - for (int i = TE_BEGIN; i < TE_END; i++) { + for (int i = TAE_BEGIN; i < TAE_END; i++) { if (this->town->goal[i] == 0) continue; if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; @@ -618,7 +619,7 @@ public: bool rtl = _current_text_dir == TD_RTL; - const CargoSpec *cargo = FindFirstCargoWithTownEffect((TownEffect)i); + const CargoSpec *cargo = FindFirstCargoWithTownAcceptanceEffect((TownAcceptanceEffect)i); assert(cargo != nullptr); StringID string; @@ -724,10 +725,10 @@ public: */ uint GetDesiredInfoHeight(int width) const { - uint aimed_height = 3 * GetCharacterHeight(FS_NORMAL); + uint aimed_height = static_cast(1 + CargoSpec::town_production_cargoes[TPE_PASSENGERS].size() + CargoSpec::town_production_cargoes[TPE_MAIL].size()) * GetCharacterHeight(FS_NORMAL); bool first = true; - for (int i = TE_BEGIN; i < TE_END; i++) { + for (int i = TAE_BEGIN; i < TAE_END; i++) { if (this->town->goal[i] == 0) continue; if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; diff --git a/src/train.h b/src/train.h index b540ba46bf..733ff3e392 100644 --- a/src/train.h +++ b/src/train.h @@ -130,7 +130,7 @@ struct TrainCache { /** * 'Train' is either a loco or a wagon. */ -struct Train FINAL : public GroundVehicle { +struct Train final : public GroundVehicle { TrackBits track; RailType railtype; uint32_t flags; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index d0ab5e0a5e..dcb94c5027 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -692,7 +692,7 @@ void AdvanceOrderIndex(const Vehicle *v, VehicleOrderID &index) case OT_GOTO_DEPOT: /* Skip service in depot orders when the train doesn't need service. */ if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) break; - FALLTHROUGH; + [[fallthrough]]; case OT_GOTO_STATION: case OT_GOTO_WAYPOINT: return; @@ -3204,6 +3204,9 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 HideFillingPercent(&v->fill_percent_te_id); ReverseTrainDirection(v); } + + /* Unbunching data is no longer valid. */ + v->ResetDepotUnbunching(); } } return CommandCost(); @@ -3237,6 +3240,9 @@ CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32_t p * next signal we encounter. */ t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL; SetWindowDirty(WC_VEHICLE_VIEW, t->index); + + /* Unbunching data is no longer valid. */ + t->ResetDepotUnbunching(); } return CommandCost(); @@ -3388,6 +3394,9 @@ static bool CheckTrainStayInDepot(Train *v) return true; } + /* Check if we should wait here for unbunching. */ + if (v->IsWaitingForUnbunching()) return true; + if (v->reverse_distance > 0) { v->reverse_distance--; if (v->reverse_distance == 0) SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); @@ -3484,6 +3493,7 @@ static bool CheckTrainStayInDepot(Train *v) if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile, VMDF_NOT_MAP_MODE); VehicleServiceInDepot(v); + v->LeaveUnbunchingDepot(); DirtyVehicleListWindowForVehicle(v); v->PlayLeaveStationSound(); @@ -4043,7 +4053,7 @@ public: case OT_GOTO_DEPOT: /* Skip service in depot orders when the train doesn't need service. */ if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !this->v->NeedsServicing()) break; - FALLTHROUGH; + [[fallthrough]]; case OT_GOTO_STATION: case OT_GOTO_WAYPOINT: this->v->current_order = *order; @@ -6427,7 +6437,7 @@ static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse) * for other directions, it will be 1, 3, 5, ..., 15 */ switch (v->direction) { case DIR_N : x = ~x + ~y + 25; break; - case DIR_NW: x = y; FALLTHROUGH; + case DIR_NW: x = y; [[fallthrough]]; case DIR_NE: x = ~x + 16; break; case DIR_E : x = ~x + y + 9; break; case DIR_SE: x = y; break; diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp index e248892a19..dec89f178a 100644 --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -591,7 +591,7 @@ CommandCost CmdPlantTree(TileIndex end_tile, DoCommandFlag flags, uint32_t p1, u msg = STR_ERROR_CAN_T_BUILD_ON_WATER; continue; } - FALLTHROUGH; + [[fallthrough]]; case MP_CLEAR: { if (!CanPlantTreesOnTile(tile, false) || IsBridgeAbove(tile)) { @@ -963,7 +963,7 @@ static void TileLoop_Trees(TileIndex tile) break; } } - FALLTHROUGH; + [[fallthrough]]; case 2: { // add a neighbouring tree if (!CanPlantExtraTrees(tile)) break; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 604565cca5..3ea7aeba57 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1135,6 +1135,9 @@ void Vehicle::HandlePathfindingResult(bool path_found) DirtyVehicleListWindowForVehicle(this); } + /* Unbunching data is no longer valid. */ + this->ResetDepotUnbunching(); + if (this->type == VEH_SHIP) { SetBit(this->vehicle_flags, VF_PATHFINDER_LOST); if (Ship::From(this)->lost_count == 255) return; @@ -2453,7 +2456,7 @@ bool Vehicle::HandleBreakdown() return (this->breakdown_type == BREAKDOWN_CRITICAL || this->breakdown_type == BREAKDOWN_EM_STOP); } - FALLTHROUGH; + [[fallthrough]]; case 1: /* Aircraft breakdowns end only when arriving at the airport */ if (this->type == VEH_AIRCRAFT) return false; @@ -2758,12 +2761,23 @@ void VehicleEnterDepot(Vehicle *v) * we shouldn't construct it when the vehicle visits the next stop. */ v->last_loading_station = INVALID_STATION; ClrBit(v->vehicle_flags, VF_LAST_LOAD_ST_SEP); + + /* Clear unbunching data. */ + v->ResetDepotUnbunching(); + + /* Announce that the vehicle is waiting to players and AIs. */ if (v->owner == _local_company) { SetDParam(0, v->index); AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index); } AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index)); } + + /* If we've entered our unbunching depot, record the round trip duration. */ + if (v->current_order.GetDepotActionType() & ODATFB_UNBUNCH && v->unbunch_state != nullptr && v->unbunch_state->depot_unbunching_last_departure != INVALID_STATE_TICKS) { + v->unbunch_state->round_trip_time = (_state_ticks - v->unbunch_state->depot_unbunching_last_departure).AsTicks(); + } + v->current_order.MakeDummy(); } } @@ -3767,6 +3781,88 @@ void Vehicle::HandleWaiting(bool stop_waiting, bool process_orders) } } +/** + * Check if the current vehicle has an unbunching order. + * @return true Iff this vehicle has an unbunching order. + */ +bool Vehicle::HasUnbunchingOrder() const +{ + for (Order *o : this->Orders()) { + if (o->IsType(OT_GOTO_DEPOT) && o->GetDepotActionType() & ODATFB_UNBUNCH) return true; + } + return false; +} + +/** + * Leave an unbunching depot and calculate the next departure time for shared order vehicles. + */ +void Vehicle::LeaveUnbunchingDepot() +{ + if (this->unbunch_state == nullptr) this->unbunch_state.reset(new VehicleUnbunchState()); + + /* Set the start point for this round trip time. */ + this->unbunch_state->depot_unbunching_last_departure = _state_ticks; + + /* Tell the timetable we are now "on time." */ + this->lateness_counter = 0; + SetWindowDirty(WC_VEHICLE_TIMETABLE, this->index); + + /* Find the average travel time of vehicles that we share orders with. */ + uint num_vehicles = 0; + Ticks total_travel_time = 0; + + Vehicle *u = this->FirstShared(); + for (; u != nullptr; u = u->NextShared()) { + /* Ignore vehicles that are manually stopped or crashed. */ + if (u->vehstatus & (VS_STOPPED | VS_CRASHED)) continue; + + num_vehicles++; + if (u->unbunch_state != nullptr) total_travel_time += u->unbunch_state->round_trip_time; + } + + /* Make sure we cannot divide by 0. */ + num_vehicles = std::max(num_vehicles, 1u); + + /* Calculate the separation by finding the average travel time, then calculating equal separation (minimum 1 tick) between vehicles. */ + Ticks separation = std::max((total_travel_time / num_vehicles / num_vehicles), 1u); + StateTicks next_departure = _state_ticks + separation; + + /* Set the departure time of all vehicles that we share orders with. */ + u = this->FirstShared(); + for (; u != nullptr; u = u->NextShared()) { + /* Ignore vehicles that are manually stopped or crashed. */ + if (u->vehstatus & (VS_STOPPED | VS_CRASHED)) continue; + + if (u->unbunch_state == nullptr) u->unbunch_state.reset(new VehicleUnbunchState()); + u->unbunch_state->depot_unbunching_next_departure = next_departure; + } +} + +/** + * Check whether a vehicle inside a depot is waiting for unbunching. + * @return True if the vehicle must continue waiting, or false if it may try to leave the depot. + */ +bool Vehicle::IsWaitingForUnbunching() const +{ + assert(this->IsInDepot()); + + /* Don't bother if there are no vehicles sharing orders. */ + if (!this->IsOrderListShared()) return false; + + /* Don't do anything if there aren't enough orders. */ + if (this->GetNumOrders() <= 1) return false; + + /* + * Make sure this is the correct depot for unbunching. + * If we are headed for the first order, we must wrap around back to the last order. + */ + bool is_first_order = (this->GetOrder(this->cur_real_order_index) == this->GetFirstOrder()); + Order *previous_order = (is_first_order) ? this->GetLastOrder() : this->GetOrder(this->cur_real_order_index - 1); + if (previous_order == nullptr || !previous_order->IsType(OT_GOTO_DEPOT) || !(previous_order->GetDepotActionType() & ODATFB_UNBUNCH)) return false; + + return (this->unbunch_state != nullptr) && (this->unbunch_state->depot_unbunching_next_departure > _state_ticks); +}; + /** * Send this vehicle to the depot using the given command(s). * @param flags the command flags (like execute and such). @@ -3803,6 +3899,9 @@ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command, Tile return CMD_ERROR; } + /* No matter why we're headed to the depot, unbunching data is no longer valid. */ + if (flags & DC_EXEC) this->ResetDepotUnbunching(); + auto cancel_order = [&]() { if (flags & DC_EXEC) { /* If the orders to 'goto depot' are in the orders list (forced servicing), @@ -4748,6 +4847,10 @@ void AdjustVehicleStateTicksBase(StateTicksDelta delta) for (Vehicle *v : Vehicle::Iterate()) { if (v->timetable_start != 0) v->timetable_start += delta; if (v->last_loading_tick != 0) v->last_loading_tick += delta; + if (v->unbunch_state != nullptr) { + if (v->unbunch_state->depot_unbunching_last_departure != INVALID_STATE_TICKS) v->unbunch_state->depot_unbunching_last_departure += delta; + if (v->unbunch_state->depot_unbunching_next_departure != INVALID_STATE_TICKS) v->unbunch_state->depot_unbunching_next_departure += delta; + } } for (OrderList *order_list : OrderList::Iterate()) { diff --git a/src/vehicle_base.h b/src/vehicle_base.h index a9a98e87a1..3d3c762c09 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -268,6 +268,12 @@ struct ClosestDepot { location(location), destination(destination), reverse(reverse), found(true) {} }; +struct VehicleUnbunchState { + StateTicks depot_unbunching_last_departure = INVALID_STATE_TICKS; ///< When the vehicle last left its unbunching depot. + StateTicks depot_unbunching_next_departure = INVALID_STATE_TICKS; ///< When the vehicle will next try to leave its unbunching depot. + Ticks round_trip_time = 0; ///< How many ticks for a single circumnavigation of the orders. +}; + /** %Vehicle data structure. */ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist { /* These are here for structure packing purposes */ @@ -409,6 +415,8 @@ public: VehicleCache vcache; ///< Cache of often used vehicle values. + std::unique_ptr unbunch_state; + /** * Calculates the weight value that this vehicle will have when fully loaded with its current cargo. * @return Weight value in tonnes. @@ -958,6 +966,12 @@ public: inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); } + inline void ResetDepotUnbunching() { this->unbunch_state.reset(); } + + bool HasUnbunchingOrder() const; + void LeaveUnbunchingDepot(); + bool IsWaitingForUnbunching() const; + VehicleOrderID GetFirstWaitingLocation(bool require_wait_timetabled) const; private: diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 3b7438e046..3dfd1a81e7 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -695,6 +695,10 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32_t p1 Train::From(v)->lookahead.reset(); FillTrainReservationLookAhead(Train::From(v)); } + + /* Unbunching data is no longer valid. */ + v->ResetDepotUnbunching(); + v->MarkDirty(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index bae472c32a..ea90856571 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1165,7 +1165,7 @@ struct RefitWindow : public Window { this->selected_vehicle = v->index; this->num_vehicles = UINT8_MAX; this->ship_part_names.clear(); - FALLTHROUGH; + [[fallthrough]]; } case 2: { // The vehicle selection has changed; rebuild the entire list. @@ -1191,7 +1191,7 @@ struct RefitWindow : public Window { this->information_width = max_width; this->ReInit(); } - FALLTHROUGH; + [[fallthrough]]; } case 1: // A new cargo has been selected. @@ -1252,7 +1252,7 @@ struct RefitWindow : public Window { if (_ctrl_pressed) this->num_vehicles = UINT8_MAX; break; } - FALLTHROUGH; + [[fallthrough]]; } default: @@ -1310,7 +1310,7 @@ struct RefitWindow : public Window { this->InvalidateData(1); if (click_count == 1) break; - FALLTHROUGH; + [[fallthrough]]; } case WID_VR_REFIT: // refit button @@ -3881,6 +3881,8 @@ public: } } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) { str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR; + } else if (v->IsInDepot() && v->IsWaitingForUnbunching()) { + str = STR_VEHICLE_STATUS_WAITING_UNBUNCHING; } else { // vehicle is in a "normal" state, show current order switch (v->current_order.GetType()) { case OT_GOTO_STATION: { @@ -3910,6 +3912,8 @@ public: str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SELL_VEL; } else if (v->current_order.GetDepotActionType() & ODATFB_HALT) { str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_VEL : STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL; + } else if (v->current_order.GetDepotActionType() & ODATFB_UNBUNCH) { + str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_SERVICE_VEL : STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_UNBUNCH_VEL; } else { str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_DEPOT_SERVICE_VEL : STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL; } @@ -3946,7 +3950,7 @@ public: str = STR_VEHICLE_STATUS_LEAVING; break; } - FALLTHROUGH; + [[fallthrough]]; default: if (v->GetNumManualOrders() == 0) { str = STR_VEHICLE_STATUS_NO_ORDERS_VEL; diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 1e5afce11f..04d5a366d5 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -426,7 +426,7 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) return 0; - FALLTHROUGH; + [[fallthrough]]; case WM_QUERYNEWPALETTE: video_driver->PaletteChanged(hwnd); diff --git a/src/viewport.cpp b/src/viewport.cpp index cd96eadd2c..a556bd79d2 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -3362,7 +3362,7 @@ static inline uint32_t ViewportMapGetColourRoutes(const TileIndex tile, TileType colour = rti->map_colour; break; } - FALLTHROUGH; + [[fallthrough]]; } default: { @@ -3658,7 +3658,7 @@ static void ViewportMapDrawBridgeTunnel(Viewport * const vp, const TunnelBridgeT colour = rti->map_colour; break; } - FALLTHROUGH; + [[fallthrough]]; } default: @@ -5803,7 +5803,7 @@ static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_t byte style_t = (byte)(TileX(end_tile) > TileX(start_tile)); start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t])); end_tile = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t])); - FALLTHROUGH; + [[fallthrough]]; } case HT_POINT: @@ -6397,7 +6397,7 @@ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) case VPM_X_LIMITED: // Drag in X direction (limited size). limit = (_thd.sizelimit - 1) * TILE_SIZE; - FALLTHROUGH; + [[fallthrough]]; case VPM_FIX_X: // drag in Y direction x = sx; @@ -6406,7 +6406,7 @@ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) case VPM_Y_LIMITED: // Drag in Y direction (limited size). limit = (_thd.sizelimit - 1) * TILE_SIZE; - FALLTHROUGH; + [[fallthrough]]; case VPM_FIX_Y: // drag in X direction y = sy; @@ -6465,7 +6465,7 @@ calc_heightdiff_single_direction:; limit = (_thd.sizelimit - 1) * TILE_SIZE; x = sx + Clamp(x - sx, -limit, limit); y = sy + Clamp(y - sy, -limit, limit); - FALLTHROUGH; + [[fallthrough]]; case VPM_X_AND_Y: // drag an X by Y area if (_settings_client.gui.measure_tooltip) { diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 10dd83639b..483ee61ca3 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -180,7 +180,7 @@ bool IsPossibleDockingTile(TileIndex t) switch (GetTileType(t)) { case MP_WATER: if (IsLock(t) && GetLockPart(t) == LOCK_PART_MIDDLE) return false; - FALLTHROUGH; + [[fallthrough]]; case MP_RAILWAY: case MP_STATION: case MP_TUNNELBRIDGE: @@ -546,7 +546,7 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32_t p1, uint MakeSea(current_tile); break; } - FALLTHROUGH; + [[fallthrough]]; default: MakeCanal(current_tile, _current_company, Random()); @@ -1162,7 +1162,7 @@ FloodingBehaviour GetFloodingBehaviour(TileIndex tile) Slope tileh = GetTileSlope(tile); return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP); } - FALLTHROUGH; + [[fallthrough]]; case MP_STATION: case MP_INDUSTRY: return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE; @@ -1216,7 +1216,7 @@ void DoFloodTile(TileIndex target) flooded = true; break; } - FALLTHROUGH; + [[fallthrough]]; case MP_CLEAR: if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) { diff --git a/src/waypoint_base.h b/src/waypoint_base.h index 95b97366e5..54c5c18d9e 100644 --- a/src/waypoint_base.h +++ b/src/waypoint_base.h @@ -21,7 +21,7 @@ enum WaypointFlags { }; /** Representation of a waypoint. */ -struct Waypoint FINAL : SpecializedStation { +struct Waypoint final : SpecializedStation { uint16_t town_cn; ///< The N-1th waypoint for this town (consecutive number) uint16_t waypoint_flags; ///< Waypoint flags, see WaypointFlags diff --git a/src/widget.cpp b/src/widget.cpp index c998f83bb0..53fb40e6b1 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -2727,7 +2727,7 @@ void NWidgetLeaf::SetupSmallestSize(Window *w) size.width = std::max(size.width, ScaleGUITrad(30) + sprite_size.width); size.height = std::max(sprite_size.height, GetStringBoundingBox("_").height + WidgetDimensions::scaled.framerect.Vertical()); } - FALLTHROUGH; + [[fallthrough]]; case WWT_PUSHBTN: { padding = {WidgetDimensions::scaled.frametext.Horizontal(), WidgetDimensions::scaled.framerect.Vertical()}; break; @@ -3110,7 +3110,7 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg NWidgetBackground *nwb = dynamic_cast(dest.get()); if (nwb != nullptr) nwb->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post); - if (unlikely(nwc == nullptr && nwb == nullptr)) throw std::runtime_error("WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground"); + if (nwc == nullptr && nwb == nullptr) [[unlikely]] throw std::runtime_error("WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground"); break; } @@ -3223,7 +3223,7 @@ std::unique_ptr MakeNWidgets(const NWidgetPart *nwid_begin, const N if (container == nullptr) container = std::make_unique(); [[maybe_unused]] const NWidgetPart *nwid_part = MakeWidgetTree(nwid_begin, nwid_end, container); #ifdef WITH_ASSERT - if (unlikely(nwid_part != nwid_end)) throw std::runtime_error("Did not consume all NWidgetParts"); + if (nwid_part != nwid_end) [[unlikely]] throw std::runtime_error("Did not consume all NWidgetParts"); #endif return container; } diff --git a/src/widgets/order_widget.h b/src/widgets/order_widget.h index 7919767236..34c5df9d1a 100644 --- a/src/widgets/order_widget.h +++ b/src/widgets/order_widget.h @@ -24,11 +24,12 @@ enum OrderWidgets : WidgetID { WID_O_DELETE, ///< Delete selected order. WID_O_STOP_SHARING, ///< Stop sharing orders. WID_O_NON_STOP, ///< Goto non-stop to destination. + WID_O_DEPOT_UNBUNCHING, ///< Toggle unbunching. WID_O_GOTO, ///< Goto destination. WID_O_FULL_LOAD, ///< Select full load. WID_O_UNLOAD, ///< Select unload. WID_O_REFIT, ///< Select refit. - WID_O_SERVICE, ///< Select service (at depot). + WID_O_DEPOT_ACTION, ///< Dropdown to select the depot action (stop, service if needed, unbunch). WID_O_REFIT_DROPDOWN, ///< Open refit options. WID_O_REVERSE, ///< Select waypoint reverse type WID_O_COND_VARIABLE, ///< Choose condition variable. diff --git a/src/window.cpp b/src/window.cpp index dd9d5792bd..583886728b 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1322,45 +1322,45 @@ static uint GetWindowZPriority(WindowClass wc) switch (wc) { case WC_TOOLTIPS: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_ERRMSG: case WC_CONFIRM_POPUP_QUERY: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_ENDSCREEN: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_HIGHSCORE: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_DROPDOWN_MENU: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_MAIN_TOOLBAR: case WC_STATUS_BAR: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_OSK: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_QUERY_STRING: case WC_SEND_NETWORK_MSG: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_NETWORK_ASK_RELAY: case WC_MODAL_PROGRESS: case WC_NETWORK_STATUS_WINDOW: case WC_SAVE_PRESET: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_GENERATE_LANDSCAPE: case WC_SAVELOAD: @@ -1372,19 +1372,19 @@ static uint GetWindowZPriority(WindowClass wc) case WC_SCRIPT_SETTINGS: case WC_TEXTFILE: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_CONSOLE: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_NEWS_WINDOW: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; default: ++z_priority; - FALLTHROUGH; + [[fallthrough]]; case WC_MAIN_WINDOW: return z_priority; @@ -3052,7 +3052,7 @@ static void MouseLoop(MouseClick click, int mousewheel) if (!scrollwheel_scrolling || w == nullptr || w->window_class != WC_SMALLMAP) break; /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. * Simulate a right button click so we can get started. */ - FALLTHROUGH; + [[fallthrough]]; case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top);