Compare commits

...
Author SHA1 Message Date
Richard Wheeler 7d76b3b296 Change: Fetch OpenGFX2 for CI workflows 2025-12-06 21:56:41 +00:00
Richard Wheeler bc6a656deb Change: Package OpenGFX2 for Windows Store and GOG 2025-12-06 21:44:02 +00:00
Rubidiumandrubidium42 55157f6df2 Doc: update contact information for Free Software Foundation 2025-12-06 19:47:10 +01:00
Peter NelsonandGitHub 9adc4bfc0f Codechange: Make order load/unload flags value types. (#14861)
Order Load and Unload flags have complex logic to ensure that invalid combinations aren't used. In fact, apart from FullLoad and FullLoadAny, all mixed combinations are invalid.

Simplify logic by removing the use of bit values and treat each option as a value.
2025-12-06 18:30:31 +00:00
Cyprian KlimaszewskiandGitHub abf8438a1b Fix #14756: Invalidate nested focus before widget container is cleared. (#14809) 2025-12-06 12:52:44 -05:00
Cyprian KlimaszewskiandGitHub 92e895a37a Fix #14723: Set force proceed to TFP_SIGNAL if next tile has signals. (#14724) 2025-12-06 18:12:03 +01:00
Peter NelsonandGitHub 046b0c6267 Codechange: Use enum class and EnumBitSet for various order flags. (#14783) 2025-12-06 12:29:11 +00:00
Peter NelsonandGitHub c1d37d8699 Add: Automatically load fonts for missing glyphs. (#14856) 2025-12-06 12:22:25 +00:00
Rubidiumandrubidium42 064f4df6cc Fix: always try to create at least one town 2025-12-06 12:55:47 +01:00
Rubidiumandrubidium42 6e65b2387a Fix #14802: close NewGRF inspection window when overbuilding with default station/waypoint 2025-12-06 12:08:03 +01:00
Rubidiumandrubidium42 1445aa9543 Codefix: some coding style improvements 2025-12-06 12:07:53 +01:00
Peter NelsonandGitHub 1829f7926d Change: Support side-by-side fallback FontCaches instead of hierarchical. (#13303)
The text layouter system can now support using different fonts for different glyphs, including mixing scalable and sprite glyphs.
2025-12-06 10:47:12 +00:00
Rubidiumandrubidium42 2c91607671 Fix #14839, e4cf6ca0ba: do not set stacked widget height, which might not be shown 2025-12-06 10:28:52 +01:00
Peter NelsonandGitHub 22569515df Fix: Drop down scrolling broken for mixed-height items. (#14840) 2025-12-06 09:15:55 +00:00
translators 06d3ae7381 Update: Translations from eints
chinese (simplified): 22 changes by WenSimEHRP
2025-12-06 04:38:49 +00:00
translators ad63087928 Update: Translations from eints
portuguese: 2 changes by jcteotonio
2025-12-05 04:43:02 +00:00
Tyler TrahanandGitHub bca8913d1d Change: Eliminate small seas instead of ending rivers there (#14797) 2025-12-04 10:55:13 -05:00
Peter NelsonandGitHub bd338d6e42 Fix 25f1c97bea: Incorrect background colour in badge configuration list. (#14850)
Provide correct widget colour instead of assuming COLOUR_GREY.
2025-12-03 14:38:20 +00:00
Peter NelsonandGitHub 7e046f112b Fix #14844: Use company colour remap for badges in picker window. (#14849)
(Except for houses, which are not company-owned.)
2025-12-03 14:38:03 +00:00
Jonathan G RennisonandGitHub 73b260ce05 Codefix: Leading newlines in Squirrel error/callstack prints (#14851) 2025-12-03 08:19:49 +00:00
translators 43a82c2e27 Update: Translations from eints
portuguese: 8 changes by jcteotonio
2025-12-03 04:42:04 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c24526a2e1 Upgrade: Bump the actions group across 1 directory with 5 updates (#14731)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 14:49:36 +00:00
Tyler TrahanandGitHub 595b696d61 Change: Avoid building farm fields in wetlands (#14846) 2025-12-02 14:28:12 +00:00
Tyler TrahanandGitHub faf3bb9739 Fix #9071: Don't consider tram tracks when growing towns (#14833) 2025-12-01 11:44:28 -05:00
mmtunligitandGitHub e96f35cda9 Codechange: Use SetDisplayedPlane instead of UpdateWidgetSize to hide various buttons (#14831) 2025-12-01 11:43:48 -05:00
translators 66185a312d Update: Translations from eints
luxembourgish: 23 changes by phreeze83
2025-12-01 04:48:24 +00:00
Peter NelsonandGitHub 0600fbe34b Change: Explicitly reserve sprite group types >= 0x80. (#14836)
The NewGRF spec does not mention that sprite group `type` and the `num-ent1` fields are the same.

Reserve all unrecognised special types in case they are wanted at some point.
2025-11-30 09:12:29 +00:00
translators 84d89cc802 Update: Translations from eints
norwegian (bokmal): 17 changes by eriksorngard
portuguese: 17 changes by jcteotonio
2025-11-30 04:44:11 +00:00
Jonathan G RennisonandGitHub 712ca5e3ec Codechange: [Script] Use std::optional for script list next iteration item (#14753)
Avoids false positive updates in Remove when iterating the final item
and leftover values being returned when IsEnd is true
2025-11-29 17:36:41 +00:00
Peter NelsonandGitHub 069833963c Codechange: Replace drop down list's default bools with DropDownOptions. (#14837)
Improves maintainability and avoids positional ambiguity.
2025-11-29 16:17:44 +00:00
Peter NelsonandPeter Nelson 2675295675 Fix #8062: (Try to) ensure enough room for profit in vehicle group window.
Width of group info panel previously relied entirely on the size of other widgets.
2025-11-29 16:17:23 +00:00
Peter NelsonandPeter Nelson 91a12a3928 Codechange: Precalculate group column rects.
Simplifies drawing group list which no longer needs to calculate horizontal positions for each row.
2025-11-29 16:17:23 +00:00
Peter NelsonandPeter Nelson e15539c430 Codechange: Extract functions to get group name and profit sprite.
Improves readability and allows long if-else conditions to be replaced with early returns.
2025-11-29 16:17:23 +00:00
translators 1810354622 Update: Translations from eints
galician: 17 changes by pvillaverde
german: 47 changes by Wuzzy2
2025-11-29 04:39:53 +00:00
translators ff578faf95 Update: Translations from eints
korean: 17 changes by telk5093
hungarian: 18 changes by vargaviktor
portuguese: 9 changes by jcteotonio
2025-11-28 04:40:44 +00:00
Peter NelsonandGitHub b9deabab7e Codefix: Add missing consts in group handling. (#14834) 2025-11-27 20:56:02 +00:00
translators fa0fd235c2 Update: Translations from eints
english (au): 9 changes by krysclarke
swedish: 17 changes by robert-i
english (us): 17 changes by 2TallTyler
greek: 9 changes by gh658804
russian: 9 changes by Ln-Wolf
finnish: 9 changes by hpiirai
portuguese (brazilian): 9 changes by pasantoro
polish: 9 changes by pAter-exe
2025-11-27 04:39:51 +00:00
Tyler TrahanandGitHub 3e73a130d8 Fix 509cbed: Don't give up erroneously when building lakes (#14832) 2025-11-26 21:34:05 +00:00
TheDude-ghandrubidium42 75aee10e1e Add: [Script] ScriptTile::IsHouseTile 2025-11-26 20:44:50 +01:00
translators 67ded4f980 Update: Translations from eints
english (au): 8 changes by krysclarke
greek: 8 changes by gh658804
russian: 8 changes by Ln-Wolf
finnish: 8 changes by hpiirai
portuguese: 8 changes by jcteotonio
portuguese (brazilian): 8 changes by pasantoro
polish: 10 changes by pAter-exe
2025-11-26 04:41:30 +00:00
Peter NelsonandGitHub f1937222d3 Change: Make picker label/text colours consistent. (#14829)
Use {GOLD} instead of {ORANGE} in house picker window, to match other picker windows.
2025-11-25 21:23:19 +00:00
mmtunligitandGitHub c3f9cdf84f Codechange 7a0814c: Use SetDisplayedPlane instead of UpdateWidgetSize (#14823) 2025-11-25 06:05:24 -05:00
mmtunligitandGitHub 3b541d4c74 Codefix: Add comments to SetViewport functions (#14822) 2025-11-25 06:04:16 -05:00
Tyler TrahanandGitHub b4ac5e2231 Change: Ensure generated towns have enough room (#14803) 2025-11-25 05:39:17 -05:00
translators 5bd28fa692 Update: Translations from eints
portuguese: 4 changes by jcteotonio
2025-11-25 04:41:35 +00:00
Cyprian KlimaszewskiandGitHub 26a84fad55 Fix 98700eee43, Fix #14815: Properly handle picker window invalidation. (#14816) 2025-11-24 23:28:41 +01:00
Peter NelsonandGitHub 3555f26ae6 Add: [NewGRF] Allow badges to be excluded from badge name list. (#14818)
This allows badges to have names that can be filtered, but avoid cluttering the purchase text.
2025-11-24 22:19:25 +00:00
Rubidiumandrubidium42 5533a24d84 Codechange: silence CodeQL complaints about long switches 2025-11-24 23:17:44 +01:00
Rubidiumandrubidium42 316f36fe14 Codefix: comparison of narrow type with wide type in loop condition 2025-11-24 23:02:00 +01:00
mmtunligitandGitHub 07177467b3 Feature: Signs, waypoint and station names may be moved (#14744) 2025-11-24 14:56:19 -05:00
Richard WheelerandGitHub f128d0de1d Fix: Bridge deck sprites were not toyland aware (#14821) 2025-11-24 19:43:12 +00:00
Jonathan G RennisonandGitHub 84eb3fb0e0 Fix #14800: Incorrect register processing in GetCustomStationRelocation (#14801)
ProcessRegisters must be called even if the sprite resolve result
is not valid.
A zero-length ResultSpriteGroup is valid because the output value
is an offset, not a sprite ID within the ResultSpriteGroup.
2025-11-24 06:22:58 -05:00
translators 74cb4dcefc Update: Translations from eints
portuguese: 11 changes by jcteotonio
2025-11-24 04:43:59 +00:00
Peter NelsonandGitHub c9b73247e0 Codefix: Remove this-> from static call to CleaningPool. (#14817)
Don't call unnecessarily.
2025-11-23 21:37:43 +00:00
translators 7ffd3b2c48 Update: Translations from eints
catalan: 4 changes by J0anJosep
portuguese: 6 changes by jcteotonio
2025-11-23 04:43:07 +00:00
Peter NelsonandGitHub e8dbd3aad2 Change: Add debug messages for errors encountered reading sounds. (#14810) 2025-11-22 12:31:08 +00:00
Peter NelsonandGitHub f3b24d51c3 Fix ed67aedabf: Saved default houses had incorrect class and index information. (#14812)
Saved default houses would not appear properly in the 'Saved' tab after restarting the game.
2025-11-22 12:15:14 +00:00
Peter NelsonandGitHub 821a496495 Codefix 0455627d16: Don't make temporary copies of order when converting old orders. (#14808) 2025-11-21 17:26:12 +00:00
Peter NelsonandGitHub 9237685f4c Fix #14794: Default railtype missing for some NewGRF rail vehicles. (#14795) 2025-11-20 22:12:10 +00:00
Peter NelsonandGitHub 98275ee5d3 Codechange: Use enum class for water-related enums. (#14804) 2025-11-19 20:35:11 +00:00
davidxnandGitHub 4e24c205d6 Fix 741c431: Miscalculated cargo penalty for poor station rating (#14712) 2025-11-18 20:18:02 +00:00
kosandrubidium42 98700eee43 Fix #14755: Remove clicked type selection when not visible 2025-11-18 20:26:45 +01:00
Rubidiumandrubidium42 62e568ce65 Codefix: shadowing variable, grouping loop increments 2025-11-18 20:22:31 +01:00
Jonathan G Rennisonandrubidium42 f0f964577d Fix 98481ecc: Incorrect parsing of var 6x parameter in NewGRF debug window 2025-11-18 20:21:03 +01:00
Jonathan G Rennisonandrubidium42 a321509d90 Fix 2b244441: [CMake] Regression tests failed if no previous crashes present
On CMake 3.x
2025-11-18 20:20:47 +01:00
Tyler TrahanandGitHub 509cbedf0b Feature: Rivers can end in wetlands if unable to reach sea (#14784) 2025-11-18 07:38:55 -05:00
translators a8b000f982 Update: Translations from eints
swedish: 4 changes by joeax910
portuguese: 1 change by jcteotonio
2025-11-18 04:39:55 +00:00
Peter NelsonandPeter Nelson c3451b5d97 Codechange: Replace color with colour. 2025-11-18 00:02:48 +00:00
Peter NelsonandPeter Nelson 73660bfaf2 Codechange: Replace favorite with favourite. 2025-11-18 00:02:48 +00:00
Peter NelsonandPeter Nelson 30955da3ce Codechange: Use enum class for Roadside. 2025-11-17 20:46:05 +00:00
Peter NelsonandPeter Nelson 2cd5a241c5 Codechange: Use enum class for RoadTileType. 2025-11-17 20:46:05 +00:00
Peter NelsonandPeter Nelson 2851c70a59 Codechange: Use enum class for RailGroundType. 2025-11-17 20:46:05 +00:00
Peter NelsonandPeter Nelson 0f5a4290df Codechange: Use enum class for RailTileType 2025-11-17 20:46:05 +00:00
Peter NelsonandGitHub e8ba7d0a08 Codefix f98b90ac2e: Use to_underlying instead of direct static_cast. (#14790) 2025-11-17 18:12:27 +00:00
Tyler TrahanandGitHub e8d49ebfe6 Fix: Two lighthouse spawn issues (#14785)
* Fix: Lighthouses need sea to generate, not rivers

* Fix: Don't spawn lighthouses close together
2025-11-17 12:55:23 +00:00
translators 7398d2e290 Update: Translations from eints
portuguese: 17 changes by jcteotonio
portuguese (brazilian): 1 change by jcteotonio
maori (new zealand): 21 changes by Kyle-McDangersword
2025-11-17 04:41:35 +00:00
translators 21329071df Update: Translations from eints
portuguese: 21 changes by jcteotonio
2025-11-16 04:40:12 +00:00
SamuXarickandGitHub 06d2f44891 Codechange: HighScore sorting to use std::vector (#14779)
Replaces the fixed-size array for company sorting with a std::vector and updates sorting to use std::ranges::sort. This removes the need for manual count management.
2025-11-15 16:40:36 -05:00
Muxy Du Goulpandrubidium42 05c40a6e55 Fix #14777: authorized_key: Correctly target key type for add/remove
The logic in ConNetworkAuthorizedKey for the `authorized_key` command was inverted.
The check `if (StrEqualsIgnoreCase(type, name)) continue;` caused the action (add/remove) to be incorrectly executed on the first key type encountered that *did not* match the requested type, rather than the intended one. This resulted in keys specified for 'admin' being added to 'rcon', for example.

This commit inverts the condition to ensure the action is performed only when the requested type matches the iterated key name.
2025-11-15 22:08:58 +01:00
Peter NelsonandGitHub d61a21cc0b Codechange: Use enum class for command-related enums. (#14775) 2025-11-15 19:33:09 +00:00
Loïc GuillouxandGitHub 2b24444146 Codechange: Detect crashes during regression (#14774) 2025-11-15 08:19:33 +00:00
translators 459d213f74 Update: Translations from eints
polish: 4 changes by pAter-exe
2025-11-15 04:38:42 +00:00
translators 2693e63247 Update: Translations from eints
norwegian (bokmal): 4 changes by eriksorngard
2025-11-14 04:39:19 +00:00
mmtunligitandGitHub 7662105081 Change: Clamp terraform toolbar to main toolbar (#14725) 2025-11-13 18:25:21 -05:00
Rito12andGitHub c38aa9cc86 Fix #14701: Company colour remap for sprites in badge filter dropdowns. (#14732) 2025-11-13 18:24:46 -05:00
translators dbe329733c Update: Translations from eints
korean: 4 changes by telk5093
2025-11-13 04:40:24 +00:00
Rito12andGitHub 120afd29f3 Codefix 394adb6: Make newgrf_badge_gui.cpp file docs compatible with the file name. (#14770) 2025-11-12 16:42:11 +00:00
translators c4b16cb4cd Update: Translations from eints
galician: 17 changes by pvillaverde
polish: 4 changes by Rito13
2025-11-12 04:39:35 +00:00
translators ae413728c1 Update: Translations from eints
english (au): 4 changes by krysclarke
english (us): 4 changes by 2TallTyler
greek: 4 changes by gh658804
hungarian: 4 changes by vargaviktor
russian: 4 changes by Ln-Wolf
finnish: 4 changes by hpiirai
portuguese: 4 changes by jcteotonio
portuguese (brazilian): 4 changes by pasantoro
2025-11-11 04:40:42 +00:00
Peter NelsonandGitHub ca866cc083 Fix 394adb654e: Incorrect spacing for badges in dropdown lists. (#14768) 2025-11-10 21:43:35 +00:00
Peter NelsonandGitHub aa6c694c67 Fix c2d4098afa: Unconfigured badge classes should be visible in column 0 by default. (#14766) 2025-11-10 21:41:02 +00:00
translators 744543e469 Update: Translations from eints
luxembourgish: 54 changes by phreeze83
2025-11-10 04:41:07 +00:00
Peter NelsonandGitHub 376a39f67a Change: Use proper tooltip strings for freeform edge toggles. (#14765) 2025-11-09 22:40:08 +00:00
Loïc GuillouxandGitHub b563c34ca4 Codefix 6d495d1: [Actions] vcpkg caching for codeql requires some permissions (#14767) 2025-11-09 21:31:59 +00:00
Rito12andGitHub 9c338cf212 Codefix 8f14894: Correct the comment for GetClassBadge function. (#14759) 2025-11-09 17:29:44 +01:00
Peter NelsonandGitHub d48463d2be Fix #14763: Crash if NewGRF currency separator is not valid. (#14764)
Ensure separator is a valid string.
2025-11-09 08:21:55 +00:00
translators f052ef213e Update: Translations from eints
luxembourgish: 54 changes by phreeze83
2025-11-07 04:39:02 +00:00
translators 94052a6ccb Update: Translations from eints
korean: 11 changes by telk5093
french: 14 changes by glx22
2025-11-06 04:41:15 +00:00
Jonathan G RennisonandGitHub 6d5f150b3d Fix: BaseBitSet bit iteration for values which don't fit in 32 bits (#14757) 2025-11-04 20:23:18 +01:00
Peter NelsonandGitHub 06d8e039c6 Codechange: Use std-find instead of for-loops in strgen. (#14754) 2025-11-04 15:26:15 +00:00
translators 3befbdd52f Update: Translations from eints
hungarian: 12 changes by vargaviktor
2025-11-04 04:38:48 +00:00
Peter NelsonandGitHub 8226548e31 Fix fd32d1447e: Test for empty shares became inverted. (#14751) 2025-11-03 16:33:18 +00:00
Rito12andGitHub f759b691d7 Codechange: Use helper function for company recolour offset (#14740) 2025-11-03 12:25:32 +00:00
Peter NelsonandPeter Nelson 9001d4a884 Codefix: Clear m8 when making tiles.
m8 should be cleared when tiles do not use it.
2025-11-02 09:24:07 +00:00
Peter NelsonandPeter Nelson 00cdf1bc56 Codefix: Clear m6 more thoroughly when making tiles.
m6 bits 6-7 were previously used to be for bridge above state, but should now be cleared.
2025-11-02 09:24:07 +00:00
Peter NelsonandGitHub 66b6d71e32 Codechange: Use std::initializer_list for NWidgetPart data. (#14749)
Avoids using C/C++ arrays.
2025-11-01 22:33:00 +00:00
Peter NelsonandGitHub 34bbae05db Codechange: Use enum/EnumBitSet for livery in use flags. (#14746)
Replaces magic numbers.
2025-11-01 14:25:24 +00:00
translators 7c855c69fa Update: Translations from eints
dutch: 11 changes by Afoklala
2025-11-01 04:37:15 +00:00
Rito12andGitHub 8ea347a811 Remove: Rail type cost from replace vehicle window. (#14748) 2025-10-31 10:26:47 -04:00
SamuXarickandGitHub 20fd2b5014 Codefix: Add missing 'this->' in ScriptList (#14747) 2025-10-31 11:38:49 +00:00
Peter NelsonandGitHub 038c4d2b87 Codechange: Make driver probe behave the same as loading by name. (#14736)
Inconsistent initialisation order when setting active driver and starting the driver.
2025-10-30 20:22:30 +00:00
SamuXarickandGitHub 3f19240bbe Doc 313c6c4: [Script] GetAllRailTypes and GetRailType are from ScriptEngine (#14745) 2025-10-30 13:36:43 -04:00
SamuXarickandGitHub 3ebedecb4a Add: [Script] Auto-convert ObjectType bool to integer when setting values for items in lists via [] (#14308) 2025-10-29 21:18:00 +01:00
translators 3b02761302 Update: Translations from eints
english (us): 11 changes by 2TallTyler
2025-10-29 04:41:13 +00:00
Peter NelsonandGitHub 534918ccb0 Codechange: Simplify YAPF debug helpers a little. (#14741)
Remove template magic to get C-array size.
2025-10-28 22:05:23 +00:00
translators 6295310f25 Update: Translations from eints
chinese (traditional): 4 changes by KogentaSan
chinese (simplified): 11 changes by WenSimEHRP
catalan: 11 changes by J0anJosep
2025-10-28 04:38:50 +00:00
Tyler TrahanandGitHub d1376d0b67 Fix #14737: Don't scale custom town and industry counts by land area (#14738) 2025-10-27 18:18:31 +00:00
translators b43cdcba01 Update: Translations from eints
norwegian (bokmal): 12 changes by eriksorngard
portuguese: 1 change by jcteotonio
polish: 2 changes by pAter-exe, 2 changes by Rito13
2025-10-27 04:41:32 +00:00
translators 1522c9f661 Update: Translations from eints
english (au): 11 changes by krysclarke
swedish: 11 changes by robert-i
chinese (traditional): 11 changes by KogentaSan
greek: 11 changes by gh658804
russian: 13 changes by Ln-Wolf
finnish: 15 changes by hpiirai
portuguese: 44 changes by jcteotonio
portuguese (brazilian): 11 changes by pasantoro, 1 change by jcteotonio
polish: 10 changes by Rito13, 1 change by pAter-exe
2025-10-26 04:38:02 +00:00
translators 7b703f688a Update: Translations from eints
galician: 1 change by pvillaverde
2025-10-25 04:38:31 +00:00
Peter NelsonandGitHub a1920fc225 Change: Scale towns/industries by amount of land tiles. (#10063) 2025-10-24 16:32:09 -04:00
Rito12andGitHub 70bf84175f Add: Show height difference in bridge is too low error message. (#14614) 2025-10-24 16:27:11 -04:00
Rito12andGitHub 6ebe64703f Add: Game units for height. (#14615) 2025-10-24 16:25:16 -04:00
Jonathan G RennisonandGitHub 2212169a8c Fix: Do not pre-fill industry production history for unused production slots (#14730) 2025-10-24 21:34:35 +02:00
Oliver Bechstein-RumbleandGitHub 6fc4bef0e3 Fix #14240: Remember previous GUI scale when toggling auto-detect (#14380) 2025-10-24 21:33:55 +02:00
Peter NelsonandGitHub 813cde3735 Fix: Don't set set town index for depot tiles. (#14729) 2025-10-24 21:30:50 +02:00
Peter NelsonandGitHub 06b830dc07 Codechange: Prefer string equality instead of comparison. (#14727) 2025-10-24 21:30:03 +02:00
Loïc GuillouxandGitHub a19f6c02e5 Codechange: Add prefix to dependabot commits (#14691) 2025-10-24 21:20:41 +02:00
SamuXarickandGitHub e4b0e84a7c Doc 80666a0: Fix typo in game script changelog (#14714) 2025-10-24 21:19:47 +02:00
Peter NelsonandPeter Nelson d6eff806f0 Codechange: Use single vector for next station order.
Pass vector to insert into to avoid handling multiple vectors.

This may change the order of returned stations.
2025-10-23 21:02:27 +01:00
Peter NelsonandPeter Nelson fd32d1447e Codechange: Remove StationIDStack and SmallStack.
Use a std::vector or std::span instead.
2025-10-23 21:02:27 +01:00
Peter NelsonandGitHub 5c89dff677 Codechange: Iterate road/tram masks instead of checking each type. (#14716) 2025-10-23 20:59:58 +01:00
Tyler TrahanandGitHub 8e8eebd785 Doc: Define policy on AI usage in OpenTTD development (#14537) 2025-10-23 08:24:58 -04:00
SamuXarickandGitHub 2396353c16 Codechange: Optimize FlowRiver (#13264) 2025-10-22 14:42:17 +02:00
Peter NelsonandPeter Nelson 9f7f314f81 Codechange: [Script] Add regression test for company president gender. 2025-10-19 17:32:48 +01:00
Peter NelsonandPeter Nelson 75ca1e3cda Fix a46a3a97f3: Incorrect parameter order for CmdSetCompanyManagerFace.
Style and bits were mixed up. Switch everything to style first, as the most significant parameter.
2025-10-19 17:32:48 +01:00
Peter NelsonandGitHub bf3a07c5d2 Codechange: Silence uninitialized variable warning from GCC. (#14715)
`is_custom_layout` is not used uninitialized but GCC does not know that and produces a warning.
2025-10-19 11:45:13 +01:00
translators c627c64cc5 Update: Translations from eints
swedish: 1 change by robert-i
norwegian (bokmal): 4 changes by eriksorngard
chinese (simplified): 4 changes by WenSimEHRP
catalan: 1 change by J0anJosep
danish: 4 changes by bscargo
latvian: 8 changes by lexuslatvia
dutch: 4 changes by Afoklala
french: 5 changes by ottdfevr
2025-10-16 04:38:47 +00:00
Peter NelsonandGitHub a949197264 Fix ef71ce0a9d: Crash when user enters a blank line in the console. (#14711)
Crash caused by reading outside the bounds of string_view (though not the underlying buffer)
2025-10-15 22:16:00 +00:00
Peter NelsonandGitHub 8e055156e3 Codefix: Make sure safeguards.h is the last included non-table header. (#14687) 2025-10-11 10:22:50 +01:00
Rito12andrubidium42 f935e34d90 Codefix: Remove double SetDirty() calls. 2025-10-11 12:15:00 +08:00
Peter NelsonandGitHub a617d009cc Codechange: Dereference with x-> instead of (*x). (#14700) 2025-10-05 15:47:33 +01:00
Peter NelsonandGitHub c9fbc41636 Codechange: Script list iterator tidying. (#14698)
* Use `iter->` instead of `(*iter).`
* Use prefix instead of postfix operators
* Use `auto` instead of explicit iterator type.
* Use `std::next()` instead of assignment then increment.
* Use range-for where possible.
2025-10-05 07:57:09 +01:00
Peter NelsonandPeter Nelson 6fdacb0759 Codechange: Use find/find_if to search for rail/road types by label.
Replaces manual loops.
2025-10-04 18:16:45 +01:00
Peter NelsonandPeter Nelson 4d40966303 Codechange: Use FlatSet to store and test alternate rail/road types. 2025-10-04 18:16:45 +01:00
Peter NelsonandGitHub 97674ac2a2 Fix f6c5da4cad: dump_info should not reverse non-ASCII label. (#14697)
Cargo/rail/road types labels are already in appropriate endian-ness.
2025-10-03 22:28:28 +01:00
translators 632ab6a4e5 Update: Translations from eints
chinese (traditional): 4 changes by KogentaSan
english (us): 1 change by 2TallTyler
korean: 1 change by telk5093
polish: 1 change by pAter-exe
2025-10-01 04:38:32 +00:00
Peter NelsonandGitHub 5d5d27841b Fix: Bootstrap ignored default OpenTTD truetype fonts. (#14684)
Bootstrapping assumed that glyphs must be missing if there is no baseset, ignoring whether there actually are glyphs missing.
2025-09-30 22:16:50 +01:00
translators 9eacb889f8 Update: Translations from eints
english (au): 1 change by krysclarke
greek: 1 change by gh658804
hungarian: 4 changes by vargaviktor
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
portuguese: 1 change by jcteotonio
portuguese (brazilian): 1 change by pasantoro
2025-09-30 04:38:08 +00:00
Peter NelsonandPeter Nelson 42084ca516 Change: Make groups window group list aware of interface scaling. 2025-09-29 22:11:02 +01:00
Peter NelsonandPeter Nelson 3087194d80 Codechange: Use Rects for group window drawing.
Simplifies handling of LTR/RTL coordinates.
2025-09-29 22:11:02 +01:00
Peter NelsonandGitHub 8a8ebabb9d Change: Provide road and rail overlay sprites for bridge decks. (#14557)
This allows bridges designed primarily with NewGRF railtypes and roadtypes to be at least somewhat compatible with built-in rail and road.
2025-09-29 22:08:16 +01:00
Rubidiumandrubidium42 aa7eb089c6 Codechange: make all Providers fully const (Font/Screenshot/Sound) 2025-09-29 23:39:13 +03:00
Peter NelsonandGitHub dcc3a67752 Fix 9cdf740097: Don't make copy of format providers when making a screenshot. (#14681)
While here, use projection instead of lambda to select provider.
2025-09-29 20:02:08 +00:00
Peter NelsonandGitHub f8aa2e64e4 Add: Include build cost in rail/road dropdowns. (#14599) 2025-09-29 19:23:02 +01:00
translators 8eaf511f0c Update: Translations from eints
english (us): 3 changes by 2TallTyler
galician: 9 changes by pvillaverde
2025-09-29 04:39:03 +00:00
SuandGitHub c8220494de Change: replace the "(City)" identifier in the town directory with the city icon (#14634) 2025-09-28 21:18:23 +02:00
Peter NelsonandPeter Nelson 29136350cf Codechange: Initialise rail/road types with range-for.
Replace double loop with single loop that performs both parts together.
2025-09-28 19:27:47 +01:00
Peter NelsonandPeter Nelson ca8fb69ffd Codechange: Use std algorithm when allocating rail/road type.
Use `std::ranges::find()` instead of a `for`-loop to allocate rail and road types.
2025-09-28 19:27:47 +01:00
Peter NelsonandPeter Nelson 126669e10d Codechange: Make GetRail/RoadTypeInfoIndex() a member method.
This follows a similar pattern used for cargoes, houses and objects.

Also fixes incorrect documentation of GetRoadTypeInfoIndex().
2025-09-28 19:27:47 +01:00
Peter NelsonandGitHub 5ed8f1203b Codechange: Cleanup unnecessary includes of spritecache.h (#14678) 2025-09-28 17:09:57 +00:00
Peter NelsonandGitHub ff674829f5 Codechange: Replace Rect CentreTo with CentreToHeight. (#14675)
So far all callers only need to centre vertically, so not having to provide the existing width simplifies calls.
2025-09-28 13:09:36 +00:00
Peter NelsonandPeter Nelson 81530e2574 Change: Support interface scaling in network client list buttons. 2025-09-28 11:00:07 +01:00
Peter NelsonandPeter Nelson cb1c2409e6 Codechange: Rework network client list buttons.
Instead of calculating and storing which buttons to display for each
line and then further calculating what each line should be when
displaying it, store everything on one pass.

This simplifies/deduplicates logic.
2025-09-28 11:00:07 +01:00
translators 37f737417c Update: Translations from eints
english (au): 3 changes by krysclarke
swedish: 3 changes by robert-i
korean: 3 changes by telk5093
greek: 3 changes by gh658804
russian: 3 changes by Ln-Wolf
finnish: 3 changes by hpiirai
catalan: 3 changes by J0anJosep
portuguese: 3 changes by jcteotonio
portuguese (brazilian): 3 changes by pasantoro
polish: 3 changes by pAter-exe
2025-09-28 04:37:53 +00:00
Peter NelsonandPeter Nelson 31eec7106b Codechange: Use Rect WithX/WithY in some places. 2025-09-28 00:31:23 +01:00
Peter NelsonandPeter Nelson 6d3f39609f Codechange: Add WithX/WithY methods to Rect.
This simplifies creating a new Rect with specific horizontal or vertical coordinates.
2025-09-28 00:31:23 +01:00
Peter NelsonandGitHub 380f9e8b48 Change: Prefer normal/medium weight font in FontConfig fallback detection. (#14672)
This way it behaves similar to Windows.
2025-09-28 00:30:47 +01:00
Rubidiumandrubidium42 e58fdb8840 Codefix: shadowing of variables 2025-09-28 01:19:32 +03:00
Jonathan G RennisonandGitHub f64e1cdae0 Fix: Industry accept/produce when not contiguous range from 0 (#14555) 2025-09-27 18:12:49 +01:00
Jonathan G RennisonandGitHub 9307e1929e Fix #14604: Clearing tiles to build objects did not update town ratings (#14616) 2025-09-27 18:11:42 +01:00
Peter NelsonandGitHub bfe5fb7339 Codechange: FlatSet's contains() should be const. (#14665)
This function does not modify contents, so should be marked const.
2025-09-27 18:10:39 +01:00
Peter NelsonandGitHub 0aaeb6f7e7 Codechange: Rename TrackFollowers to follower. (#14664)
Replaces use of codestyle breaking `F` in places.
2025-09-27 18:10:22 +01:00
Peter NelsonandGitHub 69ea970d6e Codefix 18e28077cc: Local variable icon shadowed member variable icon. (#14668)
Rename rects used in league table to avoid name shadowing. Now uses the same naming as in ScriptLeagueWindow.
2025-09-27 13:08:06 +01:00
Rubidiumandrubidium42 5e7cb08411 Fix #14549: changing interface scale could underflow map zoom 2025-09-27 07:41:20 +03:00
translators 910eeef17f Update: Translations from eints 2025-09-27 04:38:00 +00:00
Peter NelsonandGitHub 18e28077cc Fix: League Table layout broken with RTL languages. (#14667) 2025-09-27 01:50:33 +01:00
Peter NelsonandGitHub 41837d093b Change: Record and show multiple errors for each NewGRF. (#14658) 2025-09-26 19:00:45 +01:00
Tyler TrahanandGitHub 0b99a0b66a Feature: Draw infinite water when all borders are water (#13289) 2025-09-26 14:37:27 +00:00
KuhnovicandGitHub 5822c8cc65 Codechange: Set YAPF startup nodes directly. (#14663) 2025-09-26 16:33:20 +02:00
KuhnovicandGitHub aa6fb0e9e5 Codechange: Simplified logic of ship leaving a depot. (#14661) 2025-09-26 13:35:11 +02:00
KuhnovicandGitHub f4f1beba64 Codechange: Moved PruneIntermediateNodeBranch to rail pathfinder. (#14662) 2025-09-26 11:37:50 +02:00
KuhnovicandGitHub 6401855842 Fix bff8501: Gcc 15 warns about duplicate type. (#14660) 2025-09-26 10:04:50 +02:00
Peter NelsonandGitHub 80e58e751a Fix #14607: Bridge-over-station discrepancy depending on build order. (#14608)
When building a custom station, the callback-derived tile layout is ignored during the bridge height test. This caused a discrepancy between building a station under a bridge vs building a bridge over the same station.

Test the station tile layout callback during the bridge height test.
2025-09-24 22:45:18 +01:00
Peter NelsonandGitHub 42c9f84d74 Fix 3ac1a2f1e4: Game crash due to invalid vehicle type information. (#14628)
Use std::variant instead of union for vehicle info.

RailVehicleInfo is now non-POD so using in a union causes undefined behaviour.
2025-09-24 22:44:41 +01:00
KuhnovicandGitHub ecb761fc69 Codechange: Simplified structure of yapf_ship_regions. (#14640) 2025-09-24 21:34:01 +02:00
translators bec4e71d53 Update: Translations from eints
hungarian: 5 changes by vargaviktor
2025-09-24 04:37:55 +00:00
Peter NelsonandGitHub 6ad7c1c40a Fix d85f4b3ebf: Incorrect row height in network server list. (#14653) 2025-09-23 23:15:21 +01:00
Peter NelsonandGitHub 484ed1008a Codechange: Make TownRatingCheckType an enum class. (#14652) 2025-09-23 22:00:34 +01:00
Peter NelsonandGitHub 2b164111a9 Codechange: Use EnumBitSet for TownFlags. (#14651) 2025-09-22 19:04:55 +00:00
Peter NelsonandGitHub 43e65d04e4 Codefix: Incorrect naming and location of widget names for build docks window. (#14650) 2025-09-22 07:18:08 +01:00
translators 853dc245a0 Update: Translations from eints
chinese (simplified): 4 changes by WenSimEHRP
catalan: 5 changes by J0anJosep
2025-09-22 04:38:24 +00:00
Peter NelsonandGitHub 1229a498b7 Codechange: Add constant for INVALID_WIDGET. (#14649)
Replaces direct use of -1, making it easier to find.
2025-09-21 21:47:04 +00:00
Peter NelsonandGitHub 1278f62e2e Codechange: Call shorter variant of DrawFrameRect and GfxFillRect. (#14647)
Pass rect instead of breaking it up when possible.
2025-09-21 20:30:59 +01:00
Peter NelsonandGitHub 71eba489bc Codechange: Deduplicate DrawButtonDropdown. (#14646)
Use Rect methods to position components.
2025-09-21 20:26:06 +01:00
Peter NelsonandGitHub a7b06fc9f5 Codechange: Don't use Point for non-2D coordinate. (#14645)
`HandleScrollbarHittest` returns min and max coordinates, not x and y.
Also avoid referring to the min and max coordinates as top and bottom, as these functions are used for both vertical and horizontal scrollbars.
2025-09-21 14:57:53 +01:00
Peter NelsonandGitHub 29012c3fce Codechange: Move settings entry size global variables. (#14644)
_setting_circle_size and (the incorrectly named) SETTING_HEIGHT variables are now static members of BaseSettingEntry.

Neither of these are constants, so they no longer use constant naming style.
2025-09-21 13:41:47 +01:00
Peter NelsonandGitHub 13ab9c1adc Fix 6e90b828c6: Off-by-one in Rect::CentreTo. (#14643)
* Rect right/bottom are inclusive so -1 must be taken from width/height.
* Misnamed variable, `new_right` is actually `new_top`.
2025-09-21 13:41:23 +01:00
Peter NelsonandPeter Nelson 69697a62d3 Fix 8c58fb1efd: Doubled beep sounds when clicking toolbar buttons.
* ShowDropDownList() now issues a beep, so individual toolbar buttons no longer need to do it.
* HandleButtonClick() may be called twice for some buttons, as it is called by automatically for PUSH buttons.

This caused some beeps to sound louder than others.
2025-09-21 10:12:22 +01:00
Peter NelsonandPeter Nelson ce166bbbc3 Codechange: Demagicify main toolbar button type.
Use WWT_PUSHIMGBTN for non-menu buttons so they automatically raise, replacing the custom OnTimeout function.
2025-09-21 10:12:22 +01:00
Peter NelsonandGitHub 70d4182850 Fix #14631, Fix 1cb0cbcb6c: Waypoint customs spec not allocated properly on initial construction. (#14633)
Split AllocateSpecToStation/RoadStop into Allocate and Assign functions, allowing command tests to occur separately.
2025-09-21 09:32:25 +01:00
translators 030bbc6399 Update: Translations from eints
vietnamese: 4 changes by KhoiCanDev
2025-09-21 04:37:37 +00:00
Peter NelsonandGitHub d07ff71c67 Fix ed67aedabf: Wrong button type for town menu in scenario editor toolbar. (#14641)
The button was changed from an action to a menu, which should be WWT_IMGBTN instead of WWT_PUSHIMGBTN.
2025-09-21 01:25:31 +00:00
Tyler Trahan 20067d2db5 Doc: Update station rating comments and doxygen. 2025-09-20 19:28:40 -04:00
Tyler Trahan 2ab3b5516f Codechange: Early continue for cargos not moved by this station 2025-09-20 19:28:40 -04:00
KuhnovicandGitHub 1ac5baab31 Change: Add lock penalty to ship pathfinder. (#14603) 2025-09-20 22:52:59 +02:00
KuhnovicandGitHub bff850128c Codechange: Use YAPF for river builder pathfinder. (#14606) 2025-09-20 21:42:06 +02:00
translators 2aaffbe23c Update: Translations from eints
korean: 8 changes by telk5093
dutch: 4 changes by Afoklala
portuguese: 10 changes by jcteotonio
2025-09-20 04:37:32 +00:00
Peter NelsonandGitHub 68e37b7b50 Change: [Script] Decouple RAILTYPE_INVALID from internal presentation. (#14630)
RAILTYPE_INVALID is now -1, which matches ROADTYPE_INVALID.
2025-09-19 22:02:08 +01:00
translators 264cbd8ab5 Update: Translations from eints
english (au): 4 changes by krysclarke
portuguese: 13 changes by jcteotonio
2025-09-19 04:38:27 +00:00
Peter NelsonandGitHub 17fbe0b911 Change: Determine automatic interface scale by window size. (#14627)
Replace OS-dependent interface scaling with scaling dependent on the window size.

This works on all platforms and should provide a more comfortable experience for new players. Manual interface scale setting works as before.
2025-09-18 18:52:14 +01:00
translators 2d13bcb7b9 Update: Translations from eints
french: 5 changes by ottdfevr
portuguese: 31 changes by jcteotonio
2025-09-18 04:37:46 +00:00
Jonathan G RennisonandGitHub d54bf49936 Fix: Variant cycle detection in FinaliseEngineArray (#14629) 2025-09-17 22:42:42 +01:00
KuhnovicandGitHub 262c364a28 Fix #14620: Use full file path when deleting files. (#14623) 2025-09-17 21:43:22 +02:00
Peter NelsonandGitHub 129825077b Change: Apply interface scale to window snap distance. (#14625) 2025-09-17 12:29:16 +01:00
translators 445d2b3e22 Update: Translations from eints
swedish: 2 changes by robert-i
norwegian (bokmal): 4 changes by eriksorngard
chinese (traditional): 5 changes by KogentaSan
english (us): 5 changes by 2TallTyler
greek: 2 changes by gh658804
russian: 2 changes by Ln-Wolf
finnish: 2 changes by hpiirai
danish: 2 changes by bscargo
portuguese: 6 changes by jcteotonio
portuguese (brazilian): 9 changes by pasantoro
polish: 12 changes by pAter-exe
2025-09-17 04:37:43 +00:00
translators f487cde056 Update: Translations from eints
swedish: 2 changes by robert-i
greek: 2 changes by gh658804
russian: 3 changes by Ln-Wolf
finnish: 2 changes by hpiirai
danish: 3 changes by New-Authentication
portuguese: 44 changes by jcteotonio
portuguese (brazilian): 2 changes by pasantoro
polish: 2 changes by pAter-exe
2025-09-16 04:37:32 +00:00
Tyler TrahanandGitHub 5dea170589 Fix #14588: Show error when unable to clone partly-cleared crashed train (#14591) 2025-09-15 19:05:35 -04:00
KuhnovicandGitHub faacae2c3f Change: Removed disable_node_optimization YAPF setting (#14578) 2025-09-15 21:59:12 +02:00
KuhnovicandGitHub 26fef5b62b Fix 4eaeccd: FioRemove should return false if the file does not exist. (#14619) 2025-09-15 21:17:18 +02:00
Peter NelsonandGitHub f2f6609206 Fix #14572: Incorrect playlist entry was removed if there are duplicates. (#14583) 2025-09-15 18:52:07 +01:00
Peter NelsonandGitHub 5f20a97b36 Fix 313c6c45aa: [Script] Return rail types as list instead of bitmask. (#14617)
This is more idiomatic for scripts, and avoids exposing internal representation.
2025-09-15 13:59:04 +01:00
KuhnovicandGitHub 7d252ff7fc Change: Ask for confirmation before deleting a savegame / scenario / heightmap. (#14621) 2025-09-15 13:14:56 +02:00
Peter NelsonandGitHub 7240ed5817 Cleanup 3ac1a2f1e4: Don't load/save a train's railtypes property. (#14618)
A train's railtypes property is always reset by Train::ConsistChanged on load, so storing is not necessary.
2025-09-15 08:21:09 +01:00
translators c111abad37 Update: Translations from eints
portuguese: 1 change by jcteotonio
2025-09-15 04:38:59 +00:00
Michael Lutz 52e97c981c Add: Show all railtypes in the build vehicle and engine preview dialogs. 2025-09-14 17:11:26 +02:00
Michael Lutz 313c6c45aa Add: [Script] Function to get all rail types of an rail engine. 2025-09-14 17:11:26 +02:00
Michael Lutz 1779da51c2 Add: [NewGRF] Train property to set multiple track types for an engine. 2025-09-14 17:11:26 +02:00
Michael Lutz 3ac1a2f1e4 Codechange: Store the rail type of rail engines as a RailTypes bitmask. 2025-09-14 17:11:26 +02:00
Michael Lutz 0715903b24 Codechange: Use an enum for vehicle acceleration model. 2025-09-14 17:11:26 +02:00
translators 748700bd9e Update: Translations from eints
catalan: 2 changes by J0anJosep
latvian: 53 changes by lexuslatvia
portuguese: 36 changes by jcteotonio
2025-09-14 04:38:01 +00:00
translators 96b59af4d1 Update: Translations from eints
norwegian (bokmal): 2 changes by eriksorngard
vietnamese: 14 changes by KhoiCanDev
russian: 1 change by Ln-Wolf
dutch: 1 change by Afoklala
2025-09-13 04:36:41 +00:00
Peter NelsonandGitHub 3356aa7c69 Codechange: Remove two vector typedefs which are only used once. (#14612) 2025-09-12 19:41:18 +01:00
Peter NelsonandGitHub ee664f7e8c Codechange: Prefer EnumBitSet's All() method over bitwise comparisons. (#14611)
This makes the intent of the operation clearer.
2025-09-12 19:37:17 +01:00
Peter NelsonandGitHub b1dc37fb05 Fix 9a294ab2ed: Bridge height check for waypoints didn't include axis in layout. (#14609)
It's unlikely that X and Y axis waypoints have different heights, but not impossible.
2025-09-12 08:28:42 +01:00
translators 3317997976 Update: Translations from eints
english (au): 1 change by krysclarke
swedish: 1 change by robert-i
chinese (traditional): 1 change by KogentaSan
chinese (simplified): 2 changes by WenSimEHRP
korean: 1 change by telk5093
greek: 1 change by gh658804
finnish: 1 change by hpiirai
portuguese: 9 changes by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 1 change by Rito13
2025-09-12 04:43:48 +00:00
Peter NelsonandGitHub d095526406 Codechange: Range-check rail/road/tram maps by size instead of constant. (#14602)
* Compare against the size of the array instead of the constant used to define the array.
* `type_map` alias now uses auto to avoid defining the type each time.
* `_cur_gps.grffile->railtype_map` is now aliased to `type_map` to simplify and standardise.
2025-09-11 12:31:34 +01:00
translators fe9093df96 Update: Translations from eints
english (us): 1 change by 2TallTyler
korean: 1 change by telk5093
hungarian: 1 change by vargaviktor
danish: 2 changes by New-Authentication
dutch: 1 change by nicobresseleers
portuguese: 12 changes by jcteotonio
2025-09-11 04:37:58 +00:00
Peter NelsonandGitHub e10200efa4 Change: Allow bridges over locks. (#14595)
The bridge must be at least 2 levels higher than the lock.
2025-09-10 18:41:56 +01:00
translators eb09d18418 Update: Translations from eints
english (au): 1 change by krysclarke
swedish: 1 change by robert-i
chinese (traditional): 1 change by KogentaSan
vietnamese: 1 change by KhoiCanDev
greek: 1 change by gh658804
russian: 1 change by Ln-Wolf
finnish: 1 change by hpiirai
portuguese: 76 changes by jcteotonio
portuguese (brazilian): 1 change by pasantoro
polish: 4 changes by pAter-exe
2025-09-10 04:36:50 +00:00
translators 033114da8c Update: Translations from eints
italian: 64 changes by Boh132Boh
portuguese: 172 changes by jcteotonio
2025-09-09 04:38:39 +00:00
Peter NelsonandGitHub 5f84ff5c3f Change: Allow bridges over docks. (#14594) 2025-09-08 21:43:31 +01:00
Peter NelsonandGitHub 43842f0bcc Fix: Don't add spacing in rail/road type dropdowns if no badges are present. (#14598) 2025-09-08 21:42:49 +01:00
translators 16cd420e4c Update: Translations from eints
portuguese: 44 changes by jcteotonio
portuguese (brazilian): 6 changes by jcteotonio
2025-09-08 04:40:24 +00:00
Peter NelsonandGitHub 89a90080c5 Codechange: Split table data out of rail.cpp (#14597) 2025-09-07 15:44:54 +00:00
Peter NelsonandGitHub 80541a7682 Fix c02ef3e456: [AI] Incorrect infrastructure cost for road/tram tiles. (#14596)
Infrastructure total count should be split between road and tram pieces.
2025-09-07 14:11:05 +01:00
translators f82bd95faf Update: Translations from eints
portuguese: 25 changes by jcteotonio
2025-09-07 04:37:41 +00:00
translators 64dbb9383b Update: Translations from eints
chinese (traditional): 1 change by KogentaSan
danish: 28 changes by New-Authentication
portuguese: 30 changes by jcteotonio
2025-09-06 04:38:23 +00:00
Peter NelsonandGitHub 244a267304 Codechange: Give better names to water tile layouts. (#14592) 2025-09-05 19:02:00 +00:00
Peter NelsonandGitHub a2f3d59707 Codefix: Use of nullptr instead of std::nullopt. (#14590) 2025-09-05 14:05:02 +01:00
translators 122023be8d Update: Translations from eints
danish: 10 changes by New-Authentication
french: 1 change by ottdfevr
2025-09-05 04:39:06 +00:00
Peter NelsonandGitHub 6613da5d7e Fix #14586, Fix 069ff846e4: Empty station tile layouts incorrectly substituted with default layouts. (#14587)
It is no longer possible for a layout to be missing, so the nullptr check should have been removed.
2025-09-04 21:11:02 +00:00
Peter NelsonandGitHub 8d96ea1a5e Fix #14584: Crash due to drawing non-existent orders of new vehicle. (#14585)
When the vehicle list window is grouped by orders, no check was made that vehicle's order list existed.
2025-09-04 02:18:26 +00:00
Peter NelsonandGitHub 4ed4a8b602 Codechange: Remove MusicSystem::displayed_playlist. (#14582)
It is not actually used for display, and is basically a copy of the standard playlist with duplicated maintenance.
2025-09-04 02:56:19 +01:00
Peter NelsonandGitHub 5d15c8b8ab Fix: Wrong row may be selected in music playlists. (#14581)
Include frame offset when clicking on music playlist to ensure the correct row is selected.
2025-09-03 18:02:26 +00:00
Peter NelsonandGitHub f3951214c1 Codechange: Shuffle MusicSongInfo members to reduce alignment padding. (#14580) 2025-09-03 17:22:50 +00:00
KuhnovicandGitHub 80f672d5b4 Codechange: Remove redundant data members from YAPF ship node. (#14577) 2025-09-03 12:52:15 +02:00
translators 5602555a7a Update: Translations from eints
danish: 8 changes by New-Authentication
2025-09-03 04:38:23 +00:00
Peter NelsonandGitHub 736998b595 Codechange: Use span instead of raw pointer for animated cursors. (#14575)
This allows the terminator entry to be removed.
2025-09-02 21:48:24 +01:00
Peter NelsonandGitHub 7d4282b341 Fix #14569: Ensure music playlist window is large enough. (#14570)
Take number of tracks allowed in custom playlist into account, instead of just the number of tracks loaded.
2025-09-02 20:18:33 +01:00
Cornelius DiekmannandGitHub dd426bb8c7 Codefix f6555cf: fix comment track vs. tile (#14571) 2025-09-02 13:55:08 +02:00
Loïc GuillouxandGitHub 7a6e04561d Fix #14278, ccd586a7: [Script] Don't set members inside operator new() (#14568) 2025-09-02 12:58:31 +02:00
translators fce2748bb7 Update: Translations from eints
portuguese: 5 changes by jcteotonio
2025-09-02 04:39:43 +00:00
Peter NelsonandGitHub 960b840291 Fix 6d6e64b1f0: Road stop properties 0x13/0x14 were not skipped properly. (#14567)
These properties where changed to be variable length for consistency, but ignoring them treated them as fixed length.
2025-09-01 18:52:55 +01:00
Peter NelsonandGitHub 73045f9b0e Fix #13922: Ensure music track no widget is wide enough for track no. (#14566) 2025-09-01 08:44:33 +00:00
translators 4c77026167 Update: Translations from eints
galician: 2 changes by pvillaverde
vietnamese: 24 changes by MagicalDrizzle
french: 1 change by ottdfevr
2025-09-01 04:42:09 +00:00
Peter NelsonandGitHub ff5e067341 Fix 7b60e5ccad: Badge filters were only applied to trains. (#14565) 2025-08-31 23:04:48 +01:00
503 changed files with 9077 additions and 7087 deletions
+2
View File
@@ -10,3 +10,5 @@ query-filters:
- cpp/irregular-enum-init
# Our GUI code tends to use switches for OnClick handlers, DrawWidget, and UpdateWidgetSize. Sometimes GUIs just don't have many elements, but we want to keep consistency.
- cpp/trivial-switch
# Our (GUI) code tends to use long switches.
- cpp/long-switch
+2
View File
@@ -8,3 +8,5 @@ updates:
actions:
patterns:
- "*"
commit-message:
prefix: "Upgrade: "
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Fix dubious ownership
run: |
+6 -6
View File
@@ -30,7 +30,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup vcpkg
uses: ./.github/actions/setup-vcpkg
@@ -78,15 +78,15 @@ jobs:
mkdir -p ~/.local/share/openttd/baseset
cd ~/.local/share/openttd/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::group::Download OpenGFX2"
curl -L https://cdn.openttd.org/opengfx2_classic-releases/0.8/opengfx2_classic-0.8-all.zip -o opengfx2-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::group::Unpack OpenGFX2"
unzip opengfx2-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
rm -f opengfx2-all.zip
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
+6 -6
View File
@@ -32,7 +32,7 @@ jobs:
xcode-version: latest-stable
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup vcpkg
uses: ./.github/actions/setup-vcpkg
@@ -45,15 +45,15 @@ jobs:
mkdir -p ~/Documents/OpenTTD/baseset
cd ~/Documents/OpenTTD/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::group::Download OpenGFX2"
curl -L https://cdn.openttd.org/opengfx2_classic-releases/0.8/opengfx2_classic-0.8-all.zip -o opengfx2-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::group::Unpack OpenGFX2"
unzip opengfx2-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
rm -f opengfx2-all.zip
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
+6 -6
View File
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
@@ -47,15 +47,15 @@ jobs:
mkdir -p "C:/Users/Public/Documents/OpenTTD/baseset"
cd "C:/Users/Public/Documents/OpenTTD/baseset"
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::group::Download OpenGFX2"
curl -L https://cdn.openttd.org/opengfx2_classic-releases/0.8/opengfx2_classic-0.8-all.zip -o opengfx2-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::group::Unpack OpenGFX2"
unzip opengfx2-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
rm -f opengfx2-all.zip
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
+6 -6
View File
@@ -18,7 +18,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup vcpkg
uses: ./.github/actions/setup-vcpkg
@@ -31,15 +31,15 @@ jobs:
mkdir -p "C:/Users/Public/Documents/OpenTTD/baseset"
cd "C:/Users/Public/Documents/OpenTTD/baseset"
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::group::Download OpenGFX2"
curl -L https://cdn.openttd.org/opengfx2_classic-releases/0.8/opengfx2_classic-0.8-all.zip -o opengfx2-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::group::Unpack OpenGFX2"
unzip opengfx2-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
rm -f opengfx2-all.zip
- name: Install MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master
+5 -4
View File
@@ -21,10 +21,11 @@ jobs:
actions: read
contents: read
security-events: write
packages: read
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Setup vcpkg
uses: ./.github/actions/setup-vcpkg
@@ -76,7 +77,7 @@ jobs:
echo "::endgroup::"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: cpp
config-file: ./.github/codeql/codeql-config.yml
@@ -92,7 +93,7 @@ jobs:
echo "::endgroup::"
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: /language:cpp
upload: False
@@ -110,6 +111,6 @@ jobs:
output: sarif-results/cpp.sarif
- name: Upload results
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: sarif-results/cpp.sarif
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 4
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
+2 -2
View File
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
@@ -78,7 +78,7 @@ jobs:
echo "::endgroup::"
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: openttd-docs
path: build/bundles/*.tar.xz
+3 -3
View File
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
@@ -156,14 +156,14 @@ jobs:
echo "::endgroup::"
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: openttd-linux-generic
path: build/bundles
retention-days: 5
- name: Store symbols
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: symbols-linux-generic
path: build/symbols
+3 -3
View File
@@ -23,7 +23,7 @@ jobs:
xcode-version: latest-stable
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
@@ -205,14 +205,14 @@ jobs:
mv _CPack_Packages/*/Bundle/openttd-*.zip bundles/
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: openttd-macos-universal
path: build-x64/bundles
retention-days: 5
- name: Store symbols
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: symbols-macos-universal
path: build-x64/symbols
+5 -5
View File
@@ -30,14 +30,14 @@ jobs:
steps:
- name: Checkout (Release)
if: github.event_name == 'release'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
# We generate a changelog; for this we need the full git log.
fetch-depth: 0
- name: Checkout (Manual)
if: github.event_name == 'workflow_dispatch'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ github.event.inputs.ref }}
# We generate a changelog; for this we need the full git log.
@@ -45,7 +45,7 @@ jobs:
- name: Checkout (Trigger)
if: github.event_name == 'repository_dispatch'
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
ref: ${{ github.event.client_payload.ref }}
# We generate a changelog; for this we need the full git log.
@@ -202,14 +202,14 @@ jobs:
echo "::endgroup::"
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: openttd-source
path: build/bundles/*
retention-days: 5
- name: Store source (for other jobs)
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: internal-source
path: source.tar.gz
+11 -11
View File
@@ -15,7 +15,7 @@ jobs:
steps:
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
@@ -25,17 +25,17 @@ jobs:
tar -xf source.tar.gz --strip-components=1
- name: Download x86 build
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-x86
- name: Download x64 build
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-x64
- name: Download arm64 build
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-arm64
@@ -74,16 +74,16 @@ jobs:
mkdir -p builds/common-binaries/baseset
cd builds/common-binaries/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/7.1/opengfx-7.1-all.zip -o opengfx-all.zip
echo "::group::Download OpenGFX2"
curl -L https://cdn.openttd.org/opengfx2_classic-releases/0.8/opengfx2_classic-0.8-all.zip -o opengfx2_classic.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
tar xf opengfx-*.tar
echo "::group::Unpack OpenGFX2"
unzip opengfx2_classic.zip
tar xf OpenGFX2_Classic-0.8.tar
echo "::endgroup::"
rm -f opengfx-all.zip opengfx-*.tar
rm -f opengfx2_classic.zip OpenGFX2_Classic-0.8.tar
- name: Install OpenMSX
shell: bash
@@ -185,7 +185,7 @@ jobs:
move output\OpenTTD.appxbundle bundles\internal\openttd-${{ inputs.version }}-windows-store.appxbundle
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: openttd-windows-store
path: builds/bundles
+3 -3
View File
@@ -30,7 +30,7 @@ jobs:
steps:
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
@@ -194,14 +194,14 @@ jobs:
AZURE_CODESIGN_PROFILE_NAME: ${{ secrets.AZURE_CODESIGN_PROFILE_NAME }}
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: openttd-windows-${{ matrix.arch }}
path: build/bundles
retention-days: 5
- name: Store symbols
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: symbols-windows-${{ matrix.arch }}
path: build/symbols
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Check for finding script functions that require company/deity mode enforcement/checks
run: |
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Check for unused strings
run: |
+4 -4
View File
@@ -21,7 +21,7 @@ jobs:
steps:
- name: Download all bundles
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
- name: Calculate checksums
run: |
@@ -70,14 +70,14 @@ jobs:
done
- name: Store bundles
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: cdn-bundles
path: bundles/*
retention-days: 5
- name: Store breakpad symbols
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: cdn-symbols
path: symbols/*
@@ -130,7 +130,7 @@ jobs:
installation_retrieval_payload: "OpenTTD/workflows"
- name: Trigger 'Publish Docs'
uses: peter-evans/repository-dispatch@v3
uses: peter-evans/repository-dispatch@v4
with:
token: ${{ steps.generate_token.outputs.token }}
repository: OpenTTD/workflows
+11 -11
View File
@@ -15,31 +15,31 @@ jobs:
steps:
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
path: internal-source
- name: Download bundle (Windows x86)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-x86
path: openttd-windows-x86
- name: Download bundle (Windows x64)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-x64
path: openttd-windows-x64
- name: Download bundle (MacOS)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-macos-universal
path: openttd-macos-universal
- name: Download bundle (Linux)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-linux-generic
path: openttd-linux-generic
@@ -56,16 +56,16 @@ jobs:
mkdir -p gog/opengfx/baseset
cd gog/opengfx/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/7.1/opengfx-7.1-all.zip -o opengfx-all.zip
echo "::group::Download OpenGFX2"
curl -L https://cdn.openttd.org/opengfx2_classic-releases/0.8/opengfx2_classic-0.8-all.zip -o opengfx2_classic.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
tar xf opengfx-*.tar
echo "::group::Unpack OpenGFX2"
unzip opengfx2_classic.zip
tar xf OpenGFX2_Classic-0.8.tar
echo "::endgroup::"
rm -f opengfx-all.zip opengfx-*.tar
rm -f opengfx2_classic.zip OpenGFX2_Classic-0.8.tar
- name: Install OpenMSX
shell: bash
+5 -5
View File
@@ -18,31 +18,31 @@ jobs:
steps:
- name: Download source
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: internal-source
path: internal-source
- name: Download bundle (Windows x86)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-x86
path: openttd-windows-x86
- name: Download bundle (Windows x64)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-windows-x64
path: openttd-windows-x64
- name: Download bundle (MacOS)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-macos-universal
path: openttd-macos-universal
- name: Download bundle (Linux)
uses: actions/download-artifact@v4
uses: actions/download-artifact@v6
with:
name: openttd-linux-generic
path: openttd-linux-generic
+23
View File
@@ -196,6 +196,29 @@ These include:
You may also want the guide to [compiling OpenTTD](./COMPILING.md).
## Use of AI
OpenTTD is a labour of love, created by people.
Please refrain from submitting issues or pull requests that have been generated by an LLM or other fully-automated tools.
Any submission that is in violation of this policy will be closed, and the submitter may be blocked from this repository without warning.
If you submit an issue, you need to understand what your issue description is saying.
You need to be able to answer questions about your bug report or feature request.
Using an AI tool to _proofread_ your issue/comment text is acceptable. Using an AI tool to _write_ your issue/comment text is not.
If you submit a pull request, you need to understand what every line of code you've changed does.
If you can't explain why your PR is doing something, then do not submit it.
Using an AI tool to generate entire lines of code is unacceptable.
The rationale behind this policy is that automated contributions are a waste of the maintainers' time.
Humans spend their time and brainpower reviewing every submission.
Issues or pull requests generated by automation tools create an imbalance of effort between the submitter and the reviewer.
Nobody learns anything when a maintainer reviews code written by an LLM.
Additionally, AI-generated code conflicts with this project's license (GPL v2), since you cannot truly release code for use if you didn't author it yourself.
## Project goals
### What are the goals of the official branch?
+1 -1
View File
@@ -6,7 +6,7 @@ GNU General Public License
_Version 2, June 1991_
_Copyright © 1989, 1991 Free Software Foundation, Inc.,_
_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
_[https://fsf.org/](https://fsf.org/)_
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
+13
View File
@@ -25,6 +25,12 @@ if(EDITBIN_EXECUTABLE)
execute_process(COMMAND ${EDITBIN_EXECUTABLE} /nologo /subsystem:console ${OPENTTD_EXECUTABLE})
endif()
# Remove previous crash files
file(GLOB CRASH_FILES "regression/crash*")
if(CRASH_FILES)
file(REMOVE ${CRASH_FILES})
endif()
# Run the regression test
execute_process(COMMAND ${OPENTTD_EXECUTABLE}
-x
@@ -40,6 +46,13 @@ execute_process(COMMAND ${OPENTTD_EXECUTABLE}
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Detect any crash
file(GLOB CRASH_FILES "regression/crash*.log")
if (CRASH_FILES)
file(READ ${CRASH_FILES} CRASH_LOG)
message(FATAL_ERROR "OpenTTD crashed: ${CRASH_LOG}")
endif()
if(REGRESSION_OUTPUT)
message(FATAL_ERROR "Unexpected output: ${REGRESSION_OUTPUT}")
endif()
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
eb8390a0569e66ec417c64ad254f9d05
c56aad31380c077d619e124bd87c8270
+3
View File
@@ -10,6 +10,7 @@ if(GRFCODEC_FOUND)
${CMAKE_CURRENT_SOURCE_DIR}/airport_preview.nfo
${CMAKE_CURRENT_SOURCE_DIR}/aqueduct.nfo
${CMAKE_CURRENT_SOURCE_DIR}/autorail.nfo
${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks.nfo
${CMAKE_CURRENT_SOURCE_DIR}/canals.nfo
${CMAKE_CURRENT_SOURCE_DIR}/chars.nfo
${CMAKE_CURRENT_SOURCE_DIR}/elrails.nfo
@@ -31,6 +32,8 @@ if(GRFCODEC_FOUND)
${CMAKE_CURRENT_SOURCE_DIR}/airport_preview.png
${CMAKE_CURRENT_SOURCE_DIR}/aqueduct.png
${CMAKE_CURRENT_SOURCE_DIR}/autorail.png
${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks.png
${CMAKE_CURRENT_SOURCE_DIR}/bridge_decks_toyland.png
${CMAKE_CURRENT_SOURCE_DIR}/canals.png
${CMAKE_CURRENT_SOURCE_DIR}/canal_locks.png
${CMAKE_CURRENT_SOURCE_DIR}/chars.png
+70
View File
@@ -0,0 +1,70 @@
// This file is part of OpenTTD.
// OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
// OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
//
-1 * 0 0C "Bridge decks"
-1 * 0 07 83 01 \7= 03 19
-1 * 3 05 1B 18
-1 sprites/bridge_decks.png 8bpp 96 16 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 16 16 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 176 16 64 39 -31 -8 normal
-1 sprites/bridge_decks.png 8bpp 256 16 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 336 16 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 416 16 64 39 -31 -8 normal
-1 sprites/bridge_decks.png 8bpp 96 71 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 16 71 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 176 71 64 39 -31 -8 normal
-1 sprites/bridge_decks.png 8bpp 256 71 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 336 71 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 416 71 64 39 -31 -8 normal
-1 sprites/bridge_decks.png 8bpp 96 126 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 16 126 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 176 126 64 39 -31 -8 normal
-1 sprites/bridge_decks.png 8bpp 256 126 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 336 126 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 416 126 64 39 -31 -8 normal
// X and Y axis are swapped for road surface.
-1 sprites/bridge_decks.png 8bpp 16 181 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 96 181 64 31 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 176 181 64 39 -31 -8 normal
-1 sprites/bridge_decks.png 8bpp 256 181 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 336 181 64 23 -31 0 normal
-1 sprites/bridge_decks.png 8bpp 416 181 64 39 -31 -8 normal
// Toyland bridge decks, skip if not toyland.
-1 * 0 07 83 01 \7! 03 19
-1 * 3 05 1B 18
-1 sprites/bridge_decks_toyland.png 8bpp 96 16 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 16 16 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 176 16 64 39 -31 -8 normal
-1 sprites/bridge_decks_toyland.png 8bpp 256 16 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 336 16 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 416 16 64 39 -31 -8 normal
-1 sprites/bridge_decks_toyland.png 8bpp 96 71 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 16 71 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 176 71 64 39 -31 -8 normal
-1 sprites/bridge_decks_toyland.png 8bpp 256 71 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 336 71 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 416 71 64 39 -31 -8 normal
-1 sprites/bridge_decks_toyland.png 8bpp 96 126 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 16 126 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 176 126 64 39 -31 -8 normal
-1 sprites/bridge_decks_toyland.png 8bpp 256 126 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 336 126 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 416 126 64 39 -31 -8 normal
// X and Y axis are swapped for road surface.
-1 sprites/bridge_decks_toyland.png 8bpp 16 181 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 96 181 64 31 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 176 181 64 39 -31 -8 normal
-1 sprites/bridge_decks_toyland.png 8bpp 256 181 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 336 181 64 23 -31 0 normal
-1 sprites/bridge_decks_toyland.png 8bpp 416 181 64 39 -31 -8 normal
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

+1
View File
@@ -100,3 +100,4 @@
#include "palette.nfo"
#include "road_waypoints.nfo"
#include "overlay_rocks.nfo"
#include "bridge_decks.nfo"
+23
View File
@@ -461,6 +461,21 @@ function Regression::Company()
}
}
function Regression::CompanyGender()
{
print("");
print("--Company Gender--");
/* Check gender switching behaviour matches API. */
print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
print(" SetPresidentGender(): " + AICompany.SetPresidentGender(AICompany.GENDER_MALE));
print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
print(" SetPresidentGender(): " + AICompany.SetPresidentGender(AICompany.GENDER_FEMALE));
print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
/* Setting to existing gender should fail. */
print(" SetPresidentGender(): " + AICompany.SetPresidentGender(AICompany.GENDER_FEMALE));
print(" GetPresidentGender(): " + AICompany.GetPresidentGender(AICompany.COMPANY_SELF));
}
function Regression::Engine()
{
local j = 0;
@@ -487,6 +502,13 @@ function Regression::Engine()
print(" GetRailType(): " + AIEngine.GetRailType(i));
print(" GetRoadType(): " + AIEngine.GetRoadType(i));
print(" GetPlaneType(): " + AIEngine.GetPlaneType(i));
local railtypes = AIEngine.GetAllRailTypes(i);
print(" GetAllRailTypes(): " + (railtypes == null ? "null" : "instance"));
if (railtypes != null) {
foreach(t in railtypes) {
print(" " + t);
}
}
}
print(" Valid Engines: " + j);
}
@@ -2089,6 +2111,7 @@ function Regression::Start()
this.Vehicle();
/* Order has to be after Vehicle */
this.Order();
this.CompanyGender();
print("");
print(" First Subsidy Test");
PrintSubsidy(0);
File diff suppressed because it is too large Load Diff
+7 -4
View File
@@ -18,7 +18,8 @@ void sqstd_printcallstack(HSQUIRRELVM v)
SQFloat f;
SQInteger level=1; //1 is to skip this function that is level 0
SQInteger seq=0;
pf(v,"\nCALLSTACK\n");
pf(v,"\n");
pf(v,"CALLSTACK\n");
while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si)))
{
std::string_view fn="unknown";
@@ -37,7 +38,8 @@ void sqstd_printcallstack(HSQUIRRELVM v)
level++;
}
level=0;
pf(v,"\nLOCALS\n");
pf(v,"\n");
pf(v,"LOCALS\n");
for(level=0;level<10;level++){
seq=0;
@@ -116,11 +118,12 @@ static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v)
if(pf) {
std::string_view error;
if(sq_gettop(v)>=1) {
pf(v,"\n");
if(SQ_SUCCEEDED(sq_getstring(v,2,error))) {
pf(v,fmt::format("\nAN ERROR HAS OCCURRED [{}]\n",error));
pf(v,fmt::format("AN ERROR HAS OCCURRED [{}]\n",error));
}
else{
pf(v,"\nAN ERROR HAS OCCURRED [unknown]\n");
pf(v,"AN ERROR HAS OCCURRED [unknown]\n");
}
sqstd_printcallstack(v);
}
+2 -2
View File
@@ -58,7 +58,7 @@ HSQUIRRELVM sq_open(SQInteger initialstacksize)
SQVM *v;
sq_new(ss, SQSharedState);
v = (SQVM *)SQ_MALLOC(sizeof(SQVM));
new (v) SQVM(ss);
new (v, sizeof(SQVM)) SQVM(ss);
ss->_root_vm = v;
if(v->Init(nullptr, initialstacksize)) {
return v;
@@ -76,7 +76,7 @@ HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize)
ss=_ss(friendvm);
v= (SQVM *)SQ_MALLOC(sizeof(SQVM));
new (v) SQVM(ss);
new (v, sizeof(SQVM)) SQVM(ss);
if(v->Init(friendvm, initialstacksize)) {
friendvm->Push(v);
+1 -1
View File
@@ -13,7 +13,7 @@ private:
public:
static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){
SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray));
new (newarray) SQArray(ss,nInitialSize);
new (newarray, sizeof(SQArray)) SQArray(ss,nInitialSize);
return newarray;
}
#ifndef NO_GARBAGE_COLLECTOR
+3 -3
View File
@@ -34,7 +34,7 @@ struct SQClass : public CHAINABLE_OBJ
public:
static SQClass* Create(SQSharedState *ss,SQClass *base) {
SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass));
new (newclass) SQClass(ss, base);
new (newclass, sizeof(SQClass)) SQClass(ss, base);
return newclass;
}
~SQClass();
@@ -90,7 +90,7 @@ public:
SQInteger size = calcinstancesize(theclass);
SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);
new (newinst) SQInstance(ss, theclass,size);
new (newinst, size) SQInstance(ss, theclass,size);
if(theclass->_udsize) {
newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize);
}
@@ -100,7 +100,7 @@ public:
{
SQInteger size = calcinstancesize(_class);
SQInstance *newinst = (SQInstance *)SQ_MALLOC(size);
new (newinst) SQInstance(ss, this,size);
new (newinst, size) SQInstance(ss, this,size);
if(_class->_udsize) {
newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize);
}
+3 -3
View File
@@ -11,7 +11,7 @@ private:
public:
static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){
SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure));
new (nc) SQClosure(ss,func);
new (nc, sizeof(SQClosure)) SQClosure(ss,func);
return nc;
}
void Release() override {
@@ -49,7 +49,7 @@ private:
public:
static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){
SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator));
new (nc) SQGenerator(ss,closure);
new (nc, sizeof(SQGenerator)) SQGenerator(ss,closure);
return nc;
}
~SQGenerator()
@@ -85,7 +85,7 @@ public:
static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func)
{
SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure));
new (nc) SQNativeClosure(ss,func);
new (nc, sizeof(SQNativeClosure)) SQNativeClosure(ss,func);
return nc;
}
SQNativeClosure *Clone()
+3 -2
View File
@@ -99,8 +99,9 @@ public:
{
SQFunctionProto *f;
//I compact the whole class and members in a single memory allocation
f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams));
new (f) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams);
SQInteger size = _FUNC_SIZE(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams);
f = (SQFunctionProto *)sq_vm_malloc(size);
new (f, size) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams);
return f;
}
void Release() override {
+2 -1
View File
@@ -91,7 +91,8 @@ SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx)
SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)
{
if(!_weakref) {
sq_new(_weakref,SQWeakRef);
_weakref = (SQWeakRef *)sq_vm_malloc(sizeof(SQWeakRef));
new (_weakref, sizeof(SQWeakRef)) SQWeakRef();
_weakref->_obj._type = type;
_weakref->_obj._unVal.pRefCounted = this;
}
+5 -8
View File
@@ -64,22 +64,19 @@ struct SQRefCounted
virtual void Release()=0;
/* Placement new/delete to prevent memory leaks if constructor throws an exception. */
inline void *operator new(size_t size, SQRefCounted *place)
inline void *operator new([[maybe_unused]] size_t size, void *ptr, [[maybe_unused]] size_t real_size)
{
place->size = size;
return place;
assert(size <= real_size);
return ptr;
}
inline void operator delete(void *ptr, SQRefCounted *place)
inline void operator delete(void *ptr, void *, size_t real_size)
{
SQ_FREE(ptr, place->size);
SQ_FREE(ptr, real_size);
}
/* Never used but required. */
inline void operator delete(void *) { NOT_REACHED(); }
private:
size_t size = 0;
};
struct SQWeakRef : SQRefCounted
+1 -1
View File
@@ -553,7 +553,7 @@ SQString *SQStringTable::Add(std::string_view new_string)
}
SQString *t=(SQString *)SQ_MALLOC(len+sizeof(SQString));
new (t) SQString(new_string);
new (t, len+sizeof(SQString)) SQString(new_string);
t->_next = _strings[slot];
_strings[slot] = t;
_slotused++;
+1 -1
View File
@@ -46,7 +46,7 @@ public:
static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize)
{
SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable));
new (newtable) SQTable(ss, nInitialSize);
new (newtable, sizeof(SQTable)) SQTable(ss, nInitialSize);
newtable->_delegate = nullptr;
return newtable;
}
+1 -1
View File
@@ -14,7 +14,7 @@ struct SQUserData : SQDelegable
static SQUserData* Create(SQSharedState *ss, SQInteger size)
{
SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1));
new (ud) SQUserData(ss, size);
new (ud, sizeof(SQUserData)+(size-1)) SQUserData(ss, size);
return ud;
}
#ifndef NO_GARBAGE_COLLECTOR
+1 -1
View File
@@ -28,7 +28,7 @@
/** Widgets for the configure AI window. */
static constexpr NWidgetPart _nested_ai_config_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_ai_config_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
NWidget(WWT_CAPTION, COLOUR_MAUVE), SetStringTip(STR_AI_CONFIG_CAPTION_AI, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+1 -1
View File
@@ -137,5 +137,5 @@ AILibrary *AIScannerLibrary::FindLibrary(const std::string &library, int version
ScriptInfoList::iterator it = this->info_list.find(library_name);
if (it == this->info_list.end()) return nullptr;
return static_cast<AILibrary *>((*it).second);
return static_cast<AILibrary *>(it->second);
}
+27 -15
View File
@@ -16,7 +16,6 @@
#include "news_func.h"
#include "newgrf_engine.h"
#include "newgrf_sound.h"
#include "spritecache.h"
#include "error_func.h"
#include "strings_func.h"
#include "command_func.h"
@@ -131,12 +130,14 @@ static StationID FindNearestHangar(const Aircraft *v)
const Station *next_dest = nullptr;
if (max_range != 0) {
if (v->current_order.IsType(OT_GOTO_STATION) ||
(v->current_order.IsType(OT_GOTO_DEPOT) && (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0)) {
(v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.GetDepotActionType().Test(OrderDepotActionFlag::NearestDepot))) {
last_dest = Station::GetIfValid(v->last_station_visited);
next_dest = Station::GetIfValid(v->current_order.GetDestination().ToStationID());
} else {
last_dest = GetTargetAirportIfValid(v);
next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
std::vector<StationID> next_station;
v->GetNextStoppingStation(next_station);
if (!next_station.empty()) next_dest = Station::GetIfValid(next_station.back());
}
}
@@ -200,7 +201,7 @@ void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteS
static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
{
const Engine *e = Engine::Get(engine);
uint8_t spritenum = e->u.air.image_index;
uint8_t spritenum = e->VehInfo<AircraftVehicleInfo>().image_index;
if (IsCustomVehicleSpriteNum(spritenum)) {
GetCustomVehicleIcon(engine, DIR_W, image_type, result);
@@ -267,7 +268,7 @@ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoff
*/
CommandCost CmdBuildAircraft(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
{
const AircraftVehicleInfo *avi = &e->u.air;
const AircraftVehicleInfo *avi = &e->VehInfo<AircraftVehicleInfo>();
const Station *st = Station::GetByTile(tile);
/* Prevent building aircraft types at places which can't handle them */
@@ -427,7 +428,7 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
/* only goto depot if the target airport has a depot */
if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) {
v->current_order.MakeGoToDepot(st->index, ODTFB_SERVICE);
v->current_order.MakeGoToDepot(st->index, OrderDepotTypeFlag::Service);
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
} else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
v->current_order.MakeDummy();
@@ -438,7 +439,7 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
Money Aircraft::GetRunningCost() const
{
const Engine *e = this->GetEngine();
uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost);
uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->VehInfo<AircraftVehicleInfo>().running_cost);
return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
}
@@ -987,7 +988,7 @@ static bool AircraftController(Aircraft *v)
}
/* Get distance from destination pos to current pos. */
uint dist = abs(x + amd.x - v->x_pos) + abs(y + amd.y - v->y_pos);
uint dist = abs(x + amd.x - v->x_pos) + abs(y + amd.y - v->y_pos);
/* Need exact position? */
if (!amd.flags.Test(AirportMovingDataFlag::ExactPosition) && dist <= (amd.flags.Test(AirportMovingDataFlag::SlowTurn) ? 8U : 4U)) return true;
@@ -1020,10 +1021,21 @@ static bool AircraftController(Aircraft *v)
uint speed_limit = SPEED_LIMIT_TAXI;
bool hard_limit = true;
if (amd.flags.Test(AirportMovingDataFlag::NoSpeedClamp)) speed_limit = SPEED_LIMIT_NONE;
if (amd.flags.Test(AirportMovingDataFlag::Hold)) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; }
if (amd.flags.Test(AirportMovingDataFlag::Land)) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; }
if (amd.flags.Test(AirportMovingDataFlag::Brake)) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; }
if (amd.flags.Test(AirportMovingDataFlag::NoSpeedClamp)) {
speed_limit = SPEED_LIMIT_NONE;
}
if (amd.flags.Test(AirportMovingDataFlag::Hold)) {
speed_limit = SPEED_LIMIT_HOLD;
hard_limit = false;
}
if (amd.flags.Test(AirportMovingDataFlag::Land)) {
speed_limit = SPEED_LIMIT_APPROACH;
hard_limit = false;
}
if (amd.flags.Test(AirportMovingDataFlag::Brake)) {
speed_limit = SPEED_LIMIT_TAXI;
hard_limit = false;
}
int count = UpdateAircraftSpeed(v, speed_limit, hard_limit);
if (count == 0) return false;
@@ -1180,7 +1192,7 @@ static bool HandleCrashedAircraft(Aircraft *v)
Station *st = GetTargetAirportIfValid(v);
/* make aircraft crash down to the ground */
if (v->crashed_counter < 500 && st == nullptr && ((v->crashed_counter % 3) == 0) ) {
if (v->crashed_counter < 500 && st == nullptr && ((v->crashed_counter % 3) == 0)) {
int z = GetSlopePixelZ(Clamp(v->x_pos, 0, Map::MaxX() * TILE_SIZE), Clamp(v->y_pos, 0, Map::MaxY() * TILE_SIZE));
v->z_pos -= 1;
if (v->z_pos <= z) {
@@ -1813,7 +1825,7 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc)
{
/* error handling */
if (v->pos >= apc->nofelements) {
Debug(misc, 0, "[Ap] position {} is not valid for current airport. Max position is {}", v->pos, apc->nofelements-1);
Debug(misc, 0, "[Ap] position {} is not valid for current airport. Max position is {}", v->pos, apc->nofelements - 1);
assert(v->pos < apc->nofelements);
}
@@ -2175,7 +2187,7 @@ void UpdateAirplanesOnNewStation(const Station *st)
Order *o = &v->current_order;
/* The aircraft is heading to a hangar, but the new station doesn't have one,
* or the aircraft can't land on the new station. Cancel current order. */
if (o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && o->GetDestination() == st->index &&
if (o->IsType(OT_GOTO_DEPOT) && !o->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders) && o->GetDestination() == st->index &&
(!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) {
o->MakeDummy();
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
-1
View File
@@ -14,7 +14,6 @@
#include "strings_func.h"
#include "vehicle_func.h"
#include "window_gui.h"
#include "spritecache.h"
#include "zoom_func.h"
#include "table/strings.h"
+9 -4
View File
@@ -84,7 +84,7 @@ static void PlaceAirport(TileIndex tile)
/** Airport build toolbar window handler. */
struct BuildAirToolbarWindow : Window {
int last_user_action = INVALID_WID_AT; // Last started user action.
WidgetID last_user_action = INVALID_WIDGET; // Last started user action.
BuildAirToolbarWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
@@ -161,6 +161,11 @@ struct BuildAirToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
Point OnInitialPosition(int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
{
return AlignInitialConstructionToolbar(sm_width);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
{
if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
@@ -197,7 +202,7 @@ struct BuildAirToolbarWindow : Window {
}, AirportToolbarGlobalHotkeys};
};
static constexpr NWidgetPart _nested_air_toolbar_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_air_toolbar_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -211,7 +216,7 @@ static constexpr NWidgetPart _nested_air_toolbar_widgets[] = {
};
static WindowDesc _air_toolbar_desc(
WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0,
WDP_MANUAL, "toolbar_air", 0, 0,
WC_BUILD_TOOLBAR, WC_NONE,
WindowDefaultFlag::Construction,
_nested_air_toolbar_widgets,
@@ -580,7 +585,7 @@ public:
}};
};
static constexpr NWidgetPart _nested_build_airport_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_airport_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+5 -5
View File
@@ -363,12 +363,12 @@ void AddArticulatedParts(Vehicle *first)
t->subtype = 0;
t->track = front->track;
t->railtype = front->railtype;
t->railtypes = front->railtypes;
t->spritenum = e_artic->u.rail.image_index;
t->spritenum = e_artic->VehInfo<RailVehicleInfo>().image_index;
if (e_artic->CanCarryCargo()) {
t->cargo_type = e_artic->GetDefaultCargoType();
t->cargo_cap = e_artic->u.rail.capacity; // Callback 36 is called when the consist is finished
t->cargo_cap = e_artic->VehInfo<RailVehicleInfo>().capacity; // Callback 36 is called when the consist is finished
} else {
t->cargo_type = front->cargo_type; // Needed for livery selection
t->cargo_cap = 0;
@@ -392,11 +392,11 @@ void AddArticulatedParts(Vehicle *first)
rv->roadtype = front->roadtype;
rv->compatible_roadtypes = front->compatible_roadtypes;
rv->spritenum = e_artic->u.road.image_index;
rv->spritenum = e_artic->VehInfo<RoadVehicleInfo>().image_index;
if (e_artic->CanCarryCargo()) {
rv->cargo_type = e_artic->GetDefaultCargoType();
assert(IsValidCargoType(rv->cargo_type));
rv->cargo_cap = e_artic->u.road.capacity; // Callback 36 is called when the consist is finished
rv->cargo_cap = e_artic->VehInfo<RoadVehicleInfo>().capacity; // Callback 36 is called when the consist is finished
} else {
rv->cargo_type = front->cargo_type; // Needed for livery selection
rv->cargo_cap = 0;
+4 -4
View File
@@ -71,16 +71,16 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
switch (type) {
case VEH_TRAIN: {
/* make sure the railtypes are compatible */
if (!GetRailTypeInfo(e_from->u.rail.railtype)->compatible_railtypes.Any(GetRailTypeInfo(e_to->u.rail.railtype)->compatible_railtypes)) return false;
if (!GetAllCompatibleRailTypes(e_from->VehInfo<RailVehicleInfo>().railtypes).Any(GetAllCompatibleRailTypes(e_to->VehInfo<RailVehicleInfo>().railtypes))) return false;
/* make sure we do not replace wagons with engines or vice versa */
if ((e_from->u.rail.railveh_type == RAILVEH_WAGON) != (e_to->u.rail.railveh_type == RAILVEH_WAGON)) return false;
if ((e_from->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) != (e_to->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON)) return false;
break;
}
case VEH_ROAD:
/* make sure the roadtypes are compatible */
if (!GetRoadTypeInfo(e_from->u.road.roadtype)->powered_roadtypes.Any(GetRoadTypeInfo(e_to->u.road.roadtype)->powered_roadtypes)) return false;
if (!GetRoadTypeInfo(e_from->VehInfo<RoadVehicleInfo>().roadtype)->powered_roadtypes.Any(GetRoadTypeInfo(e_to->VehInfo<RoadVehicleInfo>().roadtype)->powered_roadtypes)) return false;
/* make sure that we do not replace a tram with a normal road vehicles or vice versa */
if (e_from->info.misc_flags.Test(EngineMiscFlag::RoadIsTram) != e_to->info.misc_flags.Test(EngineMiscFlag::RoadIsTram)) return false;
@@ -88,7 +88,7 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
case VEH_AIRCRAFT:
/* make sure that we do not replace a plane with a helicopter or vice versa */
if ((e_from->u.air.subtype & AIR_CTOL) != (e_to->u.air.subtype & AIR_CTOL)) return false;
if ((e_from->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL) != (e_to->VehInfo<AircraftVehicleInfo>().subtype & AIR_CTOL)) return false;
break;
default: break;
+2 -2
View File
@@ -18,7 +18,7 @@
CommandCost CmdAutoreplaceVehicle(DoCommandFlags flags, VehicleID veh_id);
CommandCost CmdSetAutoReplace(DoCommandFlags flags, GroupID id_g, EngineID old_engine_type, EngineID new_engine_type, bool when_old);
DEF_CMD_TRAIT(CMD_AUTOREPLACE_VEHICLE, CmdAutoreplaceVehicle, {}, CMDT_VEHICLE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_AUTOREPLACE, CmdSetAutoReplace, {}, CMDT_VEHICLE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_AUTOREPLACE_VEHICLE, CmdAutoreplaceVehicle, {}, CommandType::VehicleManagement)
DEF_CMD_TRAIT(CMD_SET_AUTOREPLACE, CmdSetAutoReplace, {}, CommandType::VehicleManagement)
#endif /* AUTOREPLACE_CMD_H */
+5 -5
View File
@@ -111,7 +111,7 @@ class ReplaceVehicleWindow : public Window {
if (draw_left && this->sel_railtype != INVALID_RAILTYPE) {
/* Ensure that the railtype is specific to the selected one */
if (rvi->railtype != this->sel_railtype) return false;
if (!rvi->railtypes.Test(this->sel_railtype)) return false;
}
return true;
}
@@ -140,7 +140,7 @@ class ReplaceVehicleWindow : public Window {
case VEH_ROAD:
if (draw_left && this->sel_roadtype != INVALID_ROADTYPE) {
/* Ensure that the roadtype is specific to the selected one */
if (e->u.road.roadtype != this->sel_roadtype) continue;
if (e->VehInfo<RoadVehicleInfo>().roadtype != this->sel_roadtype) continue;
}
break;
@@ -698,7 +698,7 @@ public:
}
};
static constexpr NWidgetPart _nested_replace_rail_vehicle_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_replace_rail_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION),
@@ -762,7 +762,7 @@ static WindowDesc _replace_rail_vehicle_desc(
_nested_replace_rail_vehicle_widgets
);
static constexpr NWidgetPart _nested_replace_road_vehicle_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_replace_road_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION),
@@ -820,7 +820,7 @@ static WindowDesc _replace_road_vehicle_desc(
_nested_replace_road_vehicle_widgets
);
static constexpr NWidgetPart _nested_replace_vehicle_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_replace_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14),
+1 -1
View File
@@ -79,7 +79,7 @@ bool BaseSet<T>::FillSetDetails(const IniFile &ini, const std::string &path, con
/* Add the translations of the descriptions too. */
for (const IniItem &titem : metadata->items) {
if (titem.name.compare(0, 12, "description.") != 0) continue;
if (!titem.name.starts_with("description.")) continue;
this->description[titem.name.substr(12)] = titem.value.value_or("");
}
+7 -7
View File
@@ -33,14 +33,14 @@ enum MusicTrackType : uint8_t {
/** Metadata about a music track. */
struct MusicSongInfo {
std::string songname; ///< name of song displayed in UI
uint8_t tracknr; ///< track number of song displayed in UI
std::string filename; ///< file on disk containing song (when used in MusicSet class)
std::string songname; ///< name of song displayed in UI
std::string filename; ///< file on disk containing song (when used in MusicSet class)
int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
int override_start; ///< MIDI ticks to skip over in beginning
int override_end; ///< MIDI tick to end the song at (0 if no override)
uint8_t tracknr; ///< track number of song displayed in UI
MusicTrackType filetype; ///< decoder required for song file
int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
bool loop; ///< song should play in a tight loop if possible, never ending
int override_start; ///< MIDI ticks to skip over in beginning
int override_end; ///< MIDI tick to end the song at (0 if no override)
bool loop; ///< song should play in a tight loop if possible, never ending
};
template <> struct BaseSetTraits<struct MusicSet> {
+2 -2
View File
@@ -118,9 +118,9 @@ public:
inline TileIterator& operator ++() override
{
(*this).OrthogonalTileIterator::operator++();
this->OrthogonalTileIterator::operator++();
while (this->tile != INVALID_TILE && !this->bitmap->HasTile(TileIndex(this->tile))) {
(*this).OrthogonalTileIterator::operator++();
this->OrthogonalTileIterator::operator++();
}
return *this;
}
+2 -2
View File
@@ -113,7 +113,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(SpriteType sprite_type, const SpriteLoader
else break;
dst_rgba++;
}
(*dst_rgba_line).data = nb_pix_transp;
dst_rgba_line->data = nb_pix_transp;
Colour *nb_right = dst_rgba_line + 1;
dst_rgba_line = reinterpret_cast<Colour *>(reinterpret_cast<std::byte *>(dst_rgba_line) + info.sprite_line_size);
@@ -126,7 +126,7 @@ Sprite *Blitter_32bppSSE_Base::Encode(SpriteType sprite_type, const SpriteLoader
else break;
dst_rgba--;
}
(*nb_right).data = nb_pix_transp;
nb_right->data = nb_pix_transp;
}
}
+4 -4
View File
@@ -240,9 +240,9 @@ inline void Blitter_40bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel
if (src_px->a == 255) {
src_px += n;
do {
/* If the anim buffer contains a color value, the image composition will
/* If the anim buffer contains a colour value, the image composition will
* only look at the RGB brightness value. As such, we can simply darken the
* RGB value to darken the anim color. */
* RGB value to darken the anim colour. */
Colour b = *anim != 0 ? Colour(GetColourBrightness(*dst), 0, 0) : *dst;
*dst = this->MakeTransparent(b, 3, 4);
anim++;
@@ -360,9 +360,9 @@ void Blitter_40bppAnim::DrawColourMappingRect(void *dst, int width, int height,
uint8_t *anim = VideoDriver::GetInstance()->GetAnimBuffer() + ((uint32_t *)dst - (uint32_t *)_screen.dst_ptr);
if (pal == PALETTE_TO_TRANSPARENT) {
/* If the anim buffer contains a color value, the image composition will
/* If the anim buffer contains a colour value, the image composition will
* only look at the RGB brightness value. As such, we can simply darken the
* RGB value to darken the anim color. */
* RGB value to darken the anim colour. */
do {
for (int i = 0; i != width; i++) {
Colour b = *anim != 0 ? Colour(GetColourBrightness(*udst), 0, 0) : *udst;
+7 -7
View File
@@ -33,7 +33,7 @@
#include "safeguards.h"
/** Widgets for the background window to prevent smearing. */
static constexpr NWidgetPart _background_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _background_widgets = {
NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1),
EndContainer(),
};
@@ -60,13 +60,13 @@ public:
void DrawWidget(const Rect &r, WidgetID) const override
{
GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{4}, FILLRECT_OPAQUE);
GfxFillRect(r.left, r.top, r.right, r.bottom, PixelColour{0}, FILLRECT_CHECKER);
GfxFillRect(r, PixelColour{4}, FILLRECT_OPAQUE);
GfxFillRect(r, PixelColour{0}, FILLRECT_CHECKER);
}
};
/** Nested widgets for the error window. */
static constexpr NWidgetPart _nested_bootstrap_errmsg_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_bootstrap_errmsg_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_BEM_CAPTION), SetStringTip(STR_MISSING_GRAPHICS_ERROR_TITLE),
EndContainer(),
@@ -123,7 +123,7 @@ public:
};
/** Nested widgets for the download window. */
static constexpr NWidgetPart _nested_bootstrap_download_status_window_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_bootstrap_download_status_window_widgets = {
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PANEL, COLOUR_GREY),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.modalpopup),
@@ -174,7 +174,7 @@ public:
};
/** The widgets for the query. It has no close box as that sprite does not exist yet. */
static constexpr NWidgetPart _bootstrap_query_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _bootstrap_query_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
@@ -380,7 +380,7 @@ bool HandleBootstrap()
/* Initialise the font cache. */
InitializeUnicodeGlyphMap();
/* Next "force" finding a suitable non-sprite font as the local font is missing. */
CheckForMissingGlyphs(false);
CheckForMissingGlyphs();
/* Initialise the palette. The biggest step is 'faking' some recolour sprites.
* This way the mauve and gray colours work and we can show the user interface. */
+1 -1
View File
@@ -309,7 +309,7 @@ const std::initializer_list<GUIBridgeList::SortFunction * const> BuildBridgeWind
};
/** Widgets of the bridge gui. */
static constexpr NWidgetPart _nested_build_bridge_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_bridge_widgets = {
/* Header */
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
+1
View File
@@ -135,6 +135,7 @@ inline void MakeBridgeRamp(Tile t, Owner o, BridgeType bridgetype, DiagDirection
t.m4() = 0;
t.m5() = 1 << 7 | tt << 2 | d;
SB(t.m6(), 2, 4, bridgetype);
SB(t.m6(), 6, 2, 0);
t.m7() = 0;
t.m8() = 0;
}
+45 -22
View File
@@ -58,7 +58,7 @@ uint GetEngineListHeight(VehicleType type)
return std::max<uint>(GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.matrix.Vertical(), GetVehicleImageCellSize(type, EIT_PURCHASE).height);
}
static constexpr NWidgetPart _nested_build_vehicle_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_vehicle_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetTextStyle(TC_WHITE),
@@ -632,14 +632,33 @@ static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engin
}
y += GetCharacterHeight(FS_NORMAL);
/* Supported rail types */
std::string railtypes{};
std::string_view list_separator = GetListSeparator();
for (const auto &rt : _sorted_railtypes) {
if (!rvi->railtypes.Test(rt)) continue;
if (!railtypes.empty()) railtypes += list_separator;
AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
}
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RAILTYPES, railtypes));
y += GetCharacterHeight(FS_NORMAL);
/* Max speed - Engine power */
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
y += GetCharacterHeight(FS_NORMAL);
/* Max tractive effort - not applicable if old acceleration or maglev */
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
y += GetCharacterHeight(FS_NORMAL);
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
bool is_maglev = true;
for (RailType rt : rvi->railtypes) {
is_maglev &= GetRailTypeInfo(rt)->acceleration_type == VehicleAccelerationModel::Maglev;
}
if (!is_maglev) {
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
y += GetCharacterHeight(FS_NORMAL);
}
}
/* Running cost */
@@ -707,8 +726,8 @@ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_numb
/* Purchase cost - Max speed */
uint raw_speed = e->GetDisplayMaxSpeed();
uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true);
uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false);
uint ocean_speed = e->VehInfo<ShipVehicleInfo>().ApplyWaterClassSpeedFrac(raw_speed, true);
uint canal_speed = e->VehInfo<ShipVehicleInfo>().ApplyWaterClassSpeedFrac(raw_speed, false);
if (ocean_speed == canal_speed) {
if (te.cost != 0) {
@@ -866,10 +885,10 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number,
switch (e->type) {
default: NOT_REACHED();
case VEH_TRAIN:
if (e->u.rail.railveh_type == RAILVEH_WAGON) {
y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
if (e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->VehInfo<RailVehicleInfo>(), te);
} else {
y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail, te);
y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->VehInfo<RailVehicleInfo>(), te);
}
articulated_cargo = true;
break;
@@ -901,7 +920,7 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number,
}
/* Draw details that apply to all types except rail wagons. */
if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
if (e->type != VEH_TRAIN || e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON) {
/* Design date - Life length */
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_DESIGNED_LIFE, ymd.year, TimerGameCalendar::DateToYear(e->GetLifeLengthInDays())));
y += GetCharacterHeight(FS_NORMAL);
@@ -1011,7 +1030,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
if (has_variants) {
Rect fr = tr.WithWidth(circle_width, rtl);
DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, textr.top, fr.right, textr.bottom}, SA_CENTER);
DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, fr.WithY(textr), SA_CENTER);
}
tr = tr.Indent(circle_width + WidgetDimensions::scaled.hsep_normal, rtl);
@@ -1315,8 +1334,7 @@ struct BuildVehicleWindow : Window {
this->badge_classes = GUIBadgeClasses(static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->SetCargoFilterArray();
auto container = this->GetWidget<NWidgetContainer>(WID_BV_BADGE_FILTER);
this->badge_filters = AddBadgeDropdownFilters(*container, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->badge_filters = AddBadgeDropdownFilters(this, WID_BV_BADGE_FILTER, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->widget_lookup.clear();
this->nested_root->FillWidgetLookup(this->widget_lookup);
@@ -1376,9 +1394,9 @@ struct BuildVehicleWindow : Window {
for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
const RailVehicleInfo *rvi = &e->u.rail;
const RailVehicleInfo *rvi = &e->VehInfo<RailVehicleInfo>();
if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtypes, this->filter.railtype)) continue;
if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
/* Filter now! So num_engines and num_wagons is valid */
@@ -1407,7 +1425,7 @@ struct BuildVehicleWindow : Window {
if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
const Engine *e = Engine::Get(variant);
list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlag::Shaded, 0);
if (e->u.rail.railveh_type != RAILVEH_WAGON) num_engines++;
if (e->VehInfo<RailVehicleInfo>().railveh_type != RAILVEH_WAGON) num_engines++;
}
}
@@ -1436,12 +1454,14 @@ struct BuildVehicleWindow : Window {
this->eng_list.clear();
BadgeTextFilter btf(this->string_filter, GSF_ROADVEHICLES);
BadgeDropdownFilter bdf(this->badge_filter_choices);
for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->u.road.roadtype, this->filter.roadtype)) continue;
if (this->filter.roadtype != INVALID_ROADTYPE && !HasPowerOnRoad(e->VehInfo<RoadVehicleInfo>().roadtype, this->filter.roadtype)) continue;
if (!bdf.Filter(e->badges)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
@@ -1460,11 +1480,13 @@ struct BuildVehicleWindow : Window {
this->eng_list.clear();
BadgeTextFilter btf(this->string_filter, GSF_SHIPS);
BadgeDropdownFilter bdf(this->badge_filter_choices);
for (const Engine *e : Engine::IterateType(VEH_SHIP)) {
if (!this->show_hidden_engines && e->IsVariantHidden(_local_company)) continue;
EngineID eid = e->index;
if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
if (!bdf.Filter(e->badges)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
@@ -1486,6 +1508,7 @@ struct BuildVehicleWindow : Window {
const Station *st = this->listview_mode ? nullptr : Station::GetByTile(TileIndex(this->window_number));
BadgeTextFilter btf(this->string_filter, GSF_AIRCRAFT);
BadgeDropdownFilter bdf(this->badge_filter_choices);
/* Make list of all available planes.
* Also check to see if the previously selected plane is still available,
@@ -1497,6 +1520,7 @@ struct BuildVehicleWindow : Window {
if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
if (!bdf.Filter(e->badges)) continue;
/* Filter by name or NewGRF extra text */
if (!FilterByText(e) && !btf.Filter(e->badges)) continue;
@@ -1592,7 +1616,7 @@ struct BuildVehicleWindow : Window {
DropDownList BuildBadgeConfigurationList() const
{
static const auto separators = {STR_BADGE_CONFIG_PREVIEW, STR_BADGE_CONFIG_NAME};
return BuildBadgeClassConfigurationList(this->badge_classes, BADGE_COLUMNS, separators);
return BuildBadgeClassConfigurationList(this->badge_classes, BADGE_COLUMNS, separators, COLOUR_GREY);
}
void BuildVehicle()
@@ -1680,7 +1704,7 @@ struct BuildVehicleWindow : Window {
case WID_BV_CONFIGURE_BADGES:
if (this->badge_classes.GetClasses().empty()) break;
ShowDropDownList(this, this->BuildBadgeConfigurationList(), -1, widget, 0, false, true);
ShowDropDownList(this, this->BuildBadgeConfigurationList(), -1, widget, 0, DropDownOption::Persist);
break;
case WID_BV_SHOW_HIDE: {
@@ -1706,7 +1730,8 @@ struct BuildVehicleWindow : Window {
default:
if (IsInsideMM(widget, this->badge_filters.first, this->badge_filters.second)) {
ShowDropDownList(this, this->GetWidget<NWidgetBadgeFilter>(widget)->GetDropDownList(), -1, widget, 0, false);
PaletteID palette = SPR_2CCMAP_BASE + Company::Get(_local_company)->GetCompanyRecolourOffset(LS_DEFAULT);
ShowDropDownList(this, this->GetWidget<NWidgetBadgeFilter>(widget)->GetDropDownList(palette), -1, widget, 0);
}
break;
}
@@ -1906,7 +1931,6 @@ struct BuildVehicleWindow : Window {
/* We need to refresh if a filter is removed. */
this->eng_list.ForceRebuild();
this->SetDirty();
break;
}
@@ -1918,7 +1942,6 @@ struct BuildVehicleWindow : Window {
SetBadgeFilter(this->badge_filter_choices, BadgeID(index));
}
this->eng_list.ForceRebuild();
this->SetDirty();
}
break;
}
+17 -17
View File
@@ -404,13 +404,13 @@ void VehicleCargoList::AgeCargo()
* @return MoveToAction to be performed.
*/
/* static */ VehicleCargoList::MoveToAction VehicleCargoList::ChooseAction(const CargoPacket *cp, StationID cargo_next,
StationID current_station, bool accepted, StationIDStack next_station)
StationID current_station, bool accepted, std::span<const StationID> next_station)
{
if (cargo_next == StationID::Invalid()) {
return (accepted && cp->first_station != current_station) ? MTA_DELIVER : MTA_KEEP;
} else if (cargo_next == current_station) {
return MTA_DELIVER;
} else if (next_station.Contains(cargo_next)) {
} else if (std::ranges::find(next_station, cargo_next) != std::end(next_station)) {
return MTA_KEEP;
} else {
return MTA_TRANSFER;
@@ -425,14 +425,14 @@ void VehicleCargoList::AgeCargo()
* @param accepted If the cargo will be accepted at the station.
* @param current_station ID of the station.
* @param next_station ID of the station the vehicle will go to next.
* @param order_flags OrderUnloadFlags that will apply to the unload operation.
* @param unload_type OrderUnloadType that will apply to the unload operation.
* @param ge GoodsEntry for getting the flows.
* @param cargo The cargo type of the cargo.
* @param payment Payment object for registering transfers.
* @param current_tile Current tile the cargo handling is happening on.
* return If any cargo will be unloaded.
*/
bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
bool VehicleCargoList::Stage(bool accepted, StationID current_station, std::span<const StationID> next_station, OrderUnloadType unload_type, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile)
{
this->AssertCountConsistency();
assert(this->action_counts[MTA_LOAD] == 0);
@@ -444,9 +444,9 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
static const FlowStatMap EMPTY_FLOW_STAT_MAP = {};
const FlowStatMap &flows = ge->HasData() ? ge->GetData().flows : EMPTY_FLOW_STAT_MAP;
bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0;
bool force_unload = (order_flags & OUFB_UNLOAD) != 0;
bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0;
bool force_keep = unload_type == OrderUnloadType::NoUnload;
bool force_unload = unload_type == OrderUnloadType::Unload;
bool force_transfer = unload_type == OrderUnloadType::Transfer || unload_type == OrderUnloadType::Unload;
assert(this->count > 0 || it == this->packets.end());
while (sum < this->count) {
CargoPacket *cp = *it;
@@ -468,9 +468,9 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID
} else {
FlowStat new_shares = flow_it->second;
new_shares.ChangeShare(current_station, INT_MIN);
StationIDStack excluded = next_station;
while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) {
new_shares.ChangeShare(excluded.Pop(), INT_MIN);
for (auto station_it = next_station.rbegin(); station_it != next_station.rend(); ++station_it) {
if (new_shares.GetShares()->empty()) break;
new_shares.ChangeShare(*station_it, INT_MIN);
}
if (new_shares.GetShares()->empty()) {
cargo_next = StationID::Invalid();
@@ -739,11 +739,11 @@ bool StationCargoList::ShiftCargo(Taction &action, StationID next)
* @return Amount of cargo actually moved.
*/
template <class Taction>
uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool include_invalid)
uint StationCargoList::ShiftCargo(Taction action, std::span<const StationID> next, bool include_invalid)
{
uint max_move = action.MaxMove();
while (!next.IsEmpty()) {
this->ShiftCargo(action, next.Pop());
for (auto it = next.rbegin(); it != next.rend(); ++it) {
this->ShiftCargo(action, *it);
if (action.MaxMove() == 0) break;
}
if (include_invalid && action.MaxMove() > 0) {
@@ -814,7 +814,7 @@ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_
* @param current_tile Current tile the cargo handling is happening on.
* @return Amount of cargo actually reserved.
*/
uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile)
uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, std::span<const StationID> next_station, TileIndex current_tile)
{
return this->ShiftCargo(CargoReservation(this, dest, max_move, current_tile), next_station, true);
}
@@ -831,7 +831,7 @@ uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDS
* modes of loading are exclusive, though. If cargo is reserved we don't
* need to load unreserved cargo.
*/
uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile)
uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, std::span<const StationID> next_station, TileIndex current_tile)
{
uint move = std::min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move);
if (move > 0) {
@@ -839,7 +839,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
dest->Reassign<VehicleCargoList::MTA_LOAD, VehicleCargoList::MTA_KEEP>(move);
return move;
} else {
return this->ShiftCargo(CargoLoad(this, dest, max_move, current_tile), next_station, true);
return this->ShiftCargo(CargoLoad{this, dest, max_move, current_tile}, next_station, true);
}
}
@@ -853,7 +853,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac
*/
uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge)
{
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false);
return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), {&avoid, 1}, false);
}
/*
+8 -8
View File
@@ -371,7 +371,7 @@ protected:
void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count);
static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next,
StationID current_station, bool accepted, StationIDStack next_station);
StationID current_station, bool accepted, std::span<const StationID> next_station);
public:
/** The station cargo list needs to control the unloading. */
@@ -469,7 +469,7 @@ public:
void InvalidateCache();
bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
bool Stage(bool accepted, StationID current_station, std::span<const StationID> next_station, OrderUnloadType unload_type, const GoodsEntry *ge, CargoType cargo, CargoPayment *payment, TileIndex current_tile);
/**
* Marks all cargo in the vehicle as to be kept. This is mostly useful for
@@ -543,7 +543,7 @@ public:
bool ShiftCargo(Taction &action, StationID next);
template <class Taction>
uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid);
uint ShiftCargo(Taction action, std::span<const StationID> next, bool include_invalid);
void Append(CargoPacket *cp, StationID next);
@@ -552,10 +552,10 @@ public:
* @param next Station the cargo is headed for.
* @return If there is any cargo for that station.
*/
inline bool HasCargoFor(StationIDStack next) const
inline bool HasCargoFor(std::span<const StationID> next) const
{
while (!next.IsEmpty()) {
if (this->packets.find(next.Pop()) != this->packets.end()) return true;
for (const StationID &station : next) {
if (this->packets.find(station) != this->packets.end()) return true;
}
/* Packets for StationID::Invalid() can go anywhere. */
return this->packets.find(StationID::Invalid()) != this->packets.end();
@@ -603,8 +603,8 @@ public:
* amount of cargo to be moved. Second parameter is destination (if
* applicable), return value is amount of cargo actually moved. */
uint Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile);
uint Load(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile);
uint Reserve(uint max_move, VehicleCargoList *dest, std::span<const StationID> next, TileIndex current_tile);
uint Load(uint max_move, VehicleCargoList *dest, std::span<const StationID> next, TileIndex current_tile);
uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr);
uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge);
+1 -1
View File
@@ -219,7 +219,7 @@ static const CheatEntry _cheats_ui[] = {
static_assert(CHT_NUM_CHEATS == lengthof(_cheats_ui));
/** Widget definitions of the cheat GUI. */
static constexpr NWidgetPart _nested_cheat_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_cheat_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_CHEATS, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+1 -1
View File
@@ -226,7 +226,7 @@ static inline bool NeighbourIsNormal(TileIndex tile)
TileIndex t = tile + TileOffsByDiagDir(dir);
if (!IsValidTile(t)) continue;
if (GetTropicZone(t) != TROPICZONE_DESERT) return true;
if (HasTileWaterClass(t) && GetWaterClass(t) == WATER_CLASS_SEA) return true;
if (HasTileWaterClass(t) && GetWaterClass(t) == WaterClass::Sea) return true;
}
return false;
}
+1 -1
View File
@@ -274,7 +274,7 @@ inline void MakeField(Tile t, uint field_type, IndustryID industry)
t.m3() = field_type;
t.m4() = 0 << 5 | 0 << 2;
SetClearGroundDensity(t, CLEAR_FIELDS, 3);
SB(t.m6(), 2, 4, 0);
SB(t.m6(), 2, 6, 0);
t.m7() = 0;
t.m8() = 0;
}
+13 -13
View File
@@ -144,21 +144,21 @@ std::string_view GetCommandName(Commands cmd)
bool IsCommandAllowedWhilePaused(Commands cmd)
{
/* Lookup table for the command types that are allowed for a given pause level setting. */
static const int command_type_lookup[] = {
CMDPL_ALL_ACTIONS, ///< CMDT_LANDSCAPE_CONSTRUCTION
CMDPL_NO_LANDSCAPING, ///< CMDT_VEHICLE_CONSTRUCTION
CMDPL_NO_LANDSCAPING, ///< CMDT_MONEY_MANAGEMENT
CMDPL_NO_CONSTRUCTION, ///< CMDT_VEHICLE_MANAGEMENT
CMDPL_NO_CONSTRUCTION, ///< CMDT_ROUTE_MANAGEMENT
CMDPL_NO_CONSTRUCTION, ///< CMDT_OTHER_MANAGEMENT
CMDPL_NO_ACTIONS, ///< CMDT_COMPANY_SETTING
CMDPL_NO_ACTIONS, ///< CMDT_SERVER_SETTING
CMDPL_NO_ACTIONS, ///< CMDT_CHEAT
static constexpr CommandPauseLevel command_type_lookup[] = {
CommandPauseLevel::AllActions, // CommandType::LandscapeConstruction
CommandPauseLevel::NoLandscaping, // CommandType::VehicleConstruction
CommandPauseLevel::NoLandscaping, // CommandType::MoneyManagement
CommandPauseLevel::NoConstruction, // CommandType::VehicleManagement
CommandPauseLevel::NoConstruction, // CommandType::RouteManagement
CommandPauseLevel::NoConstruction, // CommandType::OtherManagement
CommandPauseLevel::NoActions, // CommandType::CompanySetting
CommandPauseLevel::NoActions, // CommandType::ServerSetting
CommandPauseLevel::NoActions, // CommandType::Cheat
};
static_assert(lengthof(command_type_lookup) == CMDT_END);
static_assert(std::size(command_type_lookup) == to_underlying(CommandType::End));
assert(IsValidCommand(cmd));
return _game_mode == GM_EDITOR || command_type_lookup[_command_proc_table[cmd].type] <= _settings_game.construction.command_pause_level;
return _game_mode == GM_EDITOR || command_type_lookup[to_underlying(_command_proc_table[cmd].type)] <= _settings_game.construction.command_pause_level;
}
/**
@@ -384,7 +384,7 @@ CommandCost CommandHelperBase::InternalExecuteProcessResult(Commands cmd, Comman
SubtractMoneyFromCompany(res_exec);
/* Record if there was a command issues during pause; ignore pause/other setting related changes. */
if (_pause_mode.Any() && _command_proc_table[cmd].type != CMDT_SERVER_SETTING) _pause_mode.Set(PauseMode::CommandDuringPause);
if (_pause_mode.Any() && _command_proc_table[cmd].type != CommandType::ServerSetting) _pause_mode.Set(PauseMode::CommandDuringPause);
/* update signals if needed */
UpdateSignalsInBuffer();
+21 -17
View File
@@ -214,6 +214,7 @@ enum Commands : uint8_t {
CMD_BUILD_RAIL_WAYPOINT, ///< build a waypoint
CMD_RENAME_WAYPOINT, ///< rename a waypoint
CMD_MOVE_WAYPOINT_NAME, ///< move a waypoint name
CMD_REMOVE_FROM_RAIL_WAYPOINT, ///< remove a (rectangle of) tiles from a rail waypoint
CMD_BUILD_ROAD_WAYPOINT, ///< build a road waypoint
@@ -275,10 +276,12 @@ enum Commands : uint8_t {
CMD_RENAME_COMPANY, ///< change the company name
CMD_RENAME_PRESIDENT, ///< change the president name
CMD_RENAME_STATION, ///< rename a station
CMD_MOVE_STATION_NAME, ///< move a station name
CMD_RENAME_DEPOT, ///< rename a depot
CMD_PLACE_SIGN, ///< place a sign
CMD_RENAME_SIGN, ///< rename a sign
CMD_MOVE_SIGN, ///< move a sign
CMD_TURN_ROADVEH, ///< turn a road vehicle around
@@ -380,7 +383,7 @@ enum Commands : uint8_t {
*
* This enums defines some flags which can be used for the commands.
*/
enum DoCommandFlag : uint8_t {
enum class DoCommandFlag : uint8_t {
Execute, ///< execute the given command
Auto, ///< don't allow building on structures
QueryCost, ///< query cost only, don't build.
@@ -417,26 +420,27 @@ enum class CommandFlag : uint8_t {
using CommandFlags = EnumBitSet<CommandFlag, uint16_t>;
/** Types of commands we have. */
enum CommandType : uint8_t {
CMDT_LANDSCAPE_CONSTRUCTION, ///< Construction and destruction of objects on the map.
CMDT_VEHICLE_CONSTRUCTION, ///< Construction, modification (incl. refit) and destruction of vehicles.
CMDT_MONEY_MANAGEMENT, ///< Management of money, i.e. loans.
CMDT_VEHICLE_MANAGEMENT, ///< Stopping, starting, sending to depot, turning around, replace orders etc.
CMDT_ROUTE_MANAGEMENT, ///< Modifications to route management (orders, groups, etc).
CMDT_OTHER_MANAGEMENT, ///< Renaming stuff, changing company colours, placing signs, etc.
CMDT_COMPANY_SETTING, ///< Changing settings related to a company.
CMDT_SERVER_SETTING, ///< Pausing/removing companies/server settings.
CMDT_CHEAT, ///< A cheat of some sorts.
enum class CommandType : uint8_t {
LandscapeConstruction, ///< Construction and destruction of objects on the map.
VehicleConstruction, ///< Construction, modification (incl. refit) and destruction of vehicles.
MoneyManagement, ///< Management of money, i.e. loans.
VehicleManagement, ///< Stopping, starting, sending to depot, turning around, replace orders etc.
RouteManagement, ///< Modifications to route management (orders, groups, etc).
OtherManagement, ///< Renaming stuff, changing company colours, placing signs, etc.
CompanySetting, ///< Changing settings related to a company.
ServerSetting, ///< Pausing/removing companies/server settings.
Cheat, ///< A cheat of some sorts.
CMDT_END, ///< Magic end marker.
End, ///< End marker.
};
/** Different command pause levels. */
enum CommandPauseLevel : uint8_t {
CMDPL_NO_ACTIONS, ///< No user actions may be executed.
CMDPL_NO_CONSTRUCTION, ///< No construction actions may be executed.
CMDPL_NO_LANDSCAPING, ///< No landscaping actions may be executed.
CMDPL_ALL_ACTIONS, ///< All actions may be executed.
enum class CommandPauseLevel : uint8_t {
NoActions, ///< No user actions may be executed.
NoConstruction, ///< No construction actions may be executed.
NoLandscaping, ///< No landscaping actions may be executed.
AllActions, ///< All actions may be executed.
};
+16 -2
View File
@@ -45,8 +45,10 @@ struct CompanyInfrastructure {
return std::accumulate(std::begin(this->rail), std::end(this->rail), 0U);
}
uint32_t GetRoadTotal() const;
uint32_t GetTramTotal() const;
uint32_t GetRoadTramTotal(RoadTramType rtt) const;
inline uint32_t GetRoadTotal() const { return GetRoadTramTotal(RTT_ROAD); }
inline uint32_t GetTramTotal() const { return GetRoadTramTotal(RTT_TRAM); }
};
class FreeUnitIDGenerator {
@@ -178,6 +180,18 @@ struct Company : CompanyProperties, CompanyPool::PoolItem<&_company_pool> {
return !Company::Get(index)->is_ai;
}
/**
* Get offset for recolour palette of specific company.
* @param livery_scheme Scheme to use for recolour.
* @param use_secondary Specify whether to add secondary colour offset to the result.
* @return palette offset.
*/
inline uint8_t GetCompanyRecolourOffset(LiveryScheme livery_scheme, bool use_secondary = true) const
{
const Livery &l = this->livery[livery_scheme];
return use_secondary ? l.colour1 + l.colour2 * 16 : l.colour1;
}
static void PostDestructor(size_t index);
};
+21 -33
View File
@@ -574,14 +574,14 @@ restart:;
void ResetCompanyLivery(Company *c)
{
for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) {
c->livery[scheme].in_use = 0;
c->livery[scheme].in_use.Reset();
c->livery[scheme].colour1 = c->colour;
c->livery[scheme].colour2 = c->colour;
}
for (Group *g : Group::Iterate()) {
if (g->owner == c->index) {
g->livery.in_use = 0;
g->livery.in_use.Reset();
g->livery.colour1 = c->colour;
g->livery.colour2 = c->colour;
}
@@ -623,8 +623,8 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = CompanyID::Invalid(
c->inaugurated_year = TimerGameEconomy::year;
c->inaugurated_year_calendar = TimerGameCalendar::year;
/* If starting a player company in singleplayer and a favorite company manager face is selected, choose it. Otherwise, use a random face.
* In a network game, we'll choose the favorite face later in CmdCompanyCtrl to sync it to all clients. */
/* If starting a player company in singleplayer and a favourite company manager face is selected, choose it. Otherwise, use a random face.
* In a network game, we'll choose the favourite face later in CmdCompanyCtrl to sync it to all clients. */
bool randomise_face = true;
if (!_company_manager_face.empty() && !is_ai && !_networking) {
auto cmf = ParseCompanyManagerFaceCode(_company_manager_face);
@@ -917,7 +917,7 @@ CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyI
SetLocalCompany(c->index);
/*
* If a favorite company manager face is selected, choose it. Otherwise, use a random face.
* If a favourite company manager face is selected, choose it. Otherwise, use a random face.
* Because this needs to be synchronised over the network, only the client knows
* its configuration and we are currently in the execution of a command, we have
* to circumvent the normal ::Post logic for commands and just send the command.
@@ -925,7 +925,7 @@ CommandCost CmdCompanyCtrl(DoCommandFlags flags, CompanyCtrlAction cca, CompanyI
if (!_company_manager_face.empty()) {
auto cmf = ParseCompanyManagerFaceCode(_company_manager_face);
if (cmf.has_value()) {
Command<CMD_SET_COMPANY_MANAGER_FACE>::SendNet(STR_NULL, c->index, cmf->bits, cmf->style);
Command<CMD_SET_COMPANY_MANAGER_FACE>::SendNet(STR_NULL, c->index, cmf->style, cmf->bits);
}
}
@@ -1050,11 +1050,11 @@ CommandCost CmdCompanyAllowListCtrl(DoCommandFlags flags, CompanyAllowListCtrlAc
/**
* Change the company manager's face.
* @param flags operation to perform
* @param bits The bits of company manager face.
* @param style The style of the company manager face.
* @param bits The bits of company manager face.
* @return the cost of this operation or an error
*/
CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint32_t bits, uint style)
CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint style, uint32_t bits)
{
CompanyManagerFace tmp_face{style, bits, {}};
if (!IsValidCompanyManagerFace(tmp_face)) return CMD_ERROR;
@@ -1077,8 +1077,8 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint32_t bits, uint s
void UpdateCompanyLiveries(Company *c)
{
for (int i = 1; i < LS_END; i++) {
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
if (!c->livery[i].in_use.Test(Livery::Flag::Primary)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
if (!c->livery[i].in_use.Test(Livery::Flag::Secondary)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
}
UpdateCompanyGroupLiveries(c);
}
@@ -1109,7 +1109,7 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
if (flags.Test(DoCommandFlag::Execute)) {
if (primary) {
if (scheme != LS_DEFAULT) AssignBit(c->livery[scheme].in_use, 0, colour != INVALID_COLOUR);
if (scheme != LS_DEFAULT) c->livery[scheme].in_use.Set(Livery::Flag::Primary, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = c->livery[LS_DEFAULT].colour1;
c->livery[scheme].colour1 = colour;
@@ -1122,7 +1122,7 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
CompanyAdminUpdate(c);
}
} else {
if (scheme != LS_DEFAULT) AssignBit(c->livery[scheme].in_use, 1, colour != INVALID_COLOUR);
if (scheme != LS_DEFAULT) c->livery[scheme].in_use.Set(Livery::Flag::Secondary, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = c->livery[LS_DEFAULT].colour2;
c->livery[scheme].colour2 = colour;
@@ -1131,16 +1131,16 @@ CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool
}
}
if (c->livery[scheme].in_use != 0) {
if (c->livery[scheme].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
/* If enabling a scheme, set the default scheme to be in use too */
c->livery[LS_DEFAULT].in_use = 1;
c->livery[LS_DEFAULT].in_use.Set(Livery::Flag::Primary);
} else {
/* Else loop through all schemes to see if any are left enabled.
* If not, disable the default scheme too. */
c->livery[LS_DEFAULT].in_use = 0;
c->livery[LS_DEFAULT].in_use.Reset({Livery::Flag::Primary, Livery::Flag::Secondary});
for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
if (c->livery[scheme].in_use != 0) {
c->livery[LS_DEFAULT].in_use = 1;
if (c->livery[scheme].in_use.Any({Livery::Flag::Primary, Livery::Flag::Secondary})) {
c->livery[LS_DEFAULT].in_use.Set(Livery::Flag::Primary);
break;
}
}
@@ -1291,26 +1291,14 @@ int CompanyServiceInterval(const Company *c, VehicleType type)
/**
* Get total sum of all owned road bits.
* @param rtt RoadTramType to get total for.
* @return Combined total road road bits.
*/
uint32_t CompanyInfrastructure::GetRoadTotal() const
uint32_t CompanyInfrastructure::GetRoadTramTotal(RoadTramType rtt) const
{
uint32_t total = 0;
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
if (RoadTypeIsRoad(rt)) total += this->road[rt];
}
return total;
}
/**
* Get total sum of all owned tram bits.
* @return Combined total of tram road bits.
*/
uint32_t CompanyInfrastructure::GetTramTotal() const
{
uint32_t total = 0;
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
if (RoadTypeIsTram(rt)) total += this->road[rt];
for (RoadType rt : GetMaskForRoadTramType(rtt)) {
total += this->road[rt];
}
return total;
}
+7 -7
View File
@@ -25,12 +25,12 @@ CommandCost CmdRenamePresident(DoCommandFlags flags, const std::string &text);
CommandCost CmdSetCompanyManagerFace(DoCommandFlags flags, uint style, uint32_t bits);
CommandCost CmdSetCompanyColour(DoCommandFlags flags, LiveryScheme scheme, bool primary, Colours colour);
DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CommandFlags({CommandFlag::Spectator, CommandFlag::ClientID, CommandFlag::NoEst}), CMDT_SERVER_SETTING)
DEF_CMD_TRAIT(CMD_COMPANY_ALLOW_LIST_CTRL, CmdCompanyAllowListCtrl, CommandFlag::NoEst, CMDT_SERVER_SETTING)
DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, {}, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, {}, CMDT_COMPANY_SETTING)
DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, {}, CMDT_COMPANY_SETTING)
DEF_CMD_TRAIT(CMD_SET_COMPANY_MANAGER_FACE, CmdSetCompanyManagerFace, {}, CMDT_COMPANY_SETTING)
DEF_CMD_TRAIT(CMD_SET_COMPANY_COLOUR, CmdSetCompanyColour, {}, CMDT_COMPANY_SETTING)
DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CommandFlags({CommandFlag::Spectator, CommandFlag::ClientID, CommandFlag::NoEst}), CommandType::ServerSetting)
DEF_CMD_TRAIT(CMD_COMPANY_ALLOW_LIST_CTRL, CmdCompanyAllowListCtrl, CommandFlag::NoEst, CommandType::ServerSetting)
DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, {}, CommandType::MoneyManagement)
DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, {}, CommandType::CompanySetting)
DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, {}, CommandType::CompanySetting)
DEF_CMD_TRAIT(CMD_SET_COMPANY_MANAGER_FACE, CmdSetCompanyManagerFace, {}, CommandType::CompanySetting)
DEF_CMD_TRAIT(CMD_SET_COMPANY_COLOUR, CmdSetCompanyColour, {}, CommandType::CompanySetting)
#endif /* COMPANY_CMD_H */
+22 -22
View File
@@ -286,7 +286,7 @@ static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Exp
DrawPrice(sum, r.left, r.right, y, TC_WHITE);
}
static constexpr NWidgetPart _nested_company_finances_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_company_finances_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_CF_CAPTION),
@@ -655,7 +655,7 @@ private:
}
uint8_t sel;
if (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) {
if (default_livery == nullptr || livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
sel = primary ? livery->colour1 : livery->colour2;
} else {
sel = default_col;
@@ -697,6 +697,7 @@ public:
SelectCompanyLiveryWindow(WindowDesc &desc, CompanyID company, GroupID group) : Window(desc)
{
this->CreateNestedTree();
this->GetWidget<NWidgetStacked>(WID_SCL_SEC_COL_DROP_SEL)->SetDisplayedPlane(_loaded_newgrf_features.has_2CC ? 0 : SZSP_NONE);
this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
if (group == GroupID::Invalid()) {
@@ -767,10 +768,7 @@ public:
}
case WID_SCL_SEC_COL_DROPDOWN:
if (!_loaded_newgrf_features.has_2CC) {
size.width = 0;
break;
}
if (!_loaded_newgrf_features.has_2CC) break;
[[fallthrough]];
case WID_SCL_PRI_COL_DROPDOWN: {
@@ -819,7 +817,7 @@ public:
}
if (scheme == LS_END) scheme = LS_DEFAULT;
const Livery *livery = &c->livery[scheme];
if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
if (scheme == LS_DEFAULT || livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
}
}
@@ -827,7 +825,7 @@ public:
if (this->sel != GroupID::Invalid()) {
const Group *g = Group::Get(this->sel);
const Livery *livery = &g->livery;
if (HasBit(livery->in_use, primary ? 0 : 1)) {
if (livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
}
}
@@ -875,12 +873,12 @@ public:
/* Text below the first dropdown. */
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || livery.in_use.Test(Livery::Flag::Primary)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
/* Text below the second dropdown. */
if (sec.right > sec.left) { // Second dropdown has non-zero size.
DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || livery.in_use.Test(Livery::Flag::Secondary)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
}
y += this->line_height;
@@ -1062,7 +1060,7 @@ public:
}
};
static constexpr NWidgetPart _nested_select_company_livery_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_select_company_livery_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION),
@@ -1089,13 +1087,15 @@ static constexpr NWidgetPart _nested_select_company_livery_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_GREY, WID_SCL_SPACER_DROPDOWN), SetFill(1, 1), SetResize(1, 0), EndContainer(),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_PRI_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_PRIMARY_TOOLTIP),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_SECONDARY_TOOLTIP),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCL_SEC_COL_DROP_SEL),
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_SECONDARY_TOOLTIP),
EndContainer(),
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
EndContainer(),
};
static WindowDesc _select_company_livery_desc(
WDP_AUTO, "company_color_scheme", 0, 0,
WDP_AUTO, "company_colour_scheme", 0, 0,
WC_COMPANY_COLOUR, WC_NONE,
{},
_nested_select_company_livery_widgets
@@ -1161,7 +1161,7 @@ void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const
}
/** Nested widget description for the company manager face selection dialog */
static constexpr NWidgetPart _nested_select_company_manager_face_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_select_company_manager_face_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetStringTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -1333,8 +1333,8 @@ public:
Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
bool rtl = _current_text_dir == TD_RTL;
Rect br = ir.CentreTo(ir.Width(), SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreTo(ir.Width(), GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
Rect br = ir.CentreToHeight(SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreToHeight(GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
DrawArrowButtons(br.left, br.top, COLOUR_YELLOW, this->selected_var == UINT_MAX - 1 ? this->click_state : 0, true, true);
DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, STR_FACE_STYLE, this->face.style + 1, GetNumCompanyManagerFaceStyles()), TC_WHITE);
@@ -1352,8 +1352,8 @@ public:
const uint8_t var = static_cast<uint8_t>(*it - vars.data());
const FaceVar &facevar = **it;
Rect br = ir.CentreTo(ir.Width(), SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreTo(ir.Width(), GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
Rect br = ir.CentreToHeight(SETTING_BUTTON_HEIGHT).WithWidth(SETTING_BUTTON_WIDTH, rtl);
Rect tr = ir.Shrink(RectPadding::zero, WidgetDimensions::scaled.matrix).CentreToHeight(GetCharacterHeight(FS_NORMAL)).Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl);
uint val = vars[var].GetBits(this->face);
if (facevar.type == FaceVarType::Toggle) {
@@ -1384,7 +1384,7 @@ public:
/* OK button */
case WID_SCMF_ACCEPT:
Command<CMD_SET_COMPANY_MANAGER_FACE>::Post(this->face.bits, this->face.style);
Command<CMD_SET_COMPANY_MANAGER_FACE>::Post(this->face.style, this->face.bits);
[[fallthrough]];
/* Cancel button */
@@ -1536,7 +1536,7 @@ static void DoSelectCompanyManagerFace(Window *parent)
new SelectCompanyManagerFaceWindow(_select_company_manager_face_desc, parent);
}
static constexpr NWidgetPart _nested_company_infrastructure_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_company_infrastructure_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION),
@@ -1840,7 +1840,7 @@ static void ShowCompanyInfrastructure(CompanyID company)
AllocateWindowDescFront<CompanyInfrastructureWindow>(_company_infrastructure_desc, company);
}
static constexpr NWidgetPart _nested_company_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_company_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION),
@@ -2405,7 +2405,7 @@ private:
Money company_value{}; ///< The value of the company for which the user can buy it.
};
static constexpr NWidgetPart _nested_buy_company_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_buy_company_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION),
+30 -14
View File
@@ -46,6 +46,10 @@
#include "company_cmd.h"
#include "misc_cmd.h"
#if defined(WITH_ZLIB)
#include "network/network_content.h"
#endif /* WITH_ZLIB */
#include "table/strings.h"
#include "safeguards.h"
@@ -2163,7 +2167,7 @@ static bool ConNetworkAuthorizedKey(std::span<std::string_view> argv)
}
for (auto [name, authorized_keys] : _console_cmd_authorized_keys) {
if (StrEqualsIgnoreCase(type, name)) continue;
if (!StrEqualsIgnoreCase(type, name)) continue;
PerformNetworkAuthorizedKeyAction(name, authorized_keys, action, authorized_key);
return true;
@@ -2176,7 +2180,6 @@ static bool ConNetworkAuthorizedKey(std::span<std::string_view> argv)
/* Content downloading only is available with ZLIB */
#if defined(WITH_ZLIB)
#include "network/network_content.h"
/** Resolve a string to a content type. */
static ContentType StringToContentType(std::string_view str)
@@ -2316,6 +2319,18 @@ static bool ConContent(std::span<std::string_view> argv)
}
#endif /* defined(WITH_ZLIB) */
/**
* Get string representation of a font load reason.
* @param load_reason The font load reason.
* @return String representation.
*/
static std::string_view FontLoadReasonToName(FontLoadReason load_reason)
{
static const std::string_view LOAD_REASON_TO_NAME[] = { "default", "configured", "language", "missing" };
static_assert(std::size(LOAD_REASON_TO_NAME) == to_underlying(FontLoadReason::End));
return LOAD_REASON_TO_NAME[to_underlying(load_reason)];
}
static bool ConFont(std::span<std::string_view> argv)
{
if (argv.empty()) {
@@ -2364,17 +2379,18 @@ static bool ConFont(std::span<std::string_view> argv)
SetFont(argfs, font, size);
}
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
FontCache *fc = FontCache::Get(fs);
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
/* Make sure all non sprite fonts are loaded. */
if (!setting->font.empty() && !fc->HasParent()) {
FontCache::LoadFontCaches(fs);
fc = FontCache::Get(fs);
}
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
IConsolePrint(CC_DEFAULT, "Currently active: \"{}\", size {}", fc->GetFontName(), fc->GetFontSize());
IConsolePrint(CC_DEFAULT, "Requested: \"{}\", size {}", setting->font, setting->size);
IConsolePrint(CC_INFO, "Configured fonts:");
for (uint i = 0; FontSize fs : FONTSIZES_ALL) {
const FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
IConsolePrint(CC_DEFAULT, "{}) {} font: \"{}\", size {}", i, FontSizeToName(fs), setting->font, setting->size);
++i;
}
IConsolePrint(CC_INFO, "Currently active fonts:");
for (uint i = 0; const auto &fc : FontCache::Get()) {
if (fc == nullptr) continue;
IConsolePrint(CC_DEFAULT, "{}) {} font: \"{}\" size {} [{}]", i, FontSizeToName(fc->GetSize()), fc->GetFontName(), fc->GetFontSize(), FontLoadReasonToName(fc->GetFontLoadReason()));
++i;
}
return true;
@@ -2699,7 +2715,7 @@ static std::string FormatLabel(uint32_t label)
return fmt::format("{:c}{:c}{:c}{:c}", GB(label, 24, 8), GB(label, 16, 8), GB(label, 8, 8), GB(label, 0, 8));
}
return fmt::format("{:08X}", std::byteswap(label));
return fmt::format("{:08X}", label);
}
static void ConDumpRoadTypes()
+2 -2
View File
@@ -133,7 +133,7 @@ static inline void IConsoleResetHistoryPos()
static std::optional<std::string_view> IConsoleHistoryAdd(std::string_view cmd);
static void IConsoleHistoryNavigate(int direction);
static constexpr NWidgetPart _nested_console_window_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_console_window_widgets = {
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_BACKGROUND), SetResize(1, 1),
};
@@ -453,7 +453,7 @@ void IConsoleClose()
static std::optional<std::string_view> IConsoleHistoryAdd(std::string_view cmd)
{
/* Strip all spaces at the begin */
while (IsWhitespace(cmd[0])) cmd.remove_prefix(1);
while (!cmd.empty() && IsWhitespace(cmd[0])) cmd.remove_prefix(1);
/* Do not put empty command in history */
if (cmd.empty()) return std::nullopt;
-1
View File
@@ -22,7 +22,6 @@ add_files(
pool_type.hpp
random_func.cpp
random_func.hpp
smallstack_type.hpp
string_builder.cpp
string_builder.hpp
string_consumer.cpp
+2 -2
View File
@@ -254,8 +254,8 @@ public:
return std::nullopt;
}
auto begin() const { return SetBitIterator<Tvalue_type>(this->data).begin(); }
auto end() const { return SetBitIterator<Tvalue_type>(this->data).end(); }
auto begin() const { return SetBitIterator<Tvalue_type, Tstorage>(this->data).begin(); }
auto end() const { return SetBitIterator<Tvalue_type, Tstorage>(this->data).end(); }
private:
Tstorage data; ///< Bitmask of values.
+1 -1
View File
@@ -54,7 +54,7 @@ public:
* @param key Key to test.
* @return true iff the key exists in the set.
*/
bool contains(const Tkey &key)
bool contains(const Tkey &key) const
{
return std::ranges::binary_search(this->data, key, Tcompare{});
}
+44 -16
View File
@@ -62,14 +62,14 @@ struct Dimension {
bool operator< (const Dimension &other) const
{
int x = (*this).width - other.width;
int x = this->width - other.width;
if (x != 0) return x < 0;
return (*this).height < other.height;
return this->height < other.height;
}
bool operator== (const Dimension &other) const
{
return (*this).width == other.width && (*this).height == other.height;
return this->width == other.width && this->height == other.height;
}
};
@@ -211,8 +211,8 @@ struct Rect {
[[nodiscard]] inline Rect WithWidth(int width, bool end) const
{
return end
? Rect {this->right - width + 1, this->top, this->right, this->bottom}
: Rect {this->left, this->top, this->left + width - 1, this->bottom};
? this->WithX(this->right - width + 1, this->right)
: this->WithX(this->left, this->left + width - 1);
}
/**
@@ -224,21 +224,21 @@ struct Rect {
[[nodiscard]] inline Rect Indent(int indent, bool end) const
{
return end
? Rect {this->left, this->top, this->right - indent, this->bottom}
: Rect {this->left + indent, this->top, this->right, this->bottom};
? this->WithX(this->left, this->right - indent)
: this->WithX(this->left + indent, this->right);
}
/**
* Copy Rect and set its height.
* @param width height in pixels for new Rect.
* @param height height in pixels for new Rect.
* @param end if set, set height at end of Rect, i.e. at bottom.
* @return the new resized Rect.
*/
[[nodiscard]] inline Rect WithHeight(int height, bool end = false) const
{
return end
? Rect {this->left, this->bottom - height + 1, this->right, this->bottom}
: Rect {this->left, this->top, this->right, this->top + height - 1};
? this->WithY(this->bottom - height + 1, this->bottom)
: this->WithY(this->top, this->top + height - 1);
}
/**
@@ -253,17 +253,45 @@ struct Rect {
}
/**
* Centre a dimension within this Rect.
* @param width The horizontal dimension.
* Centre a vertical dimension within this Rect.
* @param height The vertical dimension.
* @return the new resized Rect.
*/
[[nodiscard]] inline Rect CentreTo(int width, int height) const
[[nodiscard]] inline Rect CentreToHeight(int height) const
{
int new_left = CentreBounds(this->left, this->right, width);
int new_right = CentreBounds(this->top, this->bottom, height);
return {new_left, new_right, new_left + width, new_right + height};
int new_top = CentreBounds(this->top, this->bottom, height);
return {this->left, new_top, this->right, new_top + height - 1};
}
/**
* Create a new Rect, replacing the left and right coordiates.
* @param new_left New left coordinate.
* @param new_right New right coordinate.
* @return The new Rect.
*/
[[nodiscard]] inline Rect WithX(int new_left, int new_right) const { return {new_left, this->top, new_right, this->bottom}; }
/**
* Create a new Rect, replacing the top and bottom coordiates.
* @param new_top New top coordinate.
* @param new_bottom New bottom coordinate.
* @return The new Rect.
*/
[[nodiscard]] inline Rect WithY(int new_top, int new_bottom) const { return {this->left, new_top, this->right, new_bottom}; }
/**
* Create a new Rect, replacing the left and right coordiates.
* @param other Rect containing the new left and right coordinates.
* @return The new Rect.
*/
[[nodiscard]] inline Rect WithX(const Rect &other) const { return this->WithX(other.left, other.right); }
/**
* Create a new Rect, replacing the top and bottom coordiates.
* @param other Rect containing the new top and bottom coordinates.
* @return The new Rect.
*/
[[nodiscard]] inline Rect WithY(const Rect &other) const { return this->WithY(other.top, other.bottom); }
};
/**
-266
View File
@@ -1,266 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file smallstack_type.hpp Minimal stack that uses a pool to avoid pointers and doesn't allocate any heap memory if there is only one valid item. */
#ifndef SMALLSTACK_TYPE_HPP
#define SMALLSTACK_TYPE_HPP
/**
* A simplified pool which stores values instead of pointers and doesn't
* redefine operator new/delete. It also never zeroes memory and always reuses
* it.
*/
template <typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
class SimplePool {
public:
inline SimplePool() : first_unused(0), first_free(0) {}
/**
* Get the item at position index.
* @return Item at index.
*/
inline Titem &Get(Tindex index) { return this->data[index]; }
/**
* Create a new item and return its index.
* @return Index of new item.
*/
inline Tindex Create()
{
Tindex index = this->FindFirstFree();
if (index < Tmax_size) {
this->data[index].valid = true;
this->first_free = index + 1;
this->first_unused = std::max(this->first_unused, this->first_free);
}
return index;
}
/**
* Destroy (or rather invalidate) the item at the given index.
* @param index Index of item to be destroyed.
*/
inline void Destroy(Tindex index)
{
this->data[index].valid = false;
this->first_free = std::min(this->first_free, index);
}
private:
inline Tindex FindFirstFree()
{
Tindex index = this->first_free;
for (; index < this->first_unused; index++) {
if (!this->data[index].valid) return index;
}
if (index >= this->data.size() && index < Tmax_size) {
this->data.resize(index + 1);
}
return index;
}
struct SimplePoolPoolItem : public Titem {
bool valid;
};
Tindex first_unused;
Tindex first_free;
std::vector<SimplePoolPoolItem> data;
};
/**
* Base class for SmallStack. We cannot add this into SmallStack itself as
* certain compilers don't like it.
*/
template <typename Titem, typename Tindex>
struct SmallStackItem {
Tindex next; ///< Pool index of next item.
Titem value; ///< Value of current item.
/**
* Create a new item.
* @param value Value of the item.
* @param next Next item in the stack.
*/
inline SmallStackItem(const Titem &value, Tindex next) :
next(next), value(value) {}
SmallStackItem() = default;
};
/**
* Minimal stack that uses a pool to avoid pointers. It has some peculiar
* properties that make it useful for passing around lists of IDs but not much
* else:
* 1. It always includes an invalid item as bottom.
* 2. It doesn't have a deep copy operation but uses smart pointers instead.
* Every copy is thus implicitly shared.
* 3. Its items are immutable.
* 4. Due to 2. and 3. memory management can be done by "branch counting".
* Whenever you copy a smallstack, the first item on the heap increases its
* branch_count, signifying that there are multiple items "in front" of it.
* When deleting a stack items are deleted up to the point where
* branch_count > 0.
* 5. You can choose your own index type, so that you can align it with your
* value type. E.G. value types of 16 bits length like to be combined with
* index types of the same length.
* @tparam Titem Value type to be used.
* @tparam Tindex Index type to use for the pool.
* @tparam Tinvalid_value Value to construct invalid item to keep at the bottom of each stack.
* @tparam Tgrowth_step Growth step for pool.
* @tparam Tmax_size Maximum size for pool.
*/
template <typename Titem, typename Tindex, auto Tinvalid_value, Tindex Tgrowth_step, Tindex Tmax_size>
class SmallStack : public SmallStackItem<Titem, Tindex> {
public:
static constexpr Titem Tinvalid{Tinvalid_value};
typedef SmallStackItem<Titem, Tindex> Item;
/**
* SmallStack item that can be kept in a pool.
*/
struct PooledSmallStack : public Item {
Tindex branch_count; ///< Number of branches in the tree structure this item is parent of
};
typedef SimplePool<PooledSmallStack, Tindex, Tgrowth_step, Tmax_size> SmallStackPool;
/**
* Constructor for a stack with one or two items in it.
* @param value Initial item. If not missing or Tinvalid there will be Tinvalid below it.
*/
inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {}
/**
* Remove the head of stack and all other items members that are unique to it.
*/
inline ~SmallStack()
{
while (this->next != Tmax_size) this->Pop();
}
/**
* Shallow copy the stack, marking the first item as branched.
* @param other Stack to copy from
*/
inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); }
/**
* Shallow copy the stack, marking the first item as branched.
* @param other Stack to copy from
* @return This smallstack.
*/
inline SmallStack &operator=(const SmallStack &other)
{
if (this == &other) return *this;
while (this->next != Tmax_size) this->Pop();
this->next = other.next;
this->value = other.value;
/* Deleting and branching are independent operations, so it's fine to
* acquire separate locks for them. */
this->Branch();
return *this;
}
/**
* Pushes a new item onto the stack if there is still space in the
* underlying pool. Otherwise the topmost item's value gets overwritten.
* @param item Item to be pushed.
*/
inline void Push(const Titem &item)
{
if (this->value != Tinvalid) {
Tindex new_item = SmallStack::GetPool().Create();
if (new_item != Tmax_size) {
PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item);
pushed.value = this->value;
pushed.next = this->next;
pushed.branch_count = 0;
this->next = new_item;
}
}
this->value = item;
}
/**
* Pop an item from the stack.
* @return Current top of stack.
*/
inline Titem Pop()
{
Titem ret = this->value;
if (this->next == Tmax_size) {
this->value = Tinvalid;
} else {
PooledSmallStack &popped = SmallStack::GetPool().Get(this->next);
this->value = popped.value;
if (popped.branch_count == 0) {
SmallStack::GetPool().Destroy(this->next);
} else {
--popped.branch_count;
if (popped.next != Tmax_size) {
++(SmallStack::GetPool().Get(popped.next).branch_count);
}
}
/* Accessing popped here is no problem as the pool will only set
* the validity flag, not actually delete the item, on Destroy(). */
this->next = popped.next;
}
return ret;
}
/**
* Check if the stack is empty.
* @return If the stack is empty.
*/
inline bool IsEmpty() const
{
return this->value == Tinvalid && this->next == Tmax_size;
}
/**
* Check if the given item is contained in the stack.
* @param item Item to look for.
* @return If the item is in the stack.
*/
inline bool Contains(const Titem &item) const
{
if (item == Tinvalid || item == this->value) return true;
if (this->next != Tmax_size) {
const SmallStack *in_list = this;
do {
in_list = static_cast<const SmallStack *>(
static_cast<const Item *>(&SmallStack::GetPool().Get(in_list->next)));
if (in_list->value == item) return true;
} while (in_list->next != Tmax_size);
}
return false;
}
protected:
static SmallStackPool &GetPool()
{
static SmallStackPool pool;
return pool;
}
/**
* Create a branch in the pool if necessary.
*/
inline void Branch()
{
if (this->next != Tmax_size) {
++(SmallStack::GetPool().Get(this->next).branch_count);
}
}
};
#endif
+27
View File
@@ -158,4 +158,31 @@ namespace StrongType {
};
}
/**
* Implementation of std::hash for StrongType::Typedef.
*
* This specialization of std::hash allows hashing of StrongType::Typedef instances
* by leveraging the hash of the base type.
*
* Example Usage:
* using MyType = StrongType::Typedef<int, struct MyTypeTag>;
* std::unordered_map<MyType, std::string> my_map;
*
* @tparam TBaseType The underlying type of the StrongType::Typedef.
* @tparam TProperties Additional properties for the StrongType::Typedef.
*/
template <typename TBaseType, typename... TProperties>
struct std::hash<StrongType::Typedef<TBaseType, TProperties...>> {
/**
* Computes the hash value for a StrongType::Typedef instance.
*
* @param t The StrongType::Typedef instance to hash.
* @return The hash value of the base type of t.
*/
std::size_t operator()(const StrongType::Typedef<TBaseType, TProperties...> &t) const noexcept
{
return std::hash<TBaseType>()(t.base());
}
};
#endif /* STRONG_TYPEDEF_TYPE_HPP */
+1 -1
View File
@@ -173,7 +173,7 @@ struct SetDateWindow : Window {
};
/** Widgets for the date setting window. */
static constexpr NWidgetPart _nested_set_date_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_set_date_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN), SetStringTip(STR_DATE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+1 -1
View File
@@ -16,7 +16,7 @@
CommandCost CmdRenameDepot(DoCommandFlags flags, DepotID depot_id, const std::string &text);
DEF_CMD_TRAIT(CMD_RENAME_DEPOT, CmdRenameDepot, {}, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_RENAME_DEPOT, CmdRenameDepot, {}, CommandType::OtherManagement)
void CcCloneVehicle(Commands cmd, const CommandCost &result, VehicleID veh_id);
+7 -7
View File
@@ -17,7 +17,7 @@
#include "viewport_func.h"
#include "command_func.h"
#include "depot_base.h"
#include "spritecache.h"
#include "spritecache_type.h"
#include "strings_func.h"
#include "sound_func.h"
#include "vehicle_func.h"
@@ -47,7 +47,7 @@
*/
/** Nested widget definition for train depots. */
static constexpr NWidgetPart _nested_train_depot_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_train_depot_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_D_SHOW_RENAME), SetAspect(WidgetDimensions::ASPECT_RENAME), // rename button
@@ -229,7 +229,7 @@ void InitDepotWindowBlockSizes()
if (!e->IsEnabled()) continue;
uint w = TRAININFO_DEFAULT_VEHICLE_WIDTH;
if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->u.rail.image_index)) {
if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->VehInfo<RailVehicleInfo>().image_index)) {
w = e->GetGRF()->traininfo_vehicle_width;
if (w != VEHICLEINFO_FULL_VEHICLE_WIDTH) {
/* Hopeless.
@@ -260,7 +260,7 @@ struct DepotWindow : Window {
VehicleType type = VEH_INVALID;
bool generate_list = true;
bool check_unitnumber_digits = true;
WidgetID hovered_widget = -1; ///< Index of the widget being hovered during drag/drop. -1 if no drag is in progress.
WidgetID hovered_widget = INVALID_WIDGET; ///< Index of the widget being hovered during drag/drop. \c INVALID_WIDGET if no drag is in progress.
VehicleList vehicle_list{};
VehicleList wagon_list{};
uint unitnumber_digits = 2;
@@ -1001,10 +1001,10 @@ struct DepotWindow : Window {
this->vehicle_over = VehicleID::Invalid();
this->SetWidgetDirty(WID_D_MATRIX);
if (this->hovered_widget != -1) {
if (this->hovered_widget != INVALID_WIDGET) {
this->SetWidgetLoweredState(this->hovered_widget, false);
this->SetWidgetDirty(this->hovered_widget);
this->hovered_widget = -1;
this->hovered_widget = INVALID_WIDGET;
}
}
@@ -1116,7 +1116,7 @@ struct DepotWindow : Window {
this->SetDirty();
break;
}
this->hovered_widget = -1;
this->hovered_widget = INVALID_WIDGET;
_cursor.vehchain = false;
}
+29 -33
View File
@@ -98,7 +98,7 @@ static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = n
/** Toolbar window for constructing water infrastructure. */
struct BuildDocksToolbarWindow : Window {
DockToolbarWidgets last_clicked_widget = WID_DT_INVALID; ///< Contains the last widget that has been clicked on this toolbar.
WidgetID last_clicked_widget = INVALID_WIDGET; ///< Contains the last widget that has been clicked on this toolbar.
BuildDocksToolbarWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
{
@@ -189,7 +189,7 @@ struct BuildDocksToolbarWindow : Window {
default: return;
}
this->last_clicked_widget = (DockToolbarWidgets)widget;
this->last_clicked_widget = widget;
}
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
@@ -250,6 +250,11 @@ struct BuildDocksToolbarWindow : Window {
VpSelectTilesWithMethod(pt.x, pt.y, select_method);
}
Point OnInitialPosition(int16_t sm_width, [[maybe_unused]] int16_t sm_height, [[maybe_unused]] int window_number) override
{
return AlignInitialConstructionToolbar(sm_width);
}
void OnPlaceMouseUp([[maybe_unused]] ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, [[maybe_unused]] Point pt, TileIndex start_tile, TileIndex end_tile) override
{
if (pt.x != -1) {
@@ -259,13 +264,13 @@ struct BuildDocksToolbarWindow : Window {
break;
case DDSP_CREATE_WATER:
if (_game_mode == GM_EDITOR) {
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, _ctrl_pressed ? WATER_CLASS_SEA : WATER_CLASS_CANAL, false);
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, _ctrl_pressed ? WaterClass::Sea : WaterClass::Canal, false);
} else {
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_CANAL, _ctrl_pressed);
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_BUILD_CANALS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WaterClass::Canal, _ctrl_pressed);
}
break;
case DDSP_CREATE_RIVER:
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WATER_CLASS_RIVER, _ctrl_pressed);
Command<CMD_BUILD_CANAL>::Post(STR_ERROR_CAN_T_PLACE_RIVERS, CcPlaySound_CONSTRUCTION_WATER, end_tile, start_tile, WaterClass::River, _ctrl_pressed);
break;
default: break;
@@ -333,7 +338,7 @@ struct BuildDocksToolbarWindow : Window {
* Nested widget parts of docks toolbar, game version.
* Position of #WID_DT_RIVER widget has changed.
*/
static constexpr NWidgetPart _nested_build_docks_toolbar_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_docks_toolbar_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_WATERWAYS_TOOLBAR_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -352,7 +357,7 @@ static constexpr NWidgetPart _nested_build_docks_toolbar_widgets[] = {
};
static WindowDesc _build_docks_toolbar_desc(
WDP_ALIGN_TOOLBAR, "toolbar_water", 0, 0,
WDP_MANUAL, "toolbar_water", 0, 0,
WC_BUILD_TOOLBAR, WC_NONE,
WindowDefaultFlag::Construction,
_nested_build_docks_toolbar_widgets,
@@ -378,7 +383,7 @@ Window *ShowBuildDocksToolbar()
* Nested widget parts of docks toolbar, scenario editor version.
* Positions of #WID_DT_DEPOT, #WID_DT_STATION, and #WID_DT_BUOY widgets have changed.
*/
static constexpr NWidgetPart _nested_build_docks_scen_toolbar_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_docks_scen_toolbar_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_WATERWAYS_TOOLBAR_CAPTION_SE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -412,21 +417,12 @@ Window *ShowBuildDocksScenToolbar()
return AllocateWindowDescFront<BuildDocksToolbarWindow>(_build_docks_scen_toolbar_desc, TRANSPORT_WATER);
}
/** Widget numbers of the build-dock GUI. */
enum BuildDockStationWidgets {
BDSW_BACKGROUND, ///< Background panel.
BDSW_LT_OFF, ///< 'Off' button of coverage high light.
BDSW_LT_ON, ///< 'On' button of coverage high light.
BDSW_INFO, ///< 'Coverage highlight' label.
BDSW_ACCEPTANCE, ///< Acceptance info.
};
struct BuildDocksStationWindow : public PickerWindowBase {
public:
BuildDocksStationWindow(WindowDesc &desc, Window *parent) : PickerWindowBase(desc, parent)
{
this->InitNested(TRANSPORT_WATER);
this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BDSW_LT_OFF);
}
void Close([[maybe_unused]] int data = 0) override
@@ -448,7 +444,7 @@ public:
}
/* strings such as 'Size' and 'Coverage Area' */
Rect r = this->GetWidget<NWidgetBase>(BDSW_ACCEPTANCE)->GetCurrentRect();
Rect r = this->GetWidget<NWidgetBase>(WID_BDSW_ACCEPTANCE)->GetCurrentRect();
const int bottom = r.bottom;
r.bottom = INT_MAX; // Allow overflow as we want to know the required height.
r.top = DrawStationCoverageAreaText(r, SCT_ALL, rad, false) + WidgetDimensions::scaled.vsep_normal;
@@ -464,11 +460,11 @@ public:
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
case BDSW_LT_OFF:
case BDSW_LT_ON:
this->RaiseWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
_settings_client.gui.station_show_coverage = (widget != BDSW_LT_OFF);
this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF);
case WID_BDSW_LT_OFF:
case WID_BDSW_LT_ON:
this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BDSW_LT_OFF);
_settings_client.gui.station_show_coverage = (widget != WID_BDSW_LT_OFF);
this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BDSW_LT_OFF);
SndClickBeep();
this->SetDirty();
SetViewportCatchmentStation(nullptr, true);
@@ -487,21 +483,21 @@ public:
};
/** Nested widget parts of a build dock station window. */
static constexpr NWidgetPart _nested_build_dock_station_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_dock_station_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_STATION_BUILD_DOCK_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BDSW_BACKGROUND),
NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BDSW_BACKGROUND),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), SetPadding(WidgetDimensions::unscaled.picker),
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_picker, 0),
NWidget(WWT_LABEL, INVALID_COLOUR, BDSW_INFO), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
NWidget(WWT_LABEL, INVALID_COLOUR, WID_BDSW_INFO), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize), SetPIP(14, 0, 14),
NWidget(WWT_TEXTBTN, COLOUR_GREY, BDSW_LT_OFF), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, BDSW_LT_ON), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BDSW_LT_OFF), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BDSW_LT_ON), SetMinimalSize(60, 12), SetFill(1, 0), SetStringTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
EndContainer(),
EndContainer(),
NWidget(WWT_EMPTY, INVALID_COLOUR, BDSW_ACCEPTANCE), SetResize(0, 1), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BDSW_ACCEPTANCE), SetResize(0, 1), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
EndContainer(),
EndContainer(),
};
@@ -564,8 +560,8 @@ public:
int y = (ir.Height() - ScaleSpriteTrad(64)) / 2;
int x1 = ScaleSpriteTrad(63);
int x2 = ScaleSpriteTrad(31);
DrawShipDepotSprite(x + (axis == AXIS_X ? x1 : x2), y + ScaleSpriteTrad(17), axis, DEPOT_PART_NORTH);
DrawShipDepotSprite(x + (axis == AXIS_X ? x2 : x1), y + ScaleSpriteTrad(33), axis, DEPOT_PART_SOUTH);
DrawShipDepotSprite(x + (axis == AXIS_X ? x1 : x2), y + ScaleSpriteTrad(17), axis, DepotPart::North);
DrawShipDepotSprite(x + (axis == AXIS_X ? x2 : x1), y + ScaleSpriteTrad(33), axis, DepotPart::South);
}
break;
}
@@ -588,7 +584,7 @@ public:
}
};
static constexpr NWidgetPart _nested_build_docks_depot_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_build_docks_depot_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_DEPOT_BUILD_SHIP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+3 -2
View File
@@ -145,11 +145,12 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t
/* Keep old driver in case we need to switch back, or may still need to process an OS callback. */
auto oldd = std::move(GetActiveDriver(type));
GetActiveDriver(type) = d->CreateInstance();
auto newd = d->CreateInstance();
auto err = GetActiveDriver(type)->Start({});
auto err = newd->Start({});
if (!err) {
Debug(driver, 1, "Successfully probed {} driver '{}'", GetDriverTypeName(type), d->name);
GetActiveDriver(type) = std::move(newd);
return true;
}
+43 -40
View File
@@ -8,6 +8,7 @@
/** @file dropdown.cpp Implementation of the dropdown widget. */
#include "stdafx.h"
#include "core/backup_type.hpp"
#include "dropdown_type.h"
#include "dropdown_func.h"
#include "strings_func.h"
@@ -56,7 +57,7 @@ std::unique_ptr<DropDownListItem> MakeDropDownListCheckedItem(bool checked, Stri
return std::make_unique<DropDownListCheckedItem>(indent, checked, GetString(str), value, masked, shaded);
}
static constexpr NWidgetPart _nested_dropdown_menu_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_dropdown_menu_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_END, WID_DM_ITEMS), SetScrollbar(WID_DM_SCROLL), EndContainer(),
NWidget(NWID_SELECTION, INVALID_COLOUR, WID_DM_SHOW_SCROLL),
@@ -81,8 +82,7 @@ struct DropdownWindow : Window {
int selected_click_result = -1; ///< Click result value, from the OnClick handler of the selected item.
uint8_t click_delay = 0; ///< Timer to delay selection.
bool drag_mode = true;
bool instant_close = false; ///< Close the window when the mouse button is raised.
bool persist = false; ///< Persist dropdown menu.
DropDownOptions options; ///< Options for this drop down menu.
int scrolling = 0; ///< If non-zero, auto-scroll the item list (one time).
Point position{}; ///< Position of the topleft corner of the window.
Scrollbar *vscroll = nullptr;
@@ -96,18 +96,16 @@ struct DropdownWindow : Window {
* @param selected Initial selected result of the list.
* @param button Widget of the parent window doing the dropdown.
* @param wi_rect Rect of the button that opened the dropdown.
* @param instant_close Close the window when the mouse button is raised.
* @param wi_colour Colour of the parent widget.
* @param persist Dropdown menu will persist.
* @param options Drop Down options for this menu.
*/
DropdownWindow(Window *parent, DropDownList &&list, int selected, WidgetID button, const Rect wi_rect, bool instant_close, Colours wi_colour, bool persist)
DropdownWindow(Window *parent, DropDownList &&list, int selected, WidgetID button, const Rect wi_rect, Colours wi_colour, DropDownOptions options)
: Window(_dropdown_desc)
, parent_button(button)
, wi_rect(wi_rect)
, list(std::move(list))
, selected_result(selected)
, instant_close(instant_close)
, persist(persist)
, options(options)
{
assert(!this->list.empty());
@@ -133,7 +131,7 @@ struct DropdownWindow : Window {
Point pt = _cursor.pos;
pt.x -= this->parent->left;
pt.y -= this->parent->top;
this->parent->OnDropdownClose(pt, this->parent_button, this->selected_result, this->selected_click_result, this->instant_close);
this->parent->OnDropdownClose(pt, this->parent_button, this->selected_result, this->selected_click_result, this->options.Test(DropDownOption::InstantClose));
/* Set flag on parent widget to indicate that we have just closed. */
NWidgetCore *nwc = this->parent->GetWidget<NWidgetCore>(this->parent_button);
@@ -143,7 +141,7 @@ struct DropdownWindow : Window {
void OnFocusLost(bool closing) override
{
if (!closing) {
this->instant_close = false;
this->options.Reset(DropDownOption::InstantClose);
this->Close();
}
}
@@ -208,8 +206,9 @@ struct DropdownWindow : Window {
this->GetWidget<NWidgetStacked>(WID_DM_SHOW_SCROLL)->SetDisplayedPlane(list_dim.height > widget_dim.height ? 0 : SZSP_NONE);
/* Capacity is the average number of items visible */
this->vscroll->SetCapacity((widget_dim.height - WidgetDimensions::scaled.dropdownlist.Vertical()) * this->list.size() / list_dim.height);
this->vscroll->SetCount(this->list.size());
this->vscroll->SetCapacity(widget_dim.height - WidgetDimensions::scaled.dropdownlist.Vertical());
this->vscroll->SetStepSize(list_dim.height / this->list.size());
this->vscroll->SetCount(list_dim.height);
/* If the dropdown is positioned above the parent widget, start selection at the bottom. */
if (this->position.y < button_rect.top && list_dim.height > widget_dim.height) this->vscroll->UpdatePosition(INT_MAX);
@@ -236,23 +235,22 @@ struct DropdownWindow : Window {
if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false;
const Rect &r = this->GetWidget<NWidgetBase>(WID_DM_ITEMS)->GetCurrentRect().Shrink(WidgetDimensions::scaled.dropdownlist).Shrink(WidgetDimensions::scaled.dropdowntext, RectPadding::zero);
int y = _cursor.pos.y - this->top - r.top;
int pos = this->vscroll->GetPosition();
int click_y = _cursor.pos.y - this->top - r.top;
int y = -this->vscroll->GetPosition();
int y_end = r.Height();
for (const auto &item : this->list) {
/* Skip items that are scrolled up */
if (--pos >= 0) continue;
int item_height = item->Height();
if (y < item_height) {
/* Skip items that are scrolled up */
if (y > y_end) break;
if (click_y >= y && click_y < y + item_height) {
if (item->masked || !item->Selectable()) return false;
result = item->result;
click_result = item->OnClick({r.left, 0, r.right, item_height - 1}, {_cursor.pos.x - this->left, y});
click_result = item->OnClick(r.WithY(0, item_height - 1), {_cursor.pos.x - this->left, click_y - y});
return true;
}
y -= item_height;
y += item_height;
}
return false;
@@ -265,16 +263,25 @@ struct DropdownWindow : Window {
Colours colour = this->GetWidget<NWidgetCore>(widget)->colour;
Rect ir = r.Shrink(WidgetDimensions::scaled.dropdownlist);
int y = ir.top;
int pos = this->vscroll->GetPosition();
/* Setup a clipping rectangle... */
DrawPixelInfo tmp_dpi;
if (!FillDrawPixelInfo(&tmp_dpi, ir)) return;
/* ...but keep coordinates relative to the window. */
tmp_dpi.left += ir.left;
tmp_dpi.top += ir.top;
AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
int y = -this->vscroll->GetPosition();
int y_end = ir.Height();
for (const auto &item : this->list) {
int item_height = item->Height();
/* Skip items that are scrolled up */
if (--pos >= 0) continue;
if (y + item_height - 1 <= ir.bottom) {
Rect full{ir.left, y, ir.right, y + item_height - 1};
if (y > y_end) break;
if (y > -item_height) {
Rect full = ir.Translate(0, y).WithHeight(item_height);
bool selected = (this->selected_result == item->result) && item->Selectable();
if (selected) GfxFillRect(full, PC_BLACK);
@@ -311,7 +318,7 @@ struct DropdownWindow : Window {
if (this->click_delay != 0 && --this->click_delay == 0) {
/* Close the dropdown, so it doesn't affect new window placement.
* Also mark it dirty in case the callback deals with the screen. (e.g. screenshots). */
if (!this->persist) this->Close();
if (!this->options.Test(DropDownOption::Persist)) this->Close();
this->parent->OnDropdownSelect(this->parent_button, this->selected_result, this->selected_click_result);
return;
}
@@ -322,7 +329,7 @@ struct DropdownWindow : Window {
if (!_left_button_clicked) {
this->drag_mode = false;
if (!this->GetDropDownItem(result, click_result)) {
if (this->instant_close) this->Close();
if (this->options.Test(DropDownOption::InstantClose)) this->Close();
return;
}
this->click_delay = 2;
@@ -390,14 +397,12 @@ Dimension GetDropDownListDimension(const DropDownList &list)
* @param button The widget which is passed to Window::OnDropdownSelect and OnDropdownClose.
* Unless you override those functions, this should be then widget index of the dropdown button.
* @param wi_rect Coord of the parent drop down button, used to position the dropdown menu.
* @param instant_close Set to true if releasing mouse button should close the
* list regardless of where the cursor is.
* @param persist Set if this dropdown should stay open after an option is selected.
* @param options Drop Down options for this menu.
*/
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, bool instant_close, bool persist)
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, DropDownOptions options)
{
CloseWindowByClass(WC_DROPDOWN_MENU);
new DropdownWindow(w, std::move(list), selected, button, wi_rect, instant_close, wi_colour, persist);
new DropdownWindow(w, std::move(list), selected, button, wi_rect, wi_colour, options);
}
/**
@@ -408,11 +413,9 @@ void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID b
* @param button The widget within the parent window that is used to determine
* the list's location.
* @param width Override the minimum width determined by the selected widget and list contents.
* @param instant_close Set to true if releasing mouse button should close the
* list regardless of where the cursor is.
* @param persist Set if this dropdown should stay open after an option is selected.
* @param options Drop Down options for this menu.
*/
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
{
/* Handle the beep of the player's click. */
SndClickBeep();
@@ -438,7 +441,7 @@ void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID but
}
}
ShowDropDownListAt(w, std::move(list), selected, button, wi_rect, wi_colour, instant_close, persist);
ShowDropDownListAt(w, std::move(list), selected, button, wi_rect, wi_colour, options);
}
/**
@@ -464,5 +467,5 @@ void ShowDropDownMenu(Window *w, std::span<const StringID> strings, int selected
++i;
}
if (!list.empty()) ShowDropDownList(w, std::move(list), selected, button, width);
if (!list.empty()) ShowDropDownList(w, std::move(list), selected, button, width, {});
}
+30 -4
View File
@@ -41,8 +41,8 @@ public:
PixelColour c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST);
int mid = CentreBounds(full.top, full.bottom, 0);
GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1);
GfxFillRect(full.left, mid, full.right, mid + WidgetDimensions::scaled.bevel.top - 1, c2);
GfxFillRect(full.WithY(mid - WidgetDimensions::scaled.bevel.bottom, mid - 1), c1);
GfxFillRect(full.WithY(mid, mid + WidgetDimensions::scaled.bevel.top - 1), c2);
}
};
@@ -216,7 +216,7 @@ public:
bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
int w = SETTING_BUTTON_WIDTH;
if (r.WithWidth(w, rtl).CentreTo(w, SETTING_BUTTON_HEIGHT).Contains(pt)) return this->click;
if (r.WithWidth(w, rtl).CentreToHeight(SETTING_BUTTON_HEIGHT).Contains(pt)) return this->click;
return this->TBase::OnClick(r.Indent(w + WidgetDimensions::scaled.hsep_wide, rtl), pt);
}
@@ -226,7 +226,7 @@ public:
bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
int w = SETTING_BUTTON_WIDTH;
Rect br = r.WithWidth(w, rtl).CentreTo(w, SETTING_BUTTON_HEIGHT);
Rect br = r.WithWidth(w, rtl).CentreToHeight(SETTING_BUTTON_HEIGHT);
DrawBoolButton(br.left, br.top, this->button_colour, this->background_colour, this->on, true);
this->TBase::Draw(full, r.Indent(w + WidgetDimensions::scaled.hsep_wide, rtl), sel, click_result, bg_colour);
@@ -260,6 +260,32 @@ public:
}
};
/**
* Drop down spacer component.
* @tparam TBase Base component.
* @tparam TEnd Position space at end if true, or start if false.
*/
template <class TBase, bool TEnd = false>
class DropDownSpacer : public TBase {
public:
template <typename... Args>
explicit DropDownSpacer(Args&&... args) : TBase(std::forward<Args>(args)...) {}
uint Width() const override { return WidgetDimensions::scaled.hsep_wide + this->TBase::Width(); }
int OnClick(const Rect &r, const Point &pt) const override
{
bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
return this->TBase::OnClick(r.Indent(WidgetDimensions::scaled.hsep_wide, rtl), pt);
}
void Draw(const Rect &full, const Rect &r, bool sel, int click_result, Colours bg_colour) const override
{
bool rtl = TEnd ^ (_current_text_dir == TD_RTL);
this->TBase::Draw(full, r.Indent(WidgetDimensions::scaled.hsep_wide, rtl), sel, click_result, bg_colour);
}
};
/**
* Drop down component that makes the item unselectable.
* @tparam TBase Base component.
+9 -2
View File
@@ -10,6 +10,7 @@
#ifndef DROPDOWN_TYPE_H
#define DROPDOWN_TYPE_H
#include "core/enum_type.hpp"
#include "window_type.h"
#include "gfx_func.h"
#include "gfx_type.h"
@@ -54,9 +55,15 @@ public:
*/
typedef std::vector<std::unique_ptr<const DropDownListItem>> DropDownList;
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, bool instant_close = false, bool persist = false);
enum class DropDownOption : uint8_t {
InstantClose, ///< Set if releasing mouse button should close the list regardless of where the cursor is.
Persist, ///< Set if this dropdown should stay open after an option is selected.
};
using DropDownOptions = EnumBitSet<DropDownOption, uint8_t>;
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width = 0, bool instant_close = false, bool persist = false);
void ShowDropDownListAt(Window *w, DropDownList &&list, int selected, WidgetID button, Rect wi_rect, Colours wi_colour, DropDownOptions options = {});
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width = 0, DropDownOptions options = {});
Dimension GetDropDownListDimension(const DropDownList &list);
+22 -20
View File
@@ -1181,7 +1181,7 @@ CargoPayment::CargoPayment(Vehicle *front) :
CargoPayment::~CargoPayment()
{
if (this->CleaningPool()) return;
if (CleaningPool()) return;
this->front->cargo_payment = nullptr;
@@ -1270,8 +1270,9 @@ void PrepareUnload(Vehicle *front_v)
assert(CargoPayment::CanAllocateItem());
front_v->cargo_payment = new CargoPayment(front_v);
StationIDStack next_station = front_v->GetNextStoppingStation();
if (front_v->orders == nullptr || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
std::vector<StationID> next_station;
front_v->GetNextStoppingStation(next_station);
if (front_v->orders == nullptr || front_v->current_order.GetUnloadType() != OrderUnloadType::NoUnload) {
Station *st = Station::Get(front_v->last_station_visited);
for (Vehicle *v = front_v; v != nullptr; v = v->Next()) {
const GoodsEntry *ge = &st->goods[v->cargo_type];
@@ -1433,7 +1434,7 @@ struct FinalizeRefitAction
{
CargoArray &consist_capleft; ///< Capacities left in the consist.
Station *st; ///< Station to reserve cargo from.
StationIDStack &next_station; ///< Next hops to reserve cargo for.
std::span<const StationID> next_station; ///< Next hops to reserve cargo for.
bool do_reserve; ///< If the vehicle should reserve.
/**
@@ -1443,7 +1444,7 @@ struct FinalizeRefitAction
* @param next_station Next hops to reserve cargo for.
* @param do_reserve If we should reserve cargo or just add up the capacities.
*/
FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station, bool do_reserve) :
FinalizeRefitAction(CargoArray &consist_capleft, Station *st, std::span<const StationID> next_station, bool do_reserve) :
consist_capleft(consist_capleft), st(st), next_station(next_station), do_reserve(do_reserve) {}
/**
@@ -1471,7 +1472,7 @@ struct FinalizeRefitAction
* @param next_station Possible next stations the vehicle can travel to.
* @param new_cargo_type Target cargo for refit.
*/
static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, StationIDStack next_station, CargoType new_cargo_type)
static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, std::span<const StationID> next_station, CargoType new_cargo_type)
{
Vehicle *v_start = v->GetFirstEnginePart();
if (!IterateVehicleParts(v_start, IsEmptyAction())) return;
@@ -1520,7 +1521,7 @@ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station
/* Add new capacity to consist capacity and reserve cargo */
IterateVehicleParts(v_start, FinalizeRefitAction(consist_capleft, st, next_station,
is_auto_refit || (v->First()->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0));
is_auto_refit || v->First()->current_order.IsFullLoadOrder()));
cur_company.Restore();
}
@@ -1538,16 +1539,16 @@ static bool MayLoadUnderExclusiveRights(const Station *st, const Vehicle *v)
struct ReserveCargoAction {
Station *st;
StationIDStack *next_station;
std::span<const StationID> next_station;
ReserveCargoAction(Station *st, StationIDStack *next_station) :
ReserveCargoAction(Station *st, std::span<const StationID> next_station) :
st(st), next_station(next_station) {}
bool operator()(Vehicle *v)
{
if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) {
st->goods[v->cargo_type].GetOrCreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(),
&v->cargo, *next_station, v->GetCargoTile());
&v->cargo, next_station, v->GetCargoTile());
}
return true;
@@ -1563,7 +1564,7 @@ struct ReserveCargoAction {
* @param consist_capleft If given, save free capacities after reserving there.
* @param next_station Station(s) the vehicle will stop at next.
*/
static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack *next_station)
static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, std::span<const StationID> next_station)
{
/* If there is a cargo payment not all vehicles of the consist have tried to do the refit.
* In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain"
@@ -1618,14 +1619,15 @@ static void LoadUnloadVehicle(Vehicle *front)
StationID last_visited = front->last_station_visited;
Station *st = Station::Get(last_visited);
StationIDStack next_station = front->GetNextStoppingStation();
std::vector<StationID> next_station;
front->GetNextStoppingStation(next_station);
bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CARGO_AUTO_REFIT;
CargoArray consist_capleft{};
if (_settings_game.order.improved_load && use_autorefit ?
front->cargo_payment == nullptr : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) {
front->cargo_payment == nullptr : (front->current_order.IsFullLoadOrder())) {
ReserveConsist(st, front,
(use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : nullptr,
&next_station);
next_station);
}
/* We have not waited enough time till the next round of loading/unloading */
@@ -1663,14 +1665,14 @@ static void LoadUnloadVehicle(Vehicle *front)
GoodsEntry *ge = &st->goods[v->cargo_type];
if (v->vehicle_flags.Test(VehicleFlag::CargoUnloading) && (front->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
if (v->vehicle_flags.Test(VehicleFlag::CargoUnloading) && front->current_order.GetUnloadType() != OrderUnloadType::NoUnload) {
uint cargo_count = v->cargo.UnloadCount();
uint amount_unloaded = _settings_game.order.gradual_loading ? std::min(cargo_count, GetLoadAmount(v)) : cargo_count;
bool remaining = false; // Are there cargo entities in this vehicle that can still be unloaded here?
if (!ge->status.Test(GoodsEntry::State::Acceptance) && v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER) > 0) {
/* The station does not accept our goods anymore. */
if (front->current_order.GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) {
if (front->current_order.GetUnloadType() == OrderUnloadType::Transfer || front->current_order.GetUnloadType() == OrderUnloadType::Unload) {
/* Transfer instead of delivering. */
v->cargo.Reassign<VehicleCargoList::MTA_DELIVER, VehicleCargoList::MTA_TRANSFER>(
v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER));
@@ -1728,7 +1730,7 @@ static void LoadUnloadVehicle(Vehicle *front)
}
/* Do not pick up goods when we have no-load set or loading is stopped. */
if (front->current_order.GetLoadType() & OLFB_NO_LOAD || front->vehicle_flags.Test(VehicleFlag::StopLoading)) continue;
if (front->current_order.GetLoadType() == OrderLoadType::NoLoad || front->vehicle_flags.Test(VehicleFlag::StopLoading)) continue;
/* This order has a refit, if this is the first vehicle part carrying cargo and the whole vehicle is empty, try refitting. */
if (front->current_order.IsRefit() && artic_part == 1) {
@@ -1852,7 +1854,7 @@ static void LoadUnloadVehicle(Vehicle *front)
}
/* We loaded less cargo than possible for all cargo types and it's not full
* load and we're not supposed to wait any longer: stop loading. */
if (!anything_unloaded && full_load_amount == 0 && reservation_left == 0 && !(front->current_order.GetLoadType() & OLFB_FULL_LOAD) &&
if (!anything_unloaded && full_load_amount == 0 && reservation_left == 0 && !front->current_order.IsFullLoadOrder() &&
front->current_order_time >= std::max(front->current_order.GetTimetabledWait() - front->lateness_counter, 0)) {
front->vehicle_flags.Set(VehicleFlag::StopLoading);
}
@@ -1861,8 +1863,8 @@ static void LoadUnloadVehicle(Vehicle *front)
} else {
UpdateLoadUnloadTicks(front, st, 20); // We need the ticks for link refreshing.
bool finished_loading = true;
if (front->current_order.GetLoadType() & OLFB_FULL_LOAD) {
if (front->current_order.GetLoadType() == OLF_FULL_LOAD_ANY) {
if (front->current_order.IsFullLoadOrder()) {
if (front->current_order.GetLoadType() == OrderLoadType::FullLoadAny) {
/* if the aircraft carries passengers and is NOT full, then
* continue loading, no matter how much mail is in */
if ((front->type == VEH_AIRCRAFT && IsCargoInClass(front->cargo_type, CargoClass::Passengers) && front->cargo_cap > front->cargo.StoredCount()) ||
+1 -1
View File
@@ -15,6 +15,6 @@
CommandCost CmdBuyCompany(DoCommandFlags flags, CompanyID target_company, bool hostile_takeover);
DEF_CMD_TRAIT(CMD_BUY_COMPANY, CmdBuyCompany, {}, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_BUY_COMPANY, CmdBuyCompany, {}, CommandType::MoneyManagement)
#endif /* ECONOMY_CMD_H */
+8 -9
View File
@@ -89,7 +89,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, DiagDirections *override
case MP_RAILWAY:
if (!HasRailCatenary(GetRailType(t))) return TRACK_BIT_NONE;
switch (GetRailTileType(t)) {
case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS:
case RailTileType::Normal: case RailTileType::Signals:
return GetTrackBits(t);
default:
return TRACK_BIT_NONE;
@@ -580,15 +580,13 @@ void SettingsDisableElrail(int32_t new_value)
void UpdateDisableElrailSettingState(bool disable, bool update_vehicles)
{
/* pick appropriate railtype for elrail engines depending on setting */
const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC;
/* walk through all train engines */
for (Engine *e : Engine::IterateType(VEH_TRAIN)) {
RailVehicleInfo *rv_info = &e->u.rail;
RailVehicleInfo *rv_info = &e->VehInfo<RailVehicleInfo>();
/* update railtype of engines intended to use elrail */
if (rv_info->intended_railtype == RAILTYPE_ELECTRIC) {
rv_info->railtype = new_railtype;
if (rv_info->intended_railtypes.Test(RAILTYPE_ELECTRIC)) {
rv_info->railtypes.Set(RAILTYPE_ELECTRIC, !disable);
rv_info->railtypes.Set(RAILTYPE_RAIL, disable);
}
}
@@ -596,11 +594,12 @@ void UpdateDisableElrailSettingState(bool disable, bool update_vehicles)
* normal rail too */
if (disable) {
for (Train *t : Train::Iterate()) {
if (t->railtype == RAILTYPE_ELECTRIC) {
if (t->railtypes.Test(RAILTYPE_ELECTRIC)) {
/* this railroad vehicle is now compatible only with elrail,
* so add there also normal rail compatibility */
t->compatible_railtypes.Set(RAILTYPE_RAIL);
t->railtype = RAILTYPE_RAIL;
t->railtypes.Reset(RAILTYPE_ELECTRIC);
t->railtypes.Set(RAILTYPE_RAIL);
t->flags.Set(VehicleRailFlag::AllowedOnNormalRail);
}
}
+68 -68
View File
@@ -78,24 +78,19 @@ Engine::Engine(VehicleType type, uint16_t local_id)
/* Check if this base engine is within the original engine data range */
if (local_id >= _engine_counts[type]) {
/* 'power' defaults to zero, so we also have to default to 'wagon' */
if (type == VEH_TRAIN) this->u.rail.railveh_type = RAILVEH_WAGON;
/* Initialise default type-specific information. */
switch (type) {
case VEH_TRAIN: this->vehicle_info.emplace<RailVehicleInfo>(); break;
case VEH_ROAD: this->vehicle_info.emplace<RoadVehicleInfo>(); break;
case VEH_SHIP: this->vehicle_info.emplace<ShipVehicleInfo>(); break;
case VEH_AIRCRAFT: this->vehicle_info.emplace<AircraftVehicleInfo>(); break;
default: break;
}
/* Set model life to maximum to make wagons available */
this->info.base_life = TimerGameCalendar::Year{0xFF};
/* Set road vehicle tractive effort to the default value */
if (type == VEH_ROAD) this->u.road.tractive_effort = 0x4C;
/* Aircraft must have CT_INVALID as default, as there is no property */
this->info.cargo_type = INVALID_CARGO;
this->info.cargo_label = (type == VEH_AIRCRAFT) ? CT_INVALID : CT_PASSENGERS;
/* Ships must have a non-zero acceleration. */
if (type == VEH_SHIP) this->u.ship.acceleration = 1;
/* Set visual effect to the default value */
switch (type) {
case VEH_TRAIN: this->u.rail.visual_effect = VE_DEFAULT; break;
case VEH_ROAD: this->u.road.visual_effect = VE_DEFAULT; break;
case VEH_SHIP: this->u.ship.visual_effect = VE_DEFAULT; break;
default: break; // The aircraft, disasters and especially visual effects have no NewGRF configured visual effects
}
/* Set cargo aging period to the default value. */
this->info.cargo_age_period = Ticks::CARGO_AGING_TICKS;
/* Not a variant */
@@ -110,33 +105,37 @@ Engine::Engine(VehicleType type, uint16_t local_id)
switch (type) {
default: NOT_REACHED();
case VEH_TRAIN:
this->u.rail = _orig_rail_vehicle_info[local_id];
this->original_image_index = this->u.rail.image_index;
case VEH_TRAIN: {
RailVehicleInfo &rvi = this->vehicle_info.emplace<RailVehicleInfo>(_orig_rail_vehicle_info[local_id]);
this->original_image_index = rvi.image_index;
this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + local_id;
/* Set the default model life of original wagons to "infinite" */
if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
if (rvi.railveh_type == RAILVEH_WAGON) this->info.base_life = TimerGameCalendar::Year{0xFF};
break;
}
case VEH_ROAD:
this->u.road = _orig_road_vehicle_info[local_id];
this->original_image_index = this->u.road.image_index;
case VEH_ROAD: {
RoadVehicleInfo &rvi = this->vehicle_info.emplace<RoadVehicleInfo>(_orig_road_vehicle_info[local_id]);
this->original_image_index = rvi.image_index;
this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + local_id;
break;
}
case VEH_SHIP:
this->u.ship = _orig_ship_vehicle_info[local_id];
this->original_image_index = this->u.ship.image_index;
case VEH_SHIP: {
ShipVehicleInfo &svi = this->vehicle_info.emplace<ShipVehicleInfo>(_orig_ship_vehicle_info[local_id]);
this->original_image_index = svi.image_index;
this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + local_id;
break;
}
case VEH_AIRCRAFT:
this->u.air = _orig_aircraft_vehicle_info[local_id];
this->original_image_index = this->u.air.image_index;
case VEH_AIRCRAFT: {
AircraftVehicleInfo &avi = this->vehicle_info.emplace<AircraftVehicleInfo>(_orig_aircraft_vehicle_info[local_id]);
this->original_image_index = avi.image_index;
this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + local_id;
break;
}
}
}
@@ -174,11 +173,11 @@ bool Engine::CanCarryCargo() const
*/
switch (this->type) {
case VEH_TRAIN:
if (this->u.rail.capacity == 0) return false;
if (this->VehInfo<RailVehicleInfo>().capacity == 0) return false;
break;
case VEH_ROAD:
if (this->u.road.capacity == 0) return false;
if (this->VehInfo<RoadVehicleInfo>().capacity == 0) return false;
break;
case VEH_SHIP:
@@ -210,7 +209,7 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
CargoType cargo_type = (v != nullptr) ? v->cargo_type : default_cargo;
if (mail_capacity != nullptr && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CargoClass::Passengers)) {
*mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
*mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
}
/* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */
@@ -225,24 +224,24 @@ uint Engine::DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity) const
uint extra_mail_cap = 0;
switch (this->type) {
case VEH_TRAIN:
capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v);
capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->VehInfo<RailVehicleInfo>().capacity, v);
/* In purchase list add the capacity of the second head. Always use the plain property for this. */
if (v == nullptr && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity;
if (v == nullptr && this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD) capacity += this->VehInfo<RailVehicleInfo>().capacity;
break;
case VEH_ROAD:
capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity, v);
capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->VehInfo<RoadVehicleInfo>().capacity, v);
break;
case VEH_SHIP:
capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity, v);
capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->VehInfo<ShipVehicleInfo>().capacity, v);
break;
case VEH_AIRCRAFT:
capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->u.air.passenger_capacity, v);
capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->VehInfo<AircraftVehicleInfo>().passenger_capacity, v);
if (!IsCargoInClass(cargo_type, CargoClass::Passengers)) {
extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v);
extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->VehInfo<AircraftVehicleInfo>().mail_capacity, v);
}
if (IsValidCargoType(GetCargoTypeByLabel(CT_MAIL))) {
if (!new_multipliers && cargo_type == GetCargoTypeByLabel(CT_MAIL)) return capacity + extra_mail_cap;
@@ -284,25 +283,25 @@ Money Engine::GetRunningCost() const
uint cost_factor;
switch (this->type) {
case VEH_ROAD:
base_price = this->u.road.running_cost_class;
base_price = this->VehInfo<RoadVehicleInfo>().running_cost_class;
if (base_price == INVALID_PRICE) return 0;
cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost);
cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().running_cost);
break;
case VEH_TRAIN:
base_price = this->u.rail.running_cost_class;
base_price = this->VehInfo<RailVehicleInfo>().running_cost_class;
if (base_price == INVALID_PRICE) return 0;
cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost);
cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->VehInfo<RailVehicleInfo>().running_cost);
break;
case VEH_SHIP:
base_price = PR_RUNNING_SHIP;
cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost);
cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().running_cost);
break;
case VEH_AIRCRAFT:
base_price = PR_RUNNING_AIRCRAFT;
cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost);
cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().running_cost);
break;
default: NOT_REACHED();
@@ -322,27 +321,27 @@ Money Engine::GetCost() const
switch (this->type) {
case VEH_ROAD:
base_price = PR_BUILD_VEHICLE_ROAD;
cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->u.road.cost_factor);
cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->VehInfo<RoadVehicleInfo>().cost_factor);
break;
case VEH_TRAIN:
if (this->u.rail.railveh_type == RAILVEH_WAGON) {
if (this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) {
base_price = PR_BUILD_VEHICLE_WAGON;
cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
} else {
base_price = PR_BUILD_VEHICLE_TRAIN;
cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor);
cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->VehInfo<RailVehicleInfo>().cost_factor);
}
break;
case VEH_SHIP:
base_price = PR_BUILD_VEHICLE_SHIP;
cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->u.ship.cost_factor);
cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->VehInfo<ShipVehicleInfo>().cost_factor);
break;
case VEH_AIRCRAFT:
base_price = PR_BUILD_VEHICLE_AIRCRAFT;
cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->u.air.cost_factor);
cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->VehInfo<AircraftVehicleInfo>().cost_factor);
break;
default: NOT_REACHED();
@@ -359,22 +358,22 @@ uint Engine::GetDisplayMaxSpeed() const
{
switch (this->type) {
case VEH_TRAIN:
return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->u.rail.max_speed);
return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->VehInfo<RailVehicleInfo>().max_speed);
case VEH_ROAD: {
uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0);
return (max_speed != 0) ? max_speed * 2 : this->u.road.max_speed / 2;
return (max_speed != 0) ? max_speed * 2 : this->VehInfo<RoadVehicleInfo>().max_speed / 2;
}
case VEH_SHIP:
return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->u.ship.max_speed) / 2;
return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->VehInfo<ShipVehicleInfo>().max_speed) / 2;
case VEH_AIRCRAFT: {
uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0);
if (max_speed != 0) {
return (max_speed * 128) / 10;
}
return this->u.air.max_speed;
return this->VehInfo<AircraftVehicleInfo>().max_speed;
}
default: NOT_REACHED();
@@ -392,9 +391,9 @@ uint Engine::GetPower() const
/* Only trains and road vehicles have 'power'. */
switch (this->type) {
case VEH_TRAIN:
return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->u.rail.power);
return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->VehInfo<RailVehicleInfo>().power);
case VEH_ROAD:
return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->u.road.power) * 10;
return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->VehInfo<RoadVehicleInfo>().power) * 10;
default: NOT_REACHED();
}
@@ -410,9 +409,9 @@ uint Engine::GetDisplayWeight() const
/* Only trains and road vehicles have 'weight'. */
switch (this->type) {
case VEH_TRAIN:
return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->VehInfo<RailVehicleInfo>().weight) << (this->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
case VEH_ROAD:
return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->u.road.weight) / 4;
return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->VehInfo<RoadVehicleInfo>().weight) / 4;
default: NOT_REACHED();
}
@@ -428,9 +427,9 @@ uint Engine::GetDisplayMaxTractiveEffort() const
/* Only trains and road vehicles have 'tractive effort'. */
switch (this->type) {
case VEH_TRAIN:
return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256;
return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->VehInfo<RailVehicleInfo>().tractive_effort)) / 256;
case VEH_ROAD:
return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256;
return (GROUND_ACCELERATION * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->VehInfo<RoadVehicleInfo>().tractive_effort)) / 256;
default: NOT_REACHED();
}
@@ -454,7 +453,7 @@ uint16_t Engine::GetRange() const
{
switch (this->type) {
case VEH_AIRCRAFT:
return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range);
return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->VehInfo<AircraftVehicleInfo>().max_range);
default: NOT_REACHED();
}
@@ -468,7 +467,7 @@ StringID Engine::GetAircraftTypeText() const
{
switch (this->type) {
case VEH_AIRCRAFT:
switch (this->u.air.subtype) {
switch (this->VehInfo<AircraftVehicleInfo>().subtype) {
case AIR_HELI: return STR_LIVERY_HELICOPTER;
case AIR_CTOL: return STR_LIVERY_SMALL_PLANE;
case AIR_CTOL | AIR_FAST: return STR_LIVERY_LARGE_PLANE;
@@ -625,7 +624,7 @@ void ShowEnginePreviewWindow(EngineID engine);
static bool IsWagon(EngineID index)
{
const Engine *e = Engine::Get(index);
return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
return e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON;
}
/**
@@ -700,7 +699,7 @@ void SetYearEngineAgingStops()
/* Exclude certain engines */
if (!ei->climates.Test(_settings_game.game_creation.landscape)) continue;
if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
if (e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) continue;
/* Base year ending date on half the model life */
TimerGameCalendar::YearMonthDay ymd = TimerGameCalendar::ConvertDateToYMD(ei->base_intro + (ei->lifelength.base() * CalendarTime::DAYS_IN_LEAP_YEAR) / 2);
@@ -1107,12 +1106,13 @@ static void NewVehicleAvailable(Engine *e)
if (e->type == VEH_TRAIN) {
/* maybe make another rail type available */
assert(e->u.rail.railtype < RAILTYPE_END);
for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, TimerGameCalendar::date);
assert(e->VehInfo<RailVehicleInfo>().railtypes != RailTypes{});
RailTypes introduced = GetAllIntroducesRailTypes(e->VehInfo<RailVehicleInfo>().railtypes);
for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | introduced, TimerGameCalendar::date);
} else if (e->type == VEH_ROAD) {
/* maybe make another road type available */
assert(e->u.road.roadtype < ROADTYPE_END);
for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, TimerGameCalendar::date);
assert(e->VehInfo<RoadVehicleInfo>().roadtype < ROADTYPE_END);
for (Company *c : Company::Iterate()) c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->introduces_roadtypes, TimerGameCalendar::date);
}
/* Only broadcast event if AIs are able to build this vehicle type. */
@@ -1267,12 +1267,12 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
if (type == VEH_TRAIN && company != OWNER_DEITY) {
/* Check if the rail type is available to this company */
const Company *c = Company::Get(company);
if (!GetRailTypeInfo(e->u.rail.railtype)->compatible_railtypes.Any(c->avail_railtypes)) return false;
if (!GetAllCompatibleRailTypes(e->VehInfo<RailVehicleInfo>().railtypes).Any(c->avail_railtypes)) return false;
}
if (type == VEH_ROAD && company != OWNER_DEITY) {
/* Check if the road type is available to this company */
const Company *c = Company::Get(company);
if (!GetRoadTypeInfo(e->u.road.roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
if (!GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->powered_roadtypes.Any(c->avail_roadtypes)) return false;
}
return true;
@@ -1318,7 +1318,7 @@ void CheckEngines()
if (!e->IsEnabled()) continue;
/* Don't consider train wagons, we need a powered engine available. */
if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue;
if (e->type == VEH_TRAIN && e->VehInfo<RailVehicleInfo>().railveh_type == RAILVEH_WAGON) continue;
/* We have an available engine... yay! */
if (e->flags.Test(EngineFlag::Available) && e->company_avail.Any()) return;
+23 -12
View File
@@ -35,7 +35,8 @@ using EngineDisplayFlags = EnumBitSet<EngineDisplayFlag, uint8_t>;
typedef Pool<Engine, EngineID, 64> EnginePool;
extern EnginePool _engine_pool;
struct Engine : EnginePool::PoolItem<&_engine_pool> {
class Engine : public EnginePool::PoolItem<&_engine_pool> {
public:
CompanyMask company_avail{}; ///< Bit for each company whether the engine is available for that company.
CompanyMask company_hidden{}; ///< Bit for each company whether the engine is normally hidden in the build gui for that company.
CompanyMask preview_asked{}; ///< Bit for each company which has already been offered a preview.
@@ -64,13 +65,6 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
EngineID display_last_variant = EngineID::Invalid(); ///< NOSAVE client-side-only last variant selected.
EngineInfo info{};
union {
RailVehicleInfo rail;
RoadVehicleInfo road;
ShipVehicleInfo ship;
AircraftVehicleInfo air;
} u{};
uint16_t list_position = 0;
/* NewGRF related data */
@@ -78,6 +72,11 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
std::vector<WagonOverride> overrides{};
std::vector<BadgeID> badges{};
private:
/* Vehicle-type specific information. */
std::variant<std::monostate, RailVehicleInfo, RoadVehicleInfo, ShipVehicleInfo, AircraftVehicleInfo> vehicle_info{};
public:
Engine() {}
Engine(VehicleType type, uint16_t local_id);
bool IsEnabled() const;
@@ -177,6 +176,18 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> {
bool operator() (size_t index) { return Engine::Get(index)->type == this->vt; }
};
template <typename T>
inline T &VehInfo()
{
return std::get<T>(this->vehicle_info);
}
template <typename T>
inline const T &VehInfo() const
{
return std::get<T>(this->vehicle_info);
}
/**
* Returns an iterable ensemble of all valid engines of the given type
* @param vt the VehicleType for engines to be valid
@@ -234,22 +245,22 @@ inline const EngineInfo *EngInfo(EngineID e)
inline const RailVehicleInfo *RailVehInfo(EngineID e)
{
return &Engine::Get(e)->u.rail;
return &Engine::Get(e)->VehInfo<RailVehicleInfo>();
}
inline const RoadVehicleInfo *RoadVehInfo(EngineID e)
{
return &Engine::Get(e)->u.road;
return &Engine::Get(e)->VehInfo<RoadVehicleInfo>();
}
inline const ShipVehicleInfo *ShipVehInfo(EngineID e)
{
return &Engine::Get(e)->u.ship;
return &Engine::Get(e)->VehInfo<ShipVehicleInfo>();
}
inline const AircraftVehicleInfo *AircraftVehInfo(EngineID e)
{
return &Engine::Get(e)->u.air;
return &Engine::Get(e)->VehInfo<AircraftVehicleInfo>();
}
#endif /* ENGINE_BASE_H */
+4 -4
View File
@@ -17,9 +17,9 @@ CommandCost CmdEngineCtrl(DoCommandFlags flags, EngineID engine_id, CompanyID co
CommandCost CmdRenameEngine(DoCommandFlags flags, EngineID engine_id, const std::string &text);
CommandCost CmdSetVehicleVisibility(DoCommandFlags flags, EngineID engine_id, bool hide);
DEF_CMD_TRAIT(CMD_WANT_ENGINE_PREVIEW, CmdWantEnginePreview, {}, CMDT_VEHICLE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_ENGINE_CTRL, CmdEngineCtrl, CommandFlag::Deity, CMDT_VEHICLE_MANAGEMENT)
DEF_CMD_TRAIT(CMD_RENAME_ENGINE, CmdRenameEngine, CommandFlag::Server, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_VEHICLE_VISIBILITY, CmdSetVehicleVisibility, {}, CMDT_COMPANY_SETTING)
DEF_CMD_TRAIT(CMD_WANT_ENGINE_PREVIEW, CmdWantEnginePreview, {}, CommandType::VehicleManagement)
DEF_CMD_TRAIT(CMD_ENGINE_CTRL, CmdEngineCtrl, CommandFlag::Deity, CommandType::VehicleManagement)
DEF_CMD_TRAIT(CMD_RENAME_ENGINE, CmdRenameEngine, CommandFlag::Server, CommandType::OtherManagement)
DEF_CMD_TRAIT(CMD_SET_VEHICLE_VISIBILITY, CmdSetVehicleVisibility, {}, CommandType::CompanySetting)
#endif /* ENGINE_CMD_H */
+24 -4
View File
@@ -43,15 +43,16 @@ StringID GetEngineCategoryName(EngineID engine)
switch (e->type) {
default: NOT_REACHED();
case VEH_ROAD:
return GetRoadTypeInfo(e->u.road.roadtype)->strings.new_engine;
return GetRoadTypeInfo(e->VehInfo<RoadVehicleInfo>().roadtype)->strings.new_engine;
case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT;
case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP;
case VEH_TRAIN:
return GetRailTypeInfo(e->u.rail.railtype)->strings.new_loco;
assert(e->VehInfo<RailVehicleInfo>().railtypes.Any());
return GetRailTypeInfo(e->VehInfo<RailVehicleInfo>().railtypes.GetNthSetBit(0).value())->strings.new_loco;
}
}
static constexpr NWidgetPart _nested_engine_preview_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_engine_preview_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetStringTip(STR_ENGINE_PREVIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
@@ -181,7 +182,26 @@ static std::string GetTrainEngineInfoString(const Engine &e)
res << GetString(STR_ENGINE_PREVIEW_COST_WEIGHT, e.GetCost(), e.GetDisplayWeight());
res << '\n';
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(e.u.rail.railtype)->acceleration_type != 2) {
if (e.VehInfo<RailVehicleInfo>().railtypes.Count() > 1) {
std::string railtypes{};
std::string_view list_separator = GetListSeparator();
for (const auto &rt : _sorted_railtypes) {
if (!e.VehInfo<RailVehicleInfo>().railtypes.Test(rt)) continue;
if (!railtypes.empty()) railtypes += list_separator;
AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
}
res << GetString(STR_ENGINE_PREVIEW_RAILTYPES, railtypes);
res << '\n';
}
bool is_maglev = true;
for (RailType rt : e.VehInfo<RailVehicleInfo>().railtypes) {
is_maglev &= GetRailTypeInfo(rt)->acceleration_type == VehicleAccelerationModel::Maglev;
}
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && !is_maglev) {
res << GetString(STR_ENGINE_PREVIEW_SPEED_POWER_MAX_TE, PackVelocity(e.GetDisplayMaxSpeed(), e.type), e.GetPower(), e.GetDisplayMaxTractiveEffort());
res << '\n';
} else {
+36 -9
View File
@@ -25,7 +25,7 @@
/** Unique identification number of an engine. */
using EngineID = PoolID<uint16_t, struct EngineIDTag, 64000, 0xFFFF>;
struct Engine;
class Engine;
/** Available types of rail vehicles. */
enum RailVehicleTypes : uint8_t {
@@ -43,13 +43,40 @@ enum EngineClass : uint8_t {
EC_MAGLEV, ///< Maglev engine.
};
/** Acceleration model of a vehicle. */
enum class VehicleAccelerationModel : uint8_t {
Normal, ///< Default acceleration model.
Monorail, ///< Monorail acceleration model.
Maglev, ///< Maglev acceleration model.
};
/** Meaning of the various bits of the visual effect. */
enum VisualEffect : uint8_t {
VE_OFFSET_START = 0, ///< First bit that contains the offset (0 = front, 8 = centre, 15 = rear)
VE_OFFSET_COUNT = 4, ///< Number of bits used for the offset
VE_OFFSET_CENTRE = 8, ///< Value of offset corresponding to a position above the centre of the vehicle
VE_TYPE_START = 4, ///< First bit used for the type of effect
VE_TYPE_COUNT = 2, ///< Number of bits used for the effect type
VE_TYPE_DEFAULT = 0, ///< Use default from engine class
VE_TYPE_STEAM = 1, ///< Steam plumes
VE_TYPE_DIESEL = 2, ///< Diesel fumes
VE_TYPE_ELECTRIC = 3, ///< Electric sparks
VE_DISABLE_EFFECT = 6, ///< Flag to disable visual effect
VE_ADVANCED_EFFECT = VE_DISABLE_EFFECT, ///< Flag for advanced effects
VE_DISABLE_WAGON_POWER = 7, ///< Flag to disable wagon power
VE_DEFAULT = 0xFF, ///< Default value to indicate that visual effect should be based on engine class
};
/** Information about a rail vehicle. */
struct RailVehicleInfo {
uint8_t image_index = 0;
RailVehicleTypes railveh_type{};
RailVehicleTypes railveh_type = RAILVEH_WAGON;
uint8_t cost_factor = 0; ///< Purchase cost factor; For multiheaded engines the sum of both engine prices.
RailType railtype{}; ///< Railtype, mangled if elrail is disabled.
RailType intended_railtype{}; ///< Intended railtype, regardless of elrail being enabled or disabled.
RailTypes railtypes{RAILTYPE_RAIL}; ///< Railtypes, mangled if elrail is disabled.
RailTypes intended_railtypes{RAILTYPE_RAIL}; ///< Intended railtypes, regardless of elrail being enabled or disabled.
uint8_t ai_passenger_only = 0; ///< Bit value to tell AI that this engine is for passenger use only
uint16_t max_speed = 0; ///< Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
uint16_t power = 0; ///< Power of engine (hp); For multiheaded engines the sum of both engine powers.
@@ -60,7 +87,7 @@ struct RailVehicleInfo {
uint8_t capacity = 0; ///< Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine.
uint16_t pow_wag_power = 0; ///< Extra power applied to consist if wagon should be powered
uint8_t pow_wag_weight = 0; ///< Extra weight applied to consist if wagon should be powered
uint8_t visual_effect = 0; ///< Bitstuffed NewGRF visual effect data
uint8_t visual_effect = VE_DEFAULT; ///< Bitstuffed NewGRF visual effect data
uint8_t shorten_factor = 0; ///< length on main map for this type is 8 - shorten_factor
uint8_t tractive_effort = 0; ///< Tractive effort coefficient
uint8_t air_drag = 0; ///< Coefficient of air drag
@@ -73,12 +100,12 @@ struct ShipVehicleInfo {
uint8_t image_index = 0;
uint8_t cost_factor = 0;
uint8_t running_cost = 0;
uint8_t acceleration = 0; ///< Acceleration (1 unit = 1/3.2 mph per tick = 0.5 km-ish/h per tick)
uint8_t acceleration = 1; ///< Acceleration (1 unit = 1/3.2 mph per tick = 0.5 km-ish/h per tick)
uint16_t max_speed = 0; ///< Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h)
uint16_t capacity = 0;
SoundID sfx{};
bool old_refittable = 0; ///< Is ship refittable; only used during initialisation. Later use EngineInfo::refit_mask.
uint8_t visual_effect = 0; ///< Bitstuffed NewGRF visual effect data
uint8_t visual_effect = VE_DEFAULT; ///< Bitstuffed NewGRF visual effect data
uint8_t ocean_speed_frac = 0; ///< Fraction of maximum speed for ocean tiles.
uint8_t canal_speed_frac = 0; ///< Fraction of maximum speed for canal/river tiles.
@@ -126,9 +153,9 @@ struct RoadVehicleInfo {
uint8_t capacity = 0;
uint8_t weight = 0; ///< Weight in 1/4t units
uint8_t power = 0; ///< Power in 10hp units
uint8_t tractive_effort = 0; ///< Coefficient of tractive effort
uint8_t tractive_effort = 0x4C; ///< Coefficient of tractive effort
uint8_t air_drag = 0; ///< Coefficient of air drag
uint8_t visual_effect = 0; ///< Bitstuffed NewGRF visual effect data
uint8_t visual_effect = VE_DEFAULT; ///< Bitstuffed NewGRF visual effect data
uint8_t shorten_factor = 0; ///< length on main map for this type is 8 - shorten_factor
RoadType roadtype{}; ///< Road type
};
+3 -3
View File
@@ -33,7 +33,7 @@
#include "safeguards.h"
static constexpr NWidgetPart _nested_errmsg_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_errmsg_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_RED),
NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetStringTip(STR_ERROR_MESSAGE_CAPTION),
@@ -50,7 +50,7 @@ static WindowDesc _errmsg_desc(
_nested_errmsg_widgets
);
static constexpr NWidgetPart _nested_errmsg_face_widgets[] = {
static constexpr std::initializer_list<NWidgetPart> _nested_errmsg_face_widgets = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_RED),
NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION),
@@ -209,7 +209,7 @@ public:
/* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */
Rect top_section = r.WithHeight(this->height_summary + extra, false);
Rect bottom_section = r.WithHeight(this->height_extra + extra, true);
Rect middle_section = { top_section.left, top_section.bottom, top_section.right, bottom_section.top };
Rect middle_section = top_section.WithY(top_section.bottom, bottom_section.top);
DrawStringMultiLineWithClipping(top_section, this->summary_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(middle_section, this->detailed_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
DrawStringMultiLineWithClipping(bottom_section, this->extra_msg.GetDecodedString(), TC_WHITE, SA_CENTER);
+7 -4
View File
@@ -328,9 +328,12 @@ bool FioRemove(const std::string &filename)
{
std::filesystem::path path = OTTD2FS(filename);
std::error_code error_code;
std::filesystem::remove(path, error_code);
if (error_code) {
Debug(misc, 0, "Removing {} failed: {}", filename, error_code.message());
if (!std::filesystem::remove(path, error_code)) {
if (error_code) {
Debug(misc, 0, "Removing {} failed: {}", filename, error_code.message());
} else {
Debug(misc, 0, "Removing {} failed: file does not exist", filename);
}
return false;
}
return true;
@@ -590,7 +593,7 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
/* We don't know the file. */
if (it == _tar_list[subdir].end()) return false;
const auto &dirname = (*it).second;
const auto &dirname = it->second;
/* The file doesn't have a sub directory! */
if (dirname.empty()) {
+1 -11
View File
@@ -230,16 +230,6 @@ std::string FiosMakeHeightmapName(std::string_view name)
return FiosMakeFilename(_fios_path, name, fmt::format(".{}", GetCurrentScreenshotExtension()));
}
/**
* Delete a file.
* @param name Filename to delete.
* @return Whether the file deletion was successful.
*/
bool FiosDelete(std::string_view name)
{
return FioRemove(FiosMakeSavegameName(name));
}
typedef std::tuple<FiosType, std::string> FiosGetTypeAndNameProc(SaveLoadOperation fop, std::string_view filename, std::string_view ext);
/**
@@ -517,7 +507,7 @@ std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(SaveLoadOperation
for (Searchpath sp : _valid_searchpaths) {
std::string buf = FioGetDirectory(sp, HEIGHTMAP_DIR);
if (buf.compare(0, buf.size(), it->second.tar_filename, 0, buf.size()) == 0) {
if (it->second.tar_filename.starts_with(buf)) {
match = true;
break;
}

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