Merge branch 'master' into jgrpp

# Conflicts:
#	src/3rdparty/fmt/core.h
#	src/command_type.h
#	src/console_cmds.cpp
#	src/core/overflowsafe_type.hpp
#	src/landscape.cpp
#	src/network/network.cpp
#	src/newgrf_object.h
#	src/object_cmd.cpp
#	src/order_gui.cpp
#	src/saveload/vehicle_sl.cpp
#	src/script/api/script_industrytype.cpp
#	src/script/api/script_object.hpp
#	src/script/api/script_town.cpp
#	src/table/object_land.h
#	src/timetable_cmd.cpp
#	src/tree_cmd.cpp
#	src/vehicle_gui.cpp
#	src/window.cpp
This commit is contained in:
Jonathan G Rennison 2023-01-15 19:28:37 +00:00
commit 1bfd96c7f2
64 changed files with 442 additions and 310 deletions

10
.github/codeql/codeql-config.yml vendored Normal file
View File

@ -0,0 +1,10 @@
name: openttd
queries:
- uses: security-and-quality
query-filters:
- exclude:
id:
# Only feasible way is to move away from fopen; fopen_s is optional C11 and not implemented on most platforms.
- cpp/world-writable-file-creation
# Basically OpenTTD's coding style for adding things like ..._INVALID to enumerations
- cpp/irregular-enum-init

78
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,78 @@
name: CodeQL
on:
push:
branches:
- master
pull_request:
# The branches below must be a subset of the branches above
branches:
- master
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install dependencies
run: |
echo "::group::Update apt"
sudo apt-get update
echo "::endgroup::"
echo "::group::Install dependencies"
sudo apt-get install -y --no-install-recommends \
liballegro4-dev \
libfontconfig-dev \
libicu-dev \
liblzma-dev \
liblzo2-dev \
libsdl2-dev \
zlib1g-dev \
# EOF
echo "::endgroup::"
env:
DEBIAN_FRONTEND: noninteractive
- name: Set number of make jobs
run: |
echo "MAKEFLAGS=-j$(nproc)" >> $GITHUB_ENV
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: cpp
config-file: ./.github/codeql/codeql-config.yml
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: /language:cpp
upload: False
output: sarif-results
- name: Filter out table & generated code
uses: advanced-security/filter-sarif@v1
with:
patterns: |
+**/*.*
-**/table/*.*
-**/generated/**/*.*
input: sarif-results/cpp.sarif
output: sarif-results/cpp.sarif
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: sarif-results/cpp.sarif

View File

@ -88,24 +88,24 @@
abs( 21): 21
--AIBase--
Rand(): -54346916
Rand(): -937374575
Rand(): 823953997
Rand(): -2062310602
Rand(): -1780331126
Rand(): -397928569
RandRange(0): 0
RandRange(0): 0
RandRange(0): 0
RandRange(1): 0
RandRange(1): 0
RandRange(1): 0
RandRange(2): 1
RandRange(2): 1
RandRange(2): 1
RandRange(1000000): 966676
RandRange(1000000): 289525
RandRange(1000000): 170283
Chance(1, 2): false
RandRange(2): 0
RandRange(2): 0
RandRange(2): 0
RandRange(1000000): 666804
RandRange(1000000): 624059
RandRange(1000000): 697029
Chance(1, 2): true
Chance(1, 2): false
Chance(1, 2): true
--List--
IsEmpty(): true
@ -420,144 +420,144 @@
1098 => 46116
1099 => 46158
Randomize ListDump:
1 => -200078348
2 => -29799264
1000 => 1630721656
1001 => 959306175
1002 => 1527421791
1003 => 1259692483
1004 => -1289244298
1005 => -1572996668
1006 => -2069479746
1007 => -1819131606
1008 => -1007163964
1009 => -1185394870
1010 => -1471365065
1011 => 364354366
1012 => -1478084253
1013 => 405281367
1014 => -11170062
1015 => 156767750
1016 => 1288924796
1017 => 1796884876
1018 => -1947073702
1019 => -1999614238
1020 => -231292809
1021 => 966621566
1022 => -606766557
1023 => -1138727825
1024 => -749544262
1025 => 2004771271
1026 => 686734186
1027 => 923274744
1028 => -1672035149
1029 => -1642064950
1030 => 1363389551
1031 => -559500928
1032 => 1656196991
1033 => 1655354425
1034 => -1027156689
1035 => 1952644328
1036 => 1217870217
1037 => 242274100
1038 => 201816080
1039 => 2127464758
1040 => 446043650
1041 => -319728455
1042 => 204701002
1043 => -571265398
1044 => -1422217131
1045 => -391208397
1046 => -1822628371
1047 => -1499755350
1048 => -1422137641
1049 => 1621693134
1051 => -1428728134
1052 => -147587573
1053 => 681719500
1054 => 1172011190
1055 => -1834344882
1056 => 1157634586
1057 => 1902133676
1058 => -1967780161
1059 => -1618025531
1060 => -810220453
1061 => 1582854921
1062 => -410004643
1063 => 1159917159
1064 => -1377804984
1065 => -738843914
1066 => -1578756103
1067 => -464090986
1068 => 1711504679
1069 => 545330655
1070 => 379462570
1071 => 514511099
1072 => -1813251176
1073 => 1424958266
1074 => -825255131
1075 => 539054595
1076 => -1764192010
1077 => -1243277769
1078 => 2017874281
1079 => -1972353607
1080 => 1879761467
1081 => 1638986560
1082 => -1832287507
1083 => -492411882
1084 => 658940812
1085 => -1044199400
1086 => 1586504918
1087 => -125492611
1088 => -1562883174
1089 => -1013778441
1090 => 1560228607
1091 => -550265689
1092 => 524767105
1093 => -713387661
1094 => 1425927738
1095 => 942653932
1096 => 1233220698
1097 => 1313602368
1098 => -140318584
1099 => 1199179892
1 => 688298322
2 => -1709546982
1000 => 1701392078
1001 => -1630848421
1002 => -886500935
1003 => -196324972
1004 => -436037402
1005 => -520341784
1006 => -1485224804
1007 => -311036236
1008 => -1503442439
1009 => -110945695
1010 => -82825175
1011 => 46859773
1012 => -1199223018
1013 => -1190555925
1014 => 326384434
1015 => 1486817960
1016 => -1411425597
1017 => -508426854
1018 => 820019294
1019 => 710762995
1020 => -760867032
1021 => -709611146
1022 => 732190215
1023 => 236336673
1024 => 740596257
1025 => 1135321785
1026 => 2067474156
1027 => -1395683607
1028 => -240528699
1029 => 928616892
1030 => 1712486685
1031 => 1994118287
1032 => 1333321243
1033 => 194124284
1034 => 615083294
1035 => 628086450
1036 => 498957825
1037 => 1359697121
1038 => 1888433963
1039 => 941623020
1040 => -1925663292
1041 => -771540264
1042 => -1058341359
1043 => 182127597
1044 => 646955927
1045 => -1424621714
1046 => 623062612
1047 => -1986955586
1048 => -1268826980
1049 => -456776220
1051 => -1112555329
1052 => -1532134052
1053 => 1960404034
1054 => 1573325453
1055 => -316619303
1056 => 699712177
1057 => 863274966
1058 => 1728276475
1059 => -246695889
1060 => 1919485436
1061 => 111273464
1062 => 125435213
1063 => 155132602
1064 => -171674076
1065 => 655046914
1066 => 1577399562
1067 => 1028818150
1068 => 447058239
1069 => -1057920269
1070 => -1326215323
1071 => -198688588
1072 => 1523643051
1073 => 231373233
1074 => 1121759962
1075 => 1449439846
1076 => -1615270753
1077 => -1509293864
1078 => 2116903943
1079 => 672822173
1080 => -969573911
1081 => 1589904755
1082 => 1148782015
1083 => 663503316
1084 => 933352745
1085 => 577717039
1086 => 402172048
1087 => 1812250453
1088 => 667300501
1089 => -1838825777
1090 => -856474776
1091 => 420696035
1092 => 2131427774
1093 => -435303548
1094 => -160883878
1095 => 1969629634
1096 => -555794155
1097 => -835119691
1098 => -1460907909
1099 => -1146924084
KeepTop(10):
1 => -200078348
2 => -29799264
1000 => 1630721656
1001 => 959306175
1002 => 1527421791
1003 => 1259692483
1004 => -1289244298
1005 => -1572996668
1006 => -2069479746
1007 => -1819131606
1 => 688298322
2 => -1709546982
1000 => 1701392078
1001 => -1630848421
1002 => -886500935
1003 => -196324972
1004 => -436037402
1005 => -520341784
1006 => -1485224804
1007 => -311036236
KeepBottom(8):
1000 => 1630721656
1001 => 959306175
1002 => 1527421791
1003 => 1259692483
1004 => -1289244298
1005 => -1572996668
1006 => -2069479746
1007 => -1819131606
1000 => 1701392078
1001 => -1630848421
1002 => -886500935
1003 => -196324972
1004 => -436037402
1005 => -520341784
1006 => -1485224804
1007 => -311036236
RemoveBottom(2):
1000 => 1630721656
1001 => 959306175
1002 => 1527421791
1003 => 1259692483
1004 => -1289244298
1005 => -1572996668
1000 => 1701392078
1001 => -1630848421
1002 => -886500935
1003 => -196324972
1004 => -436037402
1005 => -520341784
RemoveTop(2):
1002 => 1527421791
1003 => 1259692483
1004 => -1289244298
1005 => -1572996668
1002 => -886500935
1003 => -196324972
1004 => -436037402
1005 => -520341784
RemoveList({1003, 1004}):
1002 => 1527421791
1005 => -1572996668
1002 => -886500935
1005 => -520341784
KeepList({1003, 1004, 1005}):
1005 => -1572996668
1005 => -520341784
AddList({1005, 4000, 4001, 4002}):
1005 => 1005
4000 => 8000

View File

@ -10,6 +10,7 @@ struct SQClassMember {
val = o.val;
attrs = o.attrs;
}
SQClassMember& operator=(SQClassMember &o) = delete;
SQObjectPtr val;
SQObjectPtr attrs;
};

View File

@ -14,6 +14,7 @@
#include "../core/random_func.hpp"
#include "../script/squirrel_class.hpp"
#include "../script/api/script_object.hpp"
#include "ai_info.hpp"
#include "ai_scanner.hpp"
@ -77,12 +78,7 @@ AIInfo *AIScannerInfo::SelectRandomAI() const
}
/* Find a random AI */
uint pos;
if (_networking) {
pos = InteractiveRandomRange(num_random_ais);
} else {
pos = RandomRange(num_random_ais);
}
uint pos = ScriptObject::GetRandomizer(OWNER_NONE).Next(num_random_ais);
/* Find the Nth item from the array */
ScriptInfoList::const_iterator it = this->info_single_list.begin();

View File

@ -1068,6 +1068,7 @@ static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, nullptr);
if (callback == CALLBACK_FAILED || callback == 0x400) return y;
const GRFFile *grffile = Engine::Get(engine)->GetGRF();
assert(grffile != nullptr);
if (callback > 0x400) {
ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback);
return y;

View File

@ -596,7 +596,7 @@ Company *DoStartupNewCompany(DoStartupNewCompanyFlag flags, CompanyID company)
if (_company_manager_face != 0 && !is_ai && !_networking) {
c->face = _company_manager_face;
} else {
RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false);
RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, _random);
}
SetDefaultCompanySettings(c->index);

View File

@ -1751,7 +1751,7 @@ public:
/* Randomize face button */
case WID_SCMF_RANDOM_NEW_FACE:
RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced, _interactive_random);
this->UpdateData();
this->SetDirty();
break;

View File

@ -199,15 +199,13 @@ static inline void ScaleAllCompanyManagerFaceBits(CompanyManagerFace &cmf)
* @param cmf the company manager's face to write the bits to
* @param ge the gender and ethnicity of the old company manager's face
* @param adv if it for the advanced company manager's face window
* @param interactive is the call from within the user interface?
* @param randomizer the source of random to use for creating the manager face
*
* @pre scale 'ge' to a valid gender/ethnicity combination
*/
static inline void RandomCompanyManagerFaceBits(CompanyManagerFace &cmf, GenderEthnicity ge, bool adv, bool interactive = true)
static inline void RandomCompanyManagerFaceBits(CompanyManagerFace &cmf, GenderEthnicity ge, bool adv, Randomizer &randomizer)
{
/* This method is called from a command when not interactive and
* then we must use Random to get the same result on all clients. */
cmf = interactive ? InteractiveRandom() : Random(); // random all company manager's face bits
cmf = randomizer.Next(); // random all company manager's face bits
/* scale ge: 0 == GE_WM, 1 == GE_WF, 2 == GE_BM, 3 == GE_BF (and maybe in future: ...) */
ge = (GenderEthnicity)((uint)ge % GE_END);

View File

@ -313,7 +313,11 @@ DEF_CONSOLE_CMD(ConZoomToLevel)
case 2: {
uint32 level;
if (GetArgumentInteger(&level, argv[1])) {
if (level < ZOOM_LVL_MIN) {
/* In case ZOOM_LVL_MIN is more than 0, the next if statement needs to be amended.
* A simple check for less than ZOOM_LVL_MIN does not work here because we are
* reading an unsigned integer from the console, so just check for a '-' char. */
static_assert(ZOOM_LVL_MIN == 0);
if (argv[1][0] == '-') {
IConsolePrintF(CC_ERROR, "Zoom-in levels below %u are not supported.", ZOOM_LVL_MIN);
} else if (level < _settings_client.gui.zoom_min) {
IConsolePrintF(CC_ERROR, "Current client settings do not allow zooming in below level %u.", _settings_client.gui.zoom_min);
@ -322,7 +326,7 @@ DEF_CONSOLE_CMD(ConZoomToLevel)
} else if (level > _settings_client.gui.zoom_max) {
IConsolePrintF(CC_ERROR, "Current client settings do not allow zooming out beyond level %u.", _settings_client.gui.zoom_max);
} else {
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
Viewport *vp = w->viewport;
while (vp->zoom > level) DoZoomInOutWindow(ZOOM_IN, w);
while (vp->zoom < level) DoZoomInOutWindow(ZOOM_OUT, w);
@ -529,7 +533,7 @@ DEF_CONSOLE_CMD(ConRemove)
_console_file_list.ValidateFileList();
const FiosItem *item = _console_file_list.FindItem(file);
if (item != nullptr) {
if (!FiosDelete(item->name)) {
if (unlink(item->name) != 0) {
IConsolePrintF(CC_ERROR, "%s: Failed to delete file", file);
}
} else {
@ -1031,6 +1035,7 @@ DEF_CONSOLE_CMD(ConResetCompany)
return false;
}
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
assert(ci != nullptr);
if (ci->client_playas == index) {
IConsoleError("Cannot remove company: the server is connected to that company.");
return true;
@ -2240,18 +2245,15 @@ DEF_CONSOLE_CMD(ConFont)
bool aa = setting->aa;
byte arg_index = 2;
if (argc > arg_index) {
/* We may encounter "aa" or "noaa" but it must be the last argument. */
if (strcasecmp(argv[arg_index], "aa") == 0 || strcasecmp(argv[arg_index], "noaa") == 0) {
aa = strncasecmp(argv[arg_index++], "no", 2) != 0;
if (argc > arg_index) return false;
} else {
/* For <name> we want a string. */
uint v;
if (!GetArgumentInteger(&v, argv[arg_index])) {
font = argv[arg_index++];
}
/* We may encounter "aa" or "noaa" but it must be the last argument. */
if (strcasecmp(argv[arg_index], "aa") == 0 || strcasecmp(argv[arg_index], "noaa") == 0) {
aa = strncasecmp(argv[arg_index++], "no", 2) != 0;
if (argc > arg_index) return false;
} else {
/* For <name> we want a string. */
uint v;
if (!GetArgumentInteger(&v, argv[arg_index])) {
font = argv[arg_index++];
}
}
@ -2282,7 +2284,7 @@ DEF_CONSOLE_CMD(ConFont)
InitFontCache(fs == FS_MONO);
fc = FontCache::Get(fs);
}
IConsolePrintF(CC_DEFAULT, "%s: \"%s\" %d %s [\"%s\" %d %s]", FontSizeToName(fs), fc->GetFontName(), fc->GetFontSize(), GetFontAAState(fs) ? "true" : "false", setting->font.c_str(), setting->size, setting->aa ? "true" : "false");
IConsolePrintF(CC_DEFAULT, "%s: \"%s\" %d %s [\"%s\" %d %s]", FontSizeToName(fs), fc->GetFontName(), fc->GetFontSize(), GetFontAAState(fs) ? "aa" : "noaa", setting->font.c_str(), setting->size, setting->aa ? "aa" : "noaa");
}
return true;

View File

@ -172,7 +172,10 @@ public:
inline constexpr bool operator < (const int other) const { return !(*this >= other); }
inline constexpr bool operator <= (const int other) const { return !(*this > other); }
inline constexpr operator int64 () const { return this->m_value; }
inline constexpr operator T () const { return this->m_value; }
static inline constexpr OverflowSafeInt<T> max() { return T_MAX; }
static inline constexpr OverflowSafeInt<T> min() { return T_MIN; }
};

View File

@ -239,7 +239,7 @@ public:
int scr_bot = GetMainViewBottom() - 20;
Point pt = RemapCoords(this->position.x, this->position.y, GetSlopePixelZOutsideMap(this->position.x, this->position.y));
const Viewport *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
const Viewport *vp = GetMainWindow()->viewport;
if (this->face == INVALID_COMPANY) {
/* move x pos to opposite corner */
pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left;

View File

@ -225,6 +225,7 @@ public:
GameStrings *LoadTranslations()
{
const GameInfo *info = Game::GetInfo();
assert(info != nullptr);
std::string basename(info->GetMainScript());
auto e = basename.rfind(PATHSEPCHAR);
if (e == std::string::npos) return nullptr;

View File

@ -104,6 +104,7 @@ static void _GenerateWorld()
SetGeneratingWorldProgress(GWP_MAP_INIT, 2);
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
ScriptObject::InitializeRandomizers();
BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
@ -337,9 +338,7 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
ShowGenerateWorldProgress();
/* Centre the view on the map */
if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) {
ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true);
}
ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true);
_GenerateWorld();
}

View File

@ -552,8 +552,6 @@ std::unique_ptr<const ParagraphLayouter::Line> FallbackParagraphLayout::NextLine
next_run = this->buffer_begin + iter->first;
begin = this->buffer;
last_space = nullptr;
}
if (IsWhitespace(c)) last_space = this->buffer;
@ -591,7 +589,7 @@ std::unique_ptr<const ParagraphLayouter::Line> FallbackParagraphLayout::NextLine
this->buffer++;
}
if (l->size() == 0 || last_char - begin != 0) {
if (l->size() == 0 || last_char - begin > 0) {
int w = l->GetWidth();
l->emplace_back(iter->second, begin, last_char - begin, w);
}

View File

@ -222,7 +222,7 @@ struct SelectGameWindow : public Window {
}
IntroGameViewportCommand &vc = intro_viewport_commands[this->cur_viewport_command_index];
Window *mw = FindWindowByClass(WC_MAIN_WINDOW);
Window *mw = GetMainWindow();
Viewport *vp = mw->viewport;
/* Early exit if the current command hasn't elapsed and isn't animated. */

View File

@ -2076,6 +2076,7 @@ STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Vise tav
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Vis innstillinger
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Vis NewGRF-instillinger
STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Se etter nytt og oppdatert innhold for nedlasting
STR_INTRO_TOOLTIP_AI_SETTINGS :{BLACK}Vis KI innstillinger
STR_INTRO_TOOLTIP_QUIT :{BLACK}Avslutt 'OpenTTD'
STR_INTRO_BASESET :{BLACK}Det valgte innebygde grafikksettet mangler {NUM} sprite{P "" r}. Se etter oppdateringer for settet.

View File

@ -721,7 +721,7 @@ LinkGraphLegendWindow::LinkGraphLegendWindow(WindowDesc *desc, int window_number
{
this->InitNested(window_number);
this->InvalidateData(0);
this->SetOverlay(FindWindowById(WC_MAIN_WINDOW, 0)->viewport->overlay);
this->SetOverlay(GetMainWindow()->viewport->overlay);
}
/**

View File

@ -182,7 +182,7 @@ void FixTitleGameZoom(int zoom_adjust)
{
if (_game_mode != GM_MENU) return;
Viewport *vp = FindWindowByClass(WC_MAIN_WINDOW)->viewport;
Viewport *vp = GetMainWindow()->viewport;
/* Adjust the zoom in/out.
* Can't simply add, since operator+ is not defined on the ZoomLevel type. */

View File

@ -67,8 +67,10 @@ CommandCost CmdIncreaseLoan(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
break;
}
/* Overflow protection */
if (c->money + c->current_loan + loan < c->money) return CMD_ERROR;
/* In case adding the loan triggers the overflow protection of Money,
* we would essentially be losing money as taking and repaying the loan
* immediately would not get us back to the same bank balance anymore. */
if (c->money > Money::max() - loan) return CMD_ERROR;
if (flags & DC_EXEC) {
c->money += loan;

View File

@ -1340,7 +1340,7 @@ static WindowDesc _query_desc(
*/
void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback)
{
if (parent == nullptr) parent = FindWindowById(WC_MAIN_WINDOW, 0);
if (parent == nullptr) parent = GetMainWindow();
for (const Window *w : Window::IterateFromBack()) {
if (w->window_class != WC_CONFIRM_POPUP_QUERY) continue;

View File

@ -358,14 +358,14 @@ void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info, const GameInfo
}
case 4: {
GRFConfig **dst = &info->grfconfig;
uint i;
/* Ensure that the maximum number of NewGRFs and the field in the network
* protocol are matched to eachother. If that is not the case anymore a
* check must be added to ensure the received data is still valid. */
static_assert(std::numeric_limits<uint8>::max() == NETWORK_MAX_GRF_COUNT);
uint num_grfs = p->Recv_uint8();
/* Broken/bad data. It cannot have that many NewGRFs. */
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
for (i = 0; i < num_grfs; i++) {
GRFConfig **dst = &info->grfconfig;
for (uint i = 0; i < num_grfs; i++) {
NamedGRFIdentifier grf;
switch (newgrf_serialisation) {
case NST_GRFID_MD5:

View File

@ -649,6 +649,7 @@ void NetworkClose(bool close_admins)
delete[] _network_company_states;
_network_company_states = nullptr;
_network_company_server_id.clear();
_network_company_passworded = 0;
InitializeNetworkPools(close_admins);

View File

@ -2531,6 +2531,6 @@ void ShowNetworkAskRelay(const std::string &server_connection_string, const std:
{
DeleteWindowByClass(WC_NETWORK_ASK_RELAY);
Window *parent = FindWindowById(WC_MAIN_WINDOW, 0);
Window *parent = GetMainWindow();
new NetworkAskRelayWindow(&_network_ask_relay_desc, parent, server_connection_string, relay_connection_string, token);
}

View File

@ -1744,6 +1744,7 @@ static void NetworkAutoCleanCompanies()
if (!_network_dedicated) {
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
assert(ci != nullptr);
if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
}
@ -2135,6 +2136,7 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
assert(ci != nullptr);
/* No need to waste network resources if the client is in the company already! */
if (ci->client_playas == company_id) return;

View File

@ -4306,7 +4306,6 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, const G
/* Swap classid because we read it in BE. */
uint32 classid = buf->ReadDWord();
(*ospec)->cls_id = ObjectClass::Allocate(BSWAP32(classid));
(*ospec)->enabled = true;
break;
}
@ -10857,7 +10856,7 @@ static void FinaliseObjectsArray()
ObjectSpec **&objectspec = file->objectspec;
if (objectspec != nullptr) {
for (int i = 0; i < NUM_OBJECTS_PER_GRF; i++) {
if (objectspec[i] != nullptr && objectspec[i]->grf_prop.grffile != nullptr && objectspec[i]->enabled) {
if (objectspec[i] != nullptr && objectspec[i]->grf_prop.grffile != nullptr && objectspec[i]->IsEnabled()) {
_object_mngr.SetEntitySpec(objectspec[i]);
}
}

View File

@ -658,6 +658,7 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
{
const Vehicle *w = v->Next();
assert(w != nullptr);
uint16 altitude = ClampToU16(v->z_pos - w->z_pos); // Aircraft height - shadow height
byte airporttype = ATP_TTDP_LARGE;

View File

@ -1468,6 +1468,9 @@ private:
this->avails.push_back(c);
} else {
const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID);
/* Never triggers; FindGRFConfig returns either c, or a newer version of c. */
assert(best != nullptr);
/*
* If the best version is 0, then all NewGRF with this GRF ID
* have version 0, so for backward compatibility reasons we

View File

@ -60,7 +60,7 @@ ObjectSpec _object_specs[NUM_OBJECTS];
*/
bool ObjectSpec::IsEverAvailable() const
{
return this->enabled && HasBit(this->climate, _settings_game.game_creation.landscape) &&
return this->IsEnabled() && HasBit(this->climate, _settings_game.game_creation.landscape) &&
(this->flags & ((_game_mode != GM_EDITOR && !_generating_world) ? OBJECT_FLAG_ONLY_IN_SCENEDIT : OBJECT_FLAG_ONLY_IN_GAME)) == 0;
}

View File

@ -21,7 +21,7 @@
#include "newgrf_commons.h"
/** Various object behaviours. */
enum ObjectFlags {
enum ObjectFlags : uint16 {
OBJECT_FLAG_NONE = 0, ///< Just nothing.
OBJECT_FLAG_ONLY_IN_SCENEDIT = 1 << 0, ///< Object can only be constructed in the scenario editor.
OBJECT_FLAG_CANNOT_REMOVE = 1 << 1, ///< Object can not be removed.
@ -62,7 +62,7 @@ static const uint8 OBJECT_SIZE_1X1 = 0x11; ///< The value of a NewGRF's size pro
void ResetObjects();
/** Class IDs for objects. */
enum ObjectClassID {
enum ObjectClassID : uint16 {
OBJECT_CLASS_BEGIN = 0, ///< The lowest valid value
OBJECT_CLASS_MAX = 0xFFFF, ///< Maximum number of classes.
INVALID_OBJECT_CLASS = 0xFFFF, ///< Class for the less fortunate.
@ -91,6 +91,7 @@ enum ObjectViewportMapType {
struct ObjectSpec {
/* 2 because of the "normal" and "buy" sprite stacks. */
GRFFilePropsBase<2> grf_prop; ///< Properties related the the grf file
AnimationInfo animation; ///< Information about the animation.
ObjectClassID cls_id; ///< The class to which this spec belongs.
StringID name; ///< The name for this object.
@ -103,15 +104,19 @@ struct ObjectSpec {
ObjectFlags flags; ///< Flags/settings related to the object.
ObjectCtrlFlags ctrl_flags; ///< Extra control flags.
uint8 edge_foundation[4]; ///< Edge foundation flags
AnimationInfo animation; ///< Information about the animation.
uint16 callback_mask; ///< Bitmask of requested/allowed callbacks.
uint8 height; ///< The height of this structure, in heightlevels; max MAX_TILE_HEIGHT.
uint8 views; ///< The number of views.
uint8 generate_amount; ///< Number of objects which are attempted to be generated per 256^2 map during world generation.
bool enabled; ///< Is this spec enabled?
ObjectViewportMapType vport_map_type; ///< Viewport map type
uint16 vport_map_subtype; ///< Viewport map subtype
/**
* Test if this object is enabled.
* @return True iif this object is enabled.
*/
bool IsEnabled() const { return this->views > 0; }
/**
* Get the cost for building a structure of this type.
* @return The cost for building.

View File

@ -578,7 +578,7 @@ static void DrawTile_Object(TileInfo *ti, DrawTileProcParams params)
int building_z_offset = 0;
/* Fall back for when the object doesn't exist anymore. */
if (!spec->enabled) {
if (!spec->IsEnabled()) {
type = OBJECT_TRANSMITTER;
} else if ((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) {
if (spec->ctrl_flags & OBJECT_CTRL_FLAG_EDGE_FOUNDATION) {
@ -1222,7 +1222,7 @@ static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int
pre_success_checks();
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
}
} else if (spec->enabled) {
} else if (spec->IsEnabled()) {
/* allow autoslope */
pre_success_checks();
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);

View File

@ -1778,6 +1778,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (sel_ord >= v->GetNumOrders()) return CMD_ERROR;
Order *order = v->GetOrder(sel_ord);
assert(order != nullptr);
switch (order->GetType()) {
case OT_GOTO_STATION:
if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD && mof != MOF_CARGO_TYPE_UNLOAD && mof != MOF_CARGO_TYPE_LOAD && mof != MOF_RV_TRAVEL_DIR) return CMD_ERROR;

View File

@ -233,46 +233,21 @@ err1:
}
#endif /* WITH_FREETYPE */
class FontList {
protected:
wchar_t **fonts;
uint items;
uint capacity;
public:
FontList() : fonts(nullptr), items(0), capacity(0) { };
~FontList() {
if (this->fonts == nullptr) return;
for (uint i = 0; i < this->items; i++) {
free(this->fonts[i]);
}
free(this->fonts);
}
bool Add(const wchar_t *font) {
for (uint i = 0; i < this->items; i++) {
if (wcscmp(this->fonts[i], font) == 0) return false;
}
if (this->items == this->capacity) {
this->capacity += 10;
this->fonts = ReallocT(this->fonts, this->capacity);
}
this->fonts[this->items++] = wcsdup(font);
return true;
}
};
struct EFCParam {
FontCacheSettings *settings;
LOCALESIGNATURE locale;
MissingGlyphSearcher *callback;
FontList fonts;
std::vector<std::wstring> fonts;
bool Add(const std::wstring_view &font) {
for (const auto &entry : this->fonts) {
if (font.compare(entry) == 0) return false;
}
this->fonts.emplace_back(font);
return true;
}
};
static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXTMETRICEX *metric, DWORD type, LPARAM lParam)
@ -280,7 +255,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
EFCParam *info = (EFCParam *)lParam;
/* Skip duplicates */
if (!info->fonts.Add((const wchar_t *)logfont->elfFullName)) return 1;
if (!info->Add(logfont->elfFullName)) return 1;
/* Only use TrueType fonts */
if (!(type & TRUETYPE_FONTTYPE)) return 1;
/* Don't use SYMBOL fonts */
@ -463,22 +438,9 @@ void Win32FontCache::ClearFontCache()
GLYPHMETRICS gm;
MAT2 mat = { {0, 1}, {0, 0}, {0, 0}, {0, 1} };
/* Make a guess for the needed memory size. */
DWORD size = this->glyph_size.cy * Align(aa ? this->glyph_size.cx : std::max(this->glyph_size.cx / 8l, 1l), 4); // Bitmap data is DWORD-aligned rows.
byte *bmp = AllocaM(byte, size);
size = GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat);
if (size == GDI_ERROR) {
/* No dice with the guess. First query size of needed glyph memory, then allocate the
* memory and query again. This dance is necessary as some glyphs will only render with
* the exact matching size; e.g. the space glyph has no pixels and must be requested
* with size == 0, anything else fails. Unfortunately, a failed call doesn't return any
* info about the size and thus the triple GetGlyphOutline()-call. */
size = GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, 0, nullptr, &mat);
if (size == GDI_ERROR) usererror("Unable to render font glyph");
bmp = AllocaM(byte, size);
GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat);
}
/* Call GetGlyphOutline with zero size initially to get required memory size. */
DWORD size = GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, 0, nullptr, &mat);
if (size == GDI_ERROR) usererror("Unable to render font glyph");
/* Add 1 scaled pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel. */
uint shadow = (this->fs == FS_NORMAL) ? ScaleGUITrad(1) : 0;
@ -488,6 +450,10 @@ void Win32FontCache::ClearFontCache()
/* Limit glyph size to prevent overflows later on. */
if (width > MAX_GLYPH_DIM || height > MAX_GLYPH_DIM) usererror("Font glyph is too large");
/* Call GetGlyphOutline again with size to actually render the glyph. */
byte *bmp = AllocaM(byte, size);
GetGlyphOutline(this->dc, key, GGO_GLYPH_INDEX | (aa ? GGO_GRAY8_BITMAP : GGO_BITMAP), &gm, size, bmp, &mat);
/* GDI has rendered the glyph, now we allocate a sprite and copy the image into it. */
SpriteLoader::Sprite sprite;
sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);

View File

@ -266,6 +266,8 @@ static void InitializeWindowsAndCaches()
UpdateAllVirtCoords();
ResetViewportAfterLoadGame();
ScriptObject::InitializeRandomizers();
for (Company *c : Company::Iterate()) {
/* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it
* accordingly if it is not the case. No need to set it on companies that are not been used already,

View File

@ -36,18 +36,16 @@ ZoomLevel _saved_scrollpos_zoom;
void SaveViewportBeforeSaveGame()
{
const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
const Window *w = GetMainWindow();
if (w != nullptr) {
_saved_scrollpos_x = w->viewport->scrollpos_x;
_saved_scrollpos_y = w->viewport->scrollpos_y;
_saved_scrollpos_zoom = w->viewport->zoom;
}
_saved_scrollpos_x = w->viewport->scrollpos_x;
_saved_scrollpos_y = w->viewport->scrollpos_y;
_saved_scrollpos_zoom = w->viewport->zoom;
}
void ResetViewportAfterLoadGame()
{
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
w->viewport->scrollpos_x = _saved_scrollpos_x;
w->viewport->scrollpos_y = _saved_scrollpos_y;

View File

@ -497,14 +497,16 @@ void AfterLoadVehicles(bool part_of_load)
v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq);
v->UpdateSpriteSeqBound();
/* The plane's shadow will have the same image as the plane, but no colour */
/* The aircraft's shadow will have the same image as the aircraft, but no colour */
Vehicle *shadow = v->Next();
if (shadow == nullptr) SlErrorCorrupt("Missing shadow for aircraft");
shadow->sprite_seq.CopyWithoutPalette(v->sprite_seq);
shadow->sprite_seq_bounds = v->sprite_seq_bounds;
/* In the case of a helicopter we will update the rotor sprites */
if (v->subtype == AIR_HELICOPTER) {
Vehicle *rotor = shadow->Next();
if (rotor == nullptr) SlErrorCorrupt("Missing rotor for helicopter");
GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_seq);
rotor->UpdateSpriteSeqBound();
}

View File

@ -759,7 +759,7 @@ void SetupScreenshotViewport(ScreenshotType t, Viewport *vp, uint32 width, uint3
case SC_CRASHLOG: {
assert(width == 0 && height == 0);
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
vp->virtual_left = w->viewport->virtual_left;
vp->virtual_top = w->viewport->virtual_top;
vp->virtual_width = w->viewport->virtual_width;
@ -810,7 +810,7 @@ void SetupScreenshotViewport(ScreenshotType t, Viewport *vp, uint32 width, uint3
default: {
vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT;
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
vp->virtual_left = w->viewport->virtual_left;
vp->virtual_top = w->viewport->virtual_top;

View File

@ -10,17 +10,12 @@
#include "../../stdafx.h"
#include "script_base.hpp"
#include "script_error.hpp"
#include "../../network/network.h"
#include "../../core/random_func.hpp"
#include "../../safeguards.h"
/* static */ uint32 ScriptBase::Rand()
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandom();
return ::Random();
return ScriptObject::GetRandomizer().Next();
}
/* static */ uint32 ScriptBase::RandItem(int unused_param)
@ -30,10 +25,7 @@
/* static */ uint ScriptBase::RandRange(uint max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client. */
if (_networking) return ::InteractiveRandomRange(max);
return ::RandomRange(max);
return ScriptObject::GetRandomizer().Next(max);
}
/* static */ uint32 ScriptBase::RandRangeItem(int unused_param, uint max)

View File

@ -18,9 +18,6 @@
*
* @note The random functions are not called Random and RandomRange, because
* RANDOM_DEBUG does some tricky stuff, which messes with those names.
* @note In MP we cannot use Random because that will cause desyncs (scripts are
* ran on the server only, not on all clients). This means that
* we use InteractiveRandom in MP. Rand() takes care of this for you.
*/
class ScriptBase : public ScriptObject {
public:

View File

@ -93,9 +93,10 @@
EnforcePrecondition(false, gender == GENDER_MALE || gender == GENDER_FEMALE);
EnforcePrecondition(false, GetPresidentGender(ScriptCompany::COMPANY_SELF) != gender);
Randomizer &randomizer = ScriptObject::GetRandomizer();
CompanyManagerFace cmf;
GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (::InteractiveRandom() & (1 << ETHNICITY_BLACK)));
RandomCompanyManagerFaceBits(cmf, ge, false);
GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (randomizer.Next() & (1 << ETHNICITY_BLACK)));
RandomCompanyManagerFaceBits(cmf, ge, false, randomizer);
return ScriptObject::DoCommand(0, 0, cmf, CMD_SET_COMPANY_MANAGER_FACE);
}

View File

@ -26,6 +26,7 @@
if (!IsValid(setting)) return -1;
const SettingDesc *sd = GetSettingFromName(setting);
assert(sd != nullptr);
return sd->AsIntSetting()->Read(&_settings_game);
}
@ -34,6 +35,7 @@
if (!IsValid(setting)) return false;
const SettingDesc *sd = GetSettingFromName(setting);
assert(sd != nullptr);
if ((sd->flags & SF_NO_NETWORK_SYNC) != 0) return false;

View File

@ -9,6 +9,7 @@
#include "../../stdafx.h"
#include "script_industrytype.hpp"
#include "script_base.hpp"
#include "script_map.hpp"
#include "script_error.hpp"
#include "../../strings_func.h"
@ -120,8 +121,8 @@
EnforcePrecondition(false, CanBuildIndustry(industry_type));
EnforcePrecondition(false, ScriptMap::IsValidTile(tile));
uint32 seed = ::InteractiveRandom();
uint32 layout_index = ::InteractiveRandomRange((uint32)::GetIndustrySpec(industry_type)->layouts.size());
uint32 seed = ScriptBase::Rand();
uint32 layout_index = ScriptBase::RandRange((uint32)::GetIndustrySpec(industry_type)->layouts.size());
return ScriptObject::DoCommand(tile, (1 << 16) | (layout_index << 8) | industry_type, seed, CMD_BUILD_INDUSTRY);
}
@ -129,7 +130,7 @@
{
EnforcePrecondition(false, CanProspectIndustry(industry_type));
uint32 seed = ::InteractiveRandom();
uint32 seed = ScriptBase::Rand();
return ScriptObject::DoCommand(0, industry_type, seed, CMD_BUILD_INDUSTRY);
}

View File

@ -395,3 +395,19 @@ ScriptObject::ActiveInstance::~ActiveInstance()
NOT_REACHED();
}
/* static */ Randomizer ScriptObject::random_states[OWNER_END];
Randomizer &ScriptObject::GetRandomizer(Owner owner)
{
return ScriptObject::random_states[owner];
}
void ScriptObject::InitializeRandomizers()
{
Randomizer random = _random;
for (Owner owner = OWNER_BEGIN; owner < OWNER_END; owner++) {
ScriptObject::GetRandomizer(owner).SetSeed(random.Next());
}
}

View File

@ -13,6 +13,7 @@
#include "../../misc/countedptr.hpp"
#include "../../road_type.h"
#include "../../rail_type.h"
#include "../../core/random_func.hpp"
#include "script_types.hpp"
#include "../script_suspend.hpp"
@ -67,6 +68,18 @@ public:
*/
static class ScriptInstance *GetActiveInstance();
/**
* Get a reference of the randomizer that brings this script random values.
* @param owner The owner/script to get the randomizer for. This defaults to ScriptObject::GetRootCompany()
*/
static Randomizer &GetRandomizer(Owner owner = ScriptObject::GetRootCompany());
/**
* Initialize/reset the script random states. The state of the scripts are
* based on the current _random seed, but _random does not get changed.
*/
static void InitializeRandomizers();
protected:
/**
* Executes a raw DoCommand for the script.
@ -315,6 +328,8 @@ private:
* @param story_page_id The new StoryPageID.
*/
static void SetNewStoryPageElementID(StoryPageElementID story_page_element_id);
static Randomizer random_states[OWNER_END]; ///< Random states for each of the scripts (game script uses OWNER_DEITY)
};
#endif /* SCRIPT_OBJECT_HPP */

View File

@ -67,6 +67,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, ScriptOrder::OrderPositio
if (order_position == ScriptOrder::ORDER_INVALID) return nullptr;
}
const Order *order = v->GetFirstOrder();
assert(order != nullptr);
while (order->GetType() == OT_IMPLICIT) order = order->next;
while (order_position > 0) {
order_position = (ScriptOrder::OrderPosition)(order_position - 1);
@ -91,6 +92,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
int res = (int)order_position;
const Order *order = v->orders->GetFirstOrder();
assert(order != nullptr);
for (; order->GetType() == OT_IMPLICIT; order = order->next) res++;
while (order_position > 0) {
order_position = (ScriptOrder::OrderPosition)(order_position - 1);
@ -136,6 +138,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position));
assert(order != nullptr);
return order->GetType() == OT_CONDITIONAL;
}
@ -145,6 +148,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (!IsValidVehicleOrder(vehicle_id, order_position)) return false;
const Order *order = ::ResolveOrder(vehicle_id, order_position);
assert(order != nullptr);
return order->GetType() == OT_DUMMY;
}
@ -176,6 +180,7 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
if (order_position == ORDER_CURRENT) {
int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_real_order_index;
const Order *order = ::Vehicle::Get(vehicle_id)->GetFirstOrder();
assert(order != nullptr);
int num_implicit_orders = 0;
for (int i = 0; i < cur_order_pos; i++) {
if (order->GetType() == OT_IMPLICIT) num_implicit_orders++;

View File

@ -303,7 +303,7 @@
EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
}
uint32 townnameparts;
if (!GenerateTownName(&townnameparts)) {
if (!GenerateTownName(ScriptObject::GetRandomizer(), &townnameparts)) {
ScriptController::DecreaseOps(50000);
ScriptObject::SetLastError(ScriptError::ERR_NAME_IS_NOT_UNIQUE);
return false;

View File

@ -46,6 +46,7 @@
if (colour != TC_INVALID && (::TextColour)colour >= ::TC_END) return;
Window *w = FindWindowById((::WindowClass)window, number);
assert(w != nullptr);
if (widget == WIDGET_ALL) {
if (colour != TC_INVALID) return;

View File

@ -11,6 +11,7 @@
#include "../settings_type.h"
#include "../core/random_func.hpp"
#include "script_info.hpp"
#include "api/script_object.hpp"
#include "../textfile_gui.h"
#include "../string_func.h"
@ -35,7 +36,7 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match,
* for the Script that have the random flag to a random value. */
for (const auto &item : *this->info->GetConfigList()) {
if (item.flags & SCRIPTCONFIG_RANDOM) {
this->SetSetting(item.name, InteractiveRandomRange(item.max_value + 1 - item.min_value) + item.min_value);
this->SetSetting(item.name, ScriptObject::GetRandomizer(OWNER_NONE).Next(item.max_value + 1 - item.min_value) + item.min_value);
}
}
@ -157,7 +158,7 @@ void ScriptConfig::AddRandomDeviation()
{
for (const auto &item : *this->GetConfigList()) {
if (item.random_deviation != 0) {
this->SetSetting(item.name, InteractiveRandomRange(item.random_deviation * 2 + 1) - item.random_deviation + this->GetSetting(item.name));
this->SetSetting(item.name, ScriptObject::GetRandomizer(OWNER_NONE).Next(item.random_deviation * 2 + 1) - item.random_deviation + this->GetSetting(item.name));
}
}
}

View File

@ -969,7 +969,7 @@ void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const
void SmallMapWindow::DrawMapIndicators() const
{
/* Find main viewport. */
const Viewport *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
const Viewport *vp = GetMainWindow()->viewport;
Point upper_left_smallmap_coord = InverseRemapCoords2(vp->virtual_left, vp->virtual_top);
Point lower_right_smallmap_coord = InverseRemapCoords2(vp->virtual_left + vp->virtual_width - 1, vp->virtual_top + vp->virtual_height - 1);
@ -1461,7 +1461,7 @@ int SmallMapWindow::GetPositionOnLegend(Point pt)
if (click_count > 0) this->mouse_capture_widget = widget;
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
int sub;
pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w);
@ -1732,7 +1732,7 @@ void SmallMapWindow::SetNewScroll(int sx, int sy, int sub)
*/
void SmallMapWindow::SmallMapCenterOnCurrentPos()
{
const Viewport *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
const Viewport *vp = GetMainWindow()->viewport;
Point viewport_center = InverseRemapCoords2(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2);
int sub;
@ -2024,7 +2024,7 @@ void ShowSmallMap()
*/
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
{
bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
bool res = ScrollWindowTo(x, y, z, GetMainWindow(), instant);
/* If a user scrolls to a tile (via what way what so ever) and already is on
* that tile (e.g.: pressed twice), move the smallmap to that location,

View File

@ -121,7 +121,7 @@ static const DrawTileSprites _object_hq[] = {
#undef TILE_SPRITE_LINE
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, OBJECT_CTRL_FLAG_NONE, {0, 0, 0, 0}, {0, 0, 0, 0}, 0, height, 1, gen_amount, true, OVMT_DEFAULT, 0 }
#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), {0, 0, 0, 0}, INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, OBJECT_CTRL_FLAG_NONE, {0, 0, 0, 0}, 0, height, 1, gen_amount, OVMT_DEFAULT, 0 }
/* Climates
* T = Temperate

View File

@ -36,6 +36,7 @@
static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint32 val, ModifyTimetableFlags mtf, bool timetabled, bool ignore_lock = false)
{
Order *order = v->GetOrder(order_number);
assert(order != nullptr);
int total_delta = 0;
int timetable_delta = 0;

View File

@ -904,7 +904,7 @@ static CallBackFunction MenuClickShowAir(int index)
static CallBackFunction ToolbarZoomInClick(Window *w)
{
if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
if (DoZoomInOutWindow(ZOOM_IN, GetMainWindow())) {
w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
}
@ -915,7 +915,7 @@ static CallBackFunction ToolbarZoomInClick(Window *w)
static CallBackFunction ToolbarZoomOutClick(Window *w)
{
if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
if (DoZoomInOutWindow(ZOOM_OUT, GetMainWindow())) {
w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
}
@ -2196,7 +2196,7 @@ struct MainToolbarWindow : Window {
void OnInvalidateData(int data = 0, bool gui_scope = true) override
{
if (!gui_scope) return;
if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
HandleZoomMessage(this, GetMainWindow()->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
}
static HotkeyList hotkeys;
@ -2577,7 +2577,7 @@ struct ScenarioEditorToolbarWindow : Window {
void OnInvalidateData(int data = 0, bool gui_scope = true) override
{
if (!gui_scope) return;
if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
HandleZoomMessage(this, GetMainWindow()->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
}
void OnQueryTextFinished(char *str) override

View File

@ -2546,7 +2546,7 @@ bool GenerateTowns(TownLayout layout)
bool city = (_settings_game.economy.larger_towns != 0 && Chance16(1, _settings_game.economy.larger_towns));
IncreaseGeneratingWorldProgress(GWP_TOWN);
/* Get a unique name for the town. */
if (!GenerateTownName(&townnameparts, &town_names)) continue;
if (!GenerateTownName(_random, &townnameparts, &town_names)) continue;
/* try 20 times to create a random-sized town for the first loop. */
if (CreateRandomTown(20, townnameparts, TSZ_RANDOM, city, layout) != nullptr) current_number++; // If creation was successful, raise a flag.
} while (--total);
@ -2560,7 +2560,7 @@ bool GenerateTowns(TownLayout layout)
/* If current_number is still zero at this point, it means that not a single town has been created.
* So give it a last try, but now more aggressive */
if (GenerateTownName(&townnameparts) &&
if (GenerateTownName(_random, &townnameparts) &&
CreateRandomTown(10000, townnameparts, TSZ_RANDOM, _settings_game.economy.larger_towns != 0, layout) != nullptr) {
return true;
}

View File

@ -1323,7 +1323,7 @@ public:
void RandomTownName()
{
this->townnamevalid = GenerateTownName(&this->townnameparts);
this->townnamevalid = GenerateTownName(_interactive_random, &this->townnameparts);
if (!this->townnamevalid) {
this->townname_editbox.text.DeleteAll();

View File

@ -112,11 +112,12 @@ bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names)
/**
* Generates valid town name.
* @param randomizer the source of random data for generating the name
* @param townnameparts if a name is generated, it's stored there
* @param town_names if a name is generated, check its uniqueness with the set
* @return true iff a name was generated
*/
bool GenerateTownName(uint32 *townnameparts, TownNames *town_names)
bool GenerateTownName(Randomizer &randomizer, uint32 *townnameparts, TownNames *town_names)
{
TownNameParams par(_settings_game.game_creation.town_name);
@ -130,7 +131,7 @@ bool GenerateTownName(uint32 *townnameparts, TownNames *town_names)
* the other towns may take considerable amount of time (10000 is
* too much). */
for (int i = 1000; i != 0; i--) {
uint32 r = _generating_world ? Random() : InteractiveRandom();
uint32 r = randomizer.Next();
if (!VerifyTownName(r, &par, town_names)) continue;
*townnameparts = r;

View File

@ -10,12 +10,13 @@
#ifndef TOWNNAME_FUNC_H
#define TOWNNAME_FUNC_H
#include "core/random_func.hpp"
#include "townname_type.h"
char *GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed);
char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last);
char *GetTownName(char *buff, const Town *t, const char *last);
bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names = nullptr);
bool GenerateTownName(uint32 *townnameparts, TownNames *town_names = nullptr);
bool GenerateTownName(Randomizer &randomizer, uint32 *townnameparts, TownNames *town_names = nullptr);
#endif /* TOWNNAME_FUNC_H */

View File

@ -457,6 +457,7 @@ void RemoveAllTrees()
*/
uint PlaceTreeGroupAroundTile(TileIndex tile, TreeType treetype, uint radius, uint count, bool set_zone)
{
dbg_assert(_game_mode == GM_EDITOR); // Due to InteractiveRandom being used in this function
dbg_assert(treetype < TREE_TOYLAND + TREE_COUNT_TOYLAND);
const bool allow_desert = treetype == TREE_CACTUS;
uint planted = 0;

View File

@ -479,6 +479,7 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles,
u->cargo_subtype = result.subtype;
if (u->type == VEH_AIRCRAFT) {
Vehicle *w = u->Next();
assert(w != nullptr);
w->refit_cap = std::min<uint16>(w->refit_cap, result.mail_capacity);
w->cargo_cap = result.mail_capacity;
if (w->cargo.TotalCount() > w->refit_cap) w->cargo.Truncate(w->cargo.TotalCount() - w->refit_cap);

View File

@ -3878,7 +3878,7 @@ public:
if (_ctrl_pressed) {
ShowExtraViewportWindow(TileVirtXY(v->x_pos, v->y_pos));
} else {
const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
const Window *mainwindow = GetMainWindow();
if (click_count > 1 && mainwindow->viewport->zoom < ZOOM_LVL_DRAW_MAP) {
/* main window 'follows' vehicle */
mainwindow->viewport->follow_vehicle = v->index;
@ -3949,8 +3949,8 @@ public:
{
/* If the hotkey is not for any widget in the UI (i.e. for honking) */
if (hotkey == WID_VV_HONK_HORN) {
const Window* mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
const Vehicle* v = Vehicle::Get(window_number);
const Window *mainwindow = GetMainWindow();
const Vehicle *v = Vehicle::Get(window_number);
/* Only play the sound if we're following this vehicle */
if (mainwindow->viewport->follow_vehicle == v->index) {
v->PlayLeaveStationSound(true);
@ -4185,8 +4185,8 @@ bool VehicleClicked(const GUIVehicleGroup &vehgroup)
void StopGlobalFollowVehicle(const Vehicle *v)
{
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
if (w != nullptr && w->viewport->follow_vehicle == v->index) {
Window *w = GetMainWindow();
if (w->viewport->follow_vehicle == v->index) {
ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true); // lock the main view on the vehicle's last position
w->viewport->follow_vehicle = INVALID_VEHICLE;
}

View File

@ -68,7 +68,7 @@ public:
Point pt;
if (tile == INVALID_TILE) {
/* No tile? Use center of main viewport. */
const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
const Window *w = GetMainWindow();
/* center on same place as main window (zoom is maximum, no adjustment needed) */
pt.x = w->viewport->scrollpos_x + w->viewport->virtual_width / 2;
@ -101,7 +101,7 @@ public:
case WID_EV_ZOOM_OUT: DoZoomInOutWindow(ZOOM_OUT, this); break;
case WID_EV_MAIN_TO_VIEW: { // location button (move main view to same spot as this view) 'Paste Location'
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
int x = this->viewport->scrollpos_x; // Where is the main looking at
int y = this->viewport->scrollpos_y;
@ -113,7 +113,7 @@ public:
}
case WID_EV_VIEW_TO_MAIN: { // inverse location button (move this view to same spot as main view) 'Copy Location'
const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
const Window *w = GetMainWindow();
int x = w->viewport->scrollpos_x;
int y = w->viewport->scrollpos_y;

View File

@ -40,6 +40,7 @@ void MakeWaterKeepingClass(TileIndex tile, Owner o);
void CheckForDockingTile(TileIndex t);
bool RiverModifyDesertZone(TileIndex tile, void *data);
void MakeRiverAndModifyDesertZoneAround(TileIndex tile);
static const uint RIVER_OFFSET_DESERT_DISTANCE = 5; ///< Circular tile search radius to create non-desert around a river tile.
bool IsWateredTile(TileIndex tile, Direction from);

View File

@ -446,6 +446,18 @@ bool RiverModifyDesertZone(TileIndex tile, void *)
return false;
}
/**
* Make a river tile and remove desert directly around it.
* @param tile The tile to change into river and create non-desert around
*/
void MakeRiverAndModifyDesertZoneAround(TileIndex tile) {
MakeRiver(tile, Random());
MarkTileDirtyByTile(tile);
/* Remove desert directly around the river tile. */
CircularTileSearch(&tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
}
/**
* Build a piece of canal.
* @param tile end tile of stretch-dragging

View File

@ -1191,6 +1191,18 @@ Window *FindWindowByClass(WindowClass cls)
return nullptr;
}
/**
* Get the main window, i.e. FindWindowById(WC_MAIN_WINDOW, 0).
* If the main window is not available, this function will trigger an assert.
* @return Pointer to the main window.
*/
Window *GetMainWindow()
{
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
assert(w != nullptr);
return w;
}
/**
* Delete a window by its class and window number (if it is open).
* @param cls Window class
@ -2550,7 +2562,7 @@ static EventState HandleViewportScroll()
return ES_NOT_HANDLED;
}
if (_last_scroll_window == FindWindowById(WC_MAIN_WINDOW, 0) && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) {
if (_last_scroll_window == GetMainWindow() && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) {
/* If the main window is following a vehicle, then first let go of it! */
const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle);
ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle
@ -2922,7 +2934,7 @@ const std::chrono::milliseconds TIME_BETWEEN_DOUBLE_CLICK(500); ///< Time betwee
static void ScrollMainViewport(int x, int y)
{
if (_game_mode != GM_MENU && _game_mode != GM_BOOTSTRAP) {
Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
Window *w = GetMainWindow();
assert(w);
w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom);

View File

@ -16,6 +16,7 @@
Window *FindWindowById(WindowClass cls, WindowNumber number);
Window *FindWindowByClass(WindowClass cls);
Window *GetMainWindow();
void ChangeWindowOwner(Owner old_owner, Owner new_owner);
void ResizeWindow(Window *w, int x, int y, bool clamp_to_screen = true);