diff --git a/docs/GRFv9_changes.md b/docs/GRFv9_changes.md new file mode 100644 index 0000000000000..c6a28526c2c7d --- /dev/null +++ b/docs/GRFv9_changes.md @@ -0,0 +1,71 @@ +## GRFv9 changes from GRFv8. + +* ALL existing Extended Byte fields are now Word fields. +* Action 00: + * `num-info` is now a Word. + * Feature 00: Trains + * Property 05 `tracktype` is now a Word. + * Property 15 `cargotype` is now a Word. + * Property 1D `refitmask` is **removed**. + * Property 2C/2D `cttinclude`/`cttexclude` are now a Word followed by a list of Words. + * Feature 01: Road vehicles + * Property 05 `roadtramtype` is now a Word. + * Property 10 `cargotype` is now a Word. + * Property 12 `sfx` is now a Word. + * Property 16 `refitmask` is **removed**. + * Property 24/25 `cttinclude`/`cttexclude` are now a Word followed by a list of Words. + * Feature 02: Ships + * Property 0C `cargotype` is now a Word. + * Property 10 `sfx` is now a Word. + * Property 11 `refitmask` is **removed**. + * Property 1E/1F `cttinclude`/`cttexclude` are now a Word followed by a list of Words. + * Feature 03: Aircraft + * Property 12 `sfx` is now a Word. + * Property 13 `refitmask` is **removed**. + * Property 1D/1E `cttinclude`/`cttexclude` are now a Word followed by a list of Words. + * Feature 07: Houses + * Properties 0D, 0E, 0F and 1E are **removed**. + * Property 20 `watched cargoes` is now a Word followed by a list of Words. + * Property 23 `accepted cargoes` is now a Word followed by a list of (Word, Byte). + * Feature 09: Industry tiles + * Properties 0A, 0B and 0C are **removed**. + * Property 13 `cargo acceptance` is now a Word followed by a list of (Word, Byte). + * Feature 0A: Industries + * Properties 10, 11, 12, 13 are **removed**. + * Property 15 `sfx` is now a Word followed by a list of Words. + * Properties 1C, 1D and 1E are **removed**. + * Properties 25/16 `producedcargoes`/`acceptedcargoes` are now a Word followed by a list of Words. + * Property 27 `productionrates` is now a Word follow by a list of Bytes. + * Feature 10: Railtypes + * Properties 0E, 0F, 18, 19 and 1D are now a Word followed by a list of DWords. + * Feature 12/13: Roadtypes and Tramtypes + * Properties 0F, 18, 19 and 1D are now a Word followed by a list of DWords. +* Action 02: + * `set-id` is now a Word. Maximum set-id is now 7FFF instead of FF. + * `subroutine` is now a Word. + * `parameter` is now a **DWord**. + * VariationalAction2 `nvar` is now a Word. + * RandomAction2 `nrand` is now a Word. +* Action 03: + * `n-id` is now a Word. + * `ids...` are each now a Word. + * `num-cid` is now a Word. + * `cargo-type` is now a Word. +* Action 04: + * `num-ent` is now a Word. + * `offset` is now always a Word, instead of varying depending on feature/flags. +* Action 07/09: + * `num-sprites` is now a Word. If bit 15 is set, then this is a label instead of the number of sprites. +* Action 0A: + * `num-sets` is now a Word. + * `num-sprites` is now a Word. +* Action 0E: + * `num` is now a Word. +* Action 10: + * `label` is now a Word. Labels MUST have bit 15 set. This means there is no longer any conflict with labels overlapping numbers. +* Action 12: + * `num-def` is now a Word. + * `num-char` is now a Word. + * `base-char` is now a **DWord**. This allows custom glyphs between 0x10000 and 0x1FFFFD to be defined. +* Action 13: + * `num-ent` is now a Word. diff --git a/regression/regression/main.nut b/regression/regression/main.nut index fce258a739aa6..f023f0f7d07dd 100644 --- a/regression/regression/main.nut +++ b/regression/regression/main.nut @@ -2035,6 +2035,20 @@ function Regression::Start() print(" VehicleID: " + c.GetVehicleID()); } break; + case AIEvent.ET_COMPANY_RENAMED: { + local c = AIEventCompanyRenamed.Convert(e); + print(" EventName: CompanyRenamed"); + print(" CompanyID: " + c.GetCompanyID()); + print(" CompanyName: " + c.GetNewName()); + } break; + + case AIEvent.ET_PRESIDENT_RENAMED: { + local c = AIEventPresidentRenamed.Convert(e); + print(" EventName: PresidentRenamed"); + print(" CompanyID: " + c.GetCompanyID()); + print(" PresidentName: " + c.GetNewName()); + } break; + default: print(" Unknown Event"); break; diff --git a/regression/regression/result.txt b/regression/regression/result.txt index 27a81675a9d9d..8611b2f8aa1b1 100644 --- a/regression/regression/result.txt +++ b/regression/regression/result.txt @@ -9711,6 +9711,21 @@ ERROR: IsEnd() is invalid as Begin() is never called GetDestinationType(): 1 GetDestinationIndex(): 7 GetCargoType(): 0 + GetNextEvent: instance + GetEventType: 33 + EventName: CompanyRenamed + CompanyID: 1 + CompanyName: Regression + GetNextEvent: instance + GetEventType: 34 + EventName: PresidentRenamed + CompanyID: 1 + PresidentName: Regression AI + GetNextEvent: instance + GetEventType: 33 + EventName: CompanyRenamed + CompanyID: 1 + CompanyName: Little Frutford Transport IsEventWaiting: false --Math-- @@ -9748,9 +9763,9 @@ ERROR: IsEnd() is invalid as Begin() is never called --Valuate() with excessive CPU usage-- Your script made an error: excessive CPU usage in valuator function -*FUNCTION [unknown()] regression/main.nut line [2051] +*FUNCTION [unknown()] regression/main.nut line [2065] *FUNCTION [Valuate()] NATIVE line [-1] -*FUNCTION [Start()] regression/main.nut line [2052] +*FUNCTION [Start()] regression/main.nut line [2066] [id] 0 [this] TABLE @@ -9759,7 +9774,7 @@ Your script made an error: excessive CPU usage in valuator function [this] INSTANCE Your script made an error: excessive CPU usage in valuator function -*FUNCTION [Start()] regression/main.nut line [2052] +*FUNCTION [Start()] regression/main.nut line [2066] [Infinite] CLOSURE [list] INSTANCE diff --git a/src/autoreplace.cpp b/src/autoreplace.cpp index 977b5e674a04e..138a94dfb4dd7 100644 --- a/src/autoreplace.cpp +++ b/src/autoreplace.cpp @@ -65,7 +65,7 @@ void RemoveAllEngineReplacement(EngineRenewList *erl) EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old) { const EngineRenew *er = GetEngineReplacement(erl, engine, group); - if (er == nullptr && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !HasBit(Group::Get(group)->flags, GroupFlags::GF_REPLACE_PROTECTION)))) { + if (er == nullptr && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !HasFlag(Group::Get(group)->flags, GroupFlags::ReplaceProtection)))) { /* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */ er = GetEngineReplacement(erl, engine, ALL_GROUP); } diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 31a131d487586..aa3963a40297d 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -754,7 +754,7 @@ CommandCost CmdAutoreplaceVehicle(DoCommandFlag flags, VehicleID veh_id) bool wagon_removal = c->settings.renew_keep_length; const Group *g = Group::GetIfValid(v->group_id); - if (g != nullptr) wagon_removal = HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + if (g != nullptr) wagon_removal = HasFlag(g->flags, GroupFlags::ReplaceWagonRemoval); /* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */ Vehicle *w = v; diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index 0d85280db9af6..9eded8c0d75f1 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -405,7 +405,7 @@ class ReplaceVehicleWindow : public Window { bool remove_wagon; const Group *g = Group::GetIfValid(this->sel_group); if (g != nullptr) { - remove_wagon = HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + remove_wagon = HasFlag(g->flags, GroupFlags::ReplaceWagonRemoval); SetDParam(0, STR_GROUP_NAME); SetDParam(1, sel_group); } else { @@ -554,7 +554,7 @@ class ReplaceVehicleWindow : public Window { case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { const Group *g = Group::GetIfValid(this->sel_group); if (g != nullptr) { - Command::Post(this->sel_group, GroupFlags::GF_REPLACE_WAGON_REMOVAL, !HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL), _ctrl_pressed); + Command::Post(this->sel_group, GroupFlags::ReplaceWagonRemoval, !HasFlag(g->flags, GroupFlags::ReplaceWagonRemoval), _ctrl_pressed); } else { // toggle renew_keep_length Command::Post("company.renew_keep_length", Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1); diff --git a/src/base_station_base.h b/src/base_station_base.h index 72a5bb85ce38d..5bbffe6ece2a8 100644 --- a/src/base_station_base.h +++ b/src/base_station_base.h @@ -113,7 +113,7 @@ struct BaseStation : StationPool::PoolItem<&_station_pool> { * @param available will return false if ever the variable asked for does not exist * @return the value stored in the corresponding variable */ - virtual uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const = 0; + virtual uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint32_t parameter, bool &available) const = 0; /** * Update the coordinated of the sign (as shown in the viewport). diff --git a/src/blitter/32bpp_anim.cpp b/src/blitter/32bpp_anim.cpp index d118d75f7a618..13a6560da48ee 100644 --- a/src/blitter/32bpp_anim.cpp +++ b/src/blitter/32bpp_anim.cpp @@ -20,11 +20,6 @@ /** Instantiation of the 32bpp with animation blitter factory. */ static FBlitter_32bppAnim iFBlitter_32bppAnim; -Blitter_32bppAnim::~Blitter_32bppAnim() -{ - free(this->anim_alloc); -} - template inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) { @@ -545,13 +540,12 @@ void Blitter_32bppAnim::PostResize() if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height || _screen.pitch != this->anim_buf_pitch) { /* The size of the screen changed; we can assume we can wipe all data from our buffer */ - free(this->anim_alloc); this->anim_buf_width = _screen.width; this->anim_buf_height = _screen.height; this->anim_buf_pitch = (_screen.width + 7) & ~7; - this->anim_alloc = CallocT(this->anim_buf_pitch * this->anim_buf_height + 8); + this->anim_alloc = std::make_unique(this->anim_buf_pitch * this->anim_buf_height + 8); /* align buffer to next 16 byte boundary */ - this->anim_buf = reinterpret_cast((reinterpret_cast(this->anim_alloc) + 0xF) & (~0xF)); + this->anim_buf = reinterpret_cast((reinterpret_cast(this->anim_alloc.get()) + 0xF) & (~0xF)); } } diff --git a/src/blitter/32bpp_anim.hpp b/src/blitter/32bpp_anim.hpp index 975a9bfd629a4..3e4a63685ff09 100644 --- a/src/blitter/32bpp_anim.hpp +++ b/src/blitter/32bpp_anim.hpp @@ -16,7 +16,7 @@ class Blitter_32bppAnim : public Blitter_32bppOptimized { protected: uint16_t *anim_buf; ///< In this buffer we keep track of the 8bpp indexes so we can do palette animation - void *anim_alloc; ///< The raw allocated buffer, not necessarily aligned correctly + std::unique_ptr anim_alloc; ///< The raw allocated buffer, not necessarily aligned correctly int anim_buf_width; ///< The width of the animation buffer. int anim_buf_height; ///< The height of the animation buffer. int anim_buf_pitch; ///< The pitch of the animation buffer (width rounded up to 16 byte boundary). @@ -25,7 +25,6 @@ class Blitter_32bppAnim : public Blitter_32bppOptimized { public: Blitter_32bppAnim() : anim_buf(nullptr), - anim_alloc(nullptr), anim_buf_width(0), anim_buf_height(0), anim_buf_pitch(0) @@ -33,8 +32,6 @@ class Blitter_32bppAnim : public Blitter_32bppOptimized { this->palette = _cur_palette; } - ~Blitter_32bppAnim(); - void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) override; void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) override; void SetPixel(void *video, int x, int y, uint8_t colour) override; diff --git a/src/blitter/32bpp_optimized.cpp b/src/blitter/32bpp_optimized.cpp index 848bb7e9c7e96..c2d4d25fa292d 100644 --- a/src/blitter/32bpp_optimized.cpp +++ b/src/blitter/32bpp_optimized.cpp @@ -290,7 +290,7 @@ template Sprite *Blitter_32bppOptimized::EncodeInternal(const /* streams of pixels (a, r, g, b channels) * * stored in separated stream so data are always aligned on 4B boundary */ - Colour *dst_px_orig[ZOOM_LVL_END]; + std::array, ZOOM_LVL_END> dst_px_orig; /* interleaved stream of 'm' channel and 'n' channel * 'n' is number of following pixels with the same alpha channel class @@ -298,7 +298,7 @@ template Sprite *Blitter_32bppOptimized::EncodeInternal(const * * it has to be stored in one stream so fewer registers are used - * x86 has problems with register allocation even with this solution */ - uint16_t *dst_n_orig[ZOOM_LVL_END]; + std::array, ZOOM_LVL_END> dst_n_orig; /* lengths of streams */ uint32_t lengths[ZOOM_LVL_END][2]; @@ -320,11 +320,11 @@ template Sprite *Blitter_32bppOptimized::EncodeInternal(const uint size = src_orig->height * src_orig->width; - dst_px_orig[z] = CallocT(size + src_orig->height * 2); - dst_n_orig[z] = CallocT(size * 2 + src_orig->height * 4 * 2); + dst_px_orig[z] = std::make_unique(size + src_orig->height * 2); + dst_n_orig[z] = std::make_unique(size * 2 + src_orig->height * 4 * 2); - uint32_t *dst_px_ln = (uint32_t *)dst_px_orig[z]; - uint32_t *dst_n_ln = (uint32_t *)dst_n_orig[z]; + uint32_t *dst_px_ln = reinterpret_cast(dst_px_orig[z].get()); + uint32_t *dst_n_ln = reinterpret_cast(dst_n_orig[z].get()); const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *)src_orig->data; @@ -405,8 +405,8 @@ template Sprite *Blitter_32bppOptimized::EncodeInternal(const dst_n_ln = (uint32_t *)dst_n; } - lengths[z][0] = (uint8_t *)dst_px_ln - (uint8_t *)dst_px_orig[z]; // all are aligned to 4B boundary - lengths[z][1] = (uint8_t *)dst_n_ln - (uint8_t *)dst_n_orig[z]; + lengths[z][0] = reinterpret_cast(dst_px_ln) - reinterpret_cast(dst_px_orig[z].get()); // all are aligned to 4B boundary + lengths[z][1] = reinterpret_cast(dst_n_ln) - reinterpret_cast(dst_n_orig[z].get()); } uint len = 0; // total length of data @@ -428,11 +428,8 @@ template Sprite *Blitter_32bppOptimized::EncodeInternal(const dst->offset[z][0] = z == zoom_min ? 0 : lengths[z - 1][1] + dst->offset[z - 1][1]; dst->offset[z][1] = lengths[z][0] + dst->offset[z][0]; - memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]); - memcpy(dst->data + dst->offset[z][1], dst_n_orig[z], lengths[z][1]); - - free(dst_px_orig[z]); - free(dst_n_orig[z]); + memcpy(dst->data + dst->offset[z][0], dst_px_orig[z].get(), lengths[z][0]); + memcpy(dst->data + dst->offset[z][1], dst_n_orig[z].get(), lengths[z][1]); } return dest_sprite; diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 4b3c9c5db650b..4d1b1b7526ed0 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -12,6 +12,7 @@ #include "cheat_type.h" #include "company_base.h" #include "company_func.h" +#include "currency.h" #include "saveload/saveload.h" #include "vehicle_base.h" #include "textbuf_gui.h" @@ -29,6 +30,8 @@ #include "error.h" #include "misc_cmd.h" #include "core/geometry_func.hpp" +#include "settings_type.h" +#include "settings_internal.h" #include "timer/timer.h" #include "timer/timer_game_calendar.h" #include "timer/timer_game_economy.h" @@ -221,18 +224,29 @@ static constexpr NWidgetPart _nested_cheat_widgets[] = { NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_C_PANEL), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_VERTICAL), SetPadding(WidgetDimensions::unscaled.framerect), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_PANEL), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_SETTINGS), + EndContainer(), + EndContainer(), }; /** GUI for the cheats. */ struct CheatWindow : Window { int clicked; - int clicked_widget; + int clicked_cheat; uint line_height; Dimension icon; ///< Dimension of company icon sprite + std::vector sandbox_settings; + const SettingDesc *clicked_setting; + const SettingDesc *last_clicked_setting; + const SettingDesc *valuewindow_entry; + CheatWindow(WindowDesc &desc) : Window(desc) { + this->sandbox_settings = GetFilteredSettingCollection([](const SettingDesc &sd) { return HasFlag(sd.flags, SF_SANDBOX); }); this->InitNested(); } @@ -243,9 +257,15 @@ struct CheatWindow : Window { void DrawWidget(const Rect &r, WidgetID widget) const override { - if (widget != WID_C_PANEL) return; + switch (widget) { + case WID_C_PANEL: DrawCheatWidget(r); break; + case WID_C_SETTINGS: DrawSettingsWidget(r); break; + } + } - const Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); + void DrawCheatWidget(const Rect &r) const + { + const Rect ir = r; int y = ir.top; bool rtl = _current_text_dir == TD_RTL; @@ -270,7 +290,7 @@ struct CheatWindow : Window { } default: { - int32_t val = (int32_t)ReadValue(ce->variable, ce->type); + int32_t val = static_cast(ReadValue(ce->variable, ce->type)); /* Draw [<][>] boxes for settings of an integer-type */ DrawArrowButtons(button_left, y + button_y_offset, COLOUR_YELLOW, clicked - (i * 2), true, true); @@ -299,10 +319,58 @@ struct CheatWindow : Window { } } + void DrawSettingsWidget(const Rect &r) const + { + Rect ir = r.WithHeight(this->line_height); + + for (const auto &desc : this->sandbox_settings) { + DrawSetting(ir, desc); + ir = ir.Translate(0, this->line_height); + } + } + + void DrawSetting(const Rect r, const SettingDesc *desc) const + { + const IntSettingDesc *sd = desc->AsIntSetting(); + int state = this->clicked_setting == sd ? this->clicked : 0; + + bool rtl = _current_text_dir == TD_RTL; + + Rect buttons = r.WithWidth(SETTING_BUTTON_WIDTH, rtl); + Rect text = r.Indent(SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_wide, rtl); + buttons.top += (r.Height() - SETTING_BUTTON_HEIGHT) / 2; + text.top += (r.Height() - GetCharacterHeight(FS_NORMAL)) / 2; + + /* We do not allow changes of some items when we are a client in a network game */ + bool editable = sd->IsEditable(); + + SetDParam(0, STR_CONFIG_SETTING_VALUE); + int32_t value = sd->Read(&GetGameSettings()); + if (sd->IsBoolSetting()) { + /* Draw checkbox for boolean-value either on/off */ + DrawBoolButton(buttons.left, buttons.top, value != 0, editable); + } else if (HasFlag(sd->flags, SF_GUI_DROPDOWN)) { + /* Draw [v] button for settings of an enum-type */ + DrawDropDownButton(buttons.left, buttons.top, COLOUR_YELLOW, state != 0, editable); + } else { + /* Draw [<][>] boxes for settings of an integer-type */ + DrawArrowButtons(buttons.left, buttons.top, COLOUR_YELLOW, state, + editable && value != (HasFlag(sd->flags, SF_GUI_0_IS_SPECIAL) ? 0 : sd->min), editable && static_cast(value) != sd->max); + } + sd->SetValueDParams(1, value); + DrawString(text.left, text.right, text.top, sd->GetTitle(), TC_LIGHT_BLUE); + } + void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override { - if (widget != WID_C_PANEL) return; + switch (widget) { + case WID_C_PANEL: UpdateCheatPanelSize(size); break; + case WID_C_SETTINGS: UpdateSettingsPanelSize(size); break; + } + } + void UpdateCheatPanelSize(Dimension &size) + { uint width = 0; for (const auto &ce : _cheats_ui) { switch (ce.type) { @@ -340,13 +408,34 @@ struct CheatWindow : Window { this->line_height = std::max(this->line_height, GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.framerect.Vertical(); size.width = width + WidgetDimensions::scaled.hsep_wide * 2 + SETTING_BUTTON_WIDTH; - size.height = WidgetDimensions::scaled.framerect.Vertical() + this->line_height * lengthof(_cheats_ui); + size.height = this->line_height * lengthof(_cheats_ui); + } + + void UpdateSettingsPanelSize(Dimension &size) + { + uint width = 0; + for (const auto &desc : this->sandbox_settings) { + const IntSettingDesc *sd = desc->AsIntSetting(); + + SetDParam(0, STR_CONFIG_SETTING_VALUE); + sd->SetValueDParams(1, sd->max); + width = std::max(width, GetStringBoundingBox(sd->GetTitle()).width); + } + + size.width = width + WidgetDimensions::scaled.hsep_wide * 2 + SETTING_BUTTON_WIDTH; + size.height = this->line_height * static_cast(std::size(this->sandbox_settings)); } void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override { - if (widget != WID_C_PANEL) return; + switch (widget) { + case WID_C_PANEL: CheatPanelClick(pt); break; + case WID_C_SETTINGS: SettingsPanelClick(pt); break; + } + } + void CheatPanelClick(Point pt) + { Rect r = this->GetWidget(WID_C_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect); uint btn = (pt.y - r.top) / this->line_height; int x = pt.x - r.left; @@ -356,17 +445,17 @@ struct CheatWindow : Window { if (btn >= lengthof(_cheats_ui)) return; const CheatEntry *ce = &_cheats_ui[btn]; - int value = (int32_t)ReadValue(ce->variable, ce->type); + int value = static_cast(ReadValue(ce->variable, ce->type)); int oldvalue = value; if (btn == CHT_CHANGE_DATE && x >= SETTING_BUTTON_WIDTH) { /* Click at the date text directly. */ - clicked_widget = CHT_CHANGE_DATE; + clicked_cheat = CHT_CHANGE_DATE; SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CHEAT_CHANGE_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); return; } else if (btn == CHT_EDIT_MAX_HL && x >= SETTING_BUTTON_WIDTH) { - clicked_widget = CHT_EDIT_MAX_HL; + clicked_cheat = CHT_EDIT_MAX_HL; SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); return; @@ -375,6 +464,7 @@ struct CheatWindow : Window { /* Not clicking a button? */ if (!IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) return; + this->clicked_setting = nullptr; *ce->been_used = true; switch (ce->type) { @@ -392,15 +482,120 @@ struct CheatWindow : Window { break; } - if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64_t)value); + if (value != oldvalue) WriteValue(ce->variable, ce->type, static_cast(value)); this->SetTimeout(); this->SetDirty(); } + void SettingsPanelClick(Point pt) + { + int row = this->GetRowFromWidget(pt.y, WID_C_SETTINGS, WidgetDimensions::scaled.framerect.top, this->line_height); + if (row == INT_MAX) return; + + const SettingDesc *desc = this->sandbox_settings[row]; + const IntSettingDesc *sd = desc->AsIntSetting(); + + if (!sd->IsEditable()) return; + + Rect r = this->GetWidget(WID_C_SETTINGS)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect); + int x = pt.x - r.left; + bool rtl = _current_text_dir == TD_RTL; + if (rtl) x = r.Width() - 1 - x; + + if (x < SETTING_BUTTON_WIDTH) { + ChangeSettingValue(sd, x); + } else { + /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */ + if (this->last_clicked_setting == sd && !sd->IsBoolSetting() && !HasFlag(sd->flags, SF_GUI_DROPDOWN)) { + int64_t value64 = sd->Read(&GetGameSettings()); + + /* Show the correct currency-translated value */ + if (HasFlag(sd->flags, SF_GUI_CURRENCY)) value64 *= GetCurrency().rate; + + CharSetFilter charset_filter = CS_NUMERAL; //default, only numeric input allowed + if (sd->min < 0) charset_filter = CS_NUMERAL_SIGNED; // special case, also allow '-' sign for negative input + + this->valuewindow_entry = sd; + SetDParam(0, value64); + + /* Limit string length to 14 so that MAX_INT32 * max currency rate doesn't exceed MAX_INT64. */ + ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 15, this, charset_filter, QSF_ENABLE_DEFAULT); + } + + this->clicked_setting = sd; + } + } + + void ChangeSettingValue(const IntSettingDesc *sd, int x) + { + int32_t value = sd->Read(&GetGameSettings()); + int32_t oldvalue = value; + if (sd->IsBoolSetting()) { + value ^= 1; + } else { + /* don't allow too fast scrolling */ + if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) { + _left_button_clicked = false; + return; + } + + /* Add a dynamic step-size to the scroller. In a maximum of + * 50-steps you should be able to get from min to max, + * unless specified otherwise in the 'interval' variable + * of the current setting. */ + uint32_t step = (sd->interval == 0) ? ((sd->max - sd->min) / 50) : sd->interval; + if (step == 0) step = 1; + + /* Increase or decrease the value and clamp it to extremes */ + if (x >= SETTING_BUTTON_WIDTH / 2) { + value += step; + if (sd->min < 0) { + assert(static_cast(sd->max) >= 0); + if (value > static_cast(sd->max)) value = static_cast(sd->max); + } else { + if (static_cast(value) > sd->max) value = static_cast(sd->max); + } + if (value < sd->min) value = sd->min; // skip between "disabled" and minimum + } else { + value -= step; + if (value < sd->min) value = HasFlag(sd->flags, SF_GUI_0_IS_SPECIAL) ? 0 : sd->min; + } + + /* Set up scroller timeout for numeric values */ + if (value != oldvalue) { + this->last_clicked_setting = nullptr; + this->clicked_setting = sd; + this->clicked = (x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? 2 : 1; + this->SetTimeout(); + _left_button_clicked = false; + } + } + + if (value != oldvalue) { + SetSettingValue(sd, value); + this->SetDirty(); + } + } + + bool OnTooltip([[maybe_unused]] Point pt, WidgetID widget, TooltipCloseCondition close_cond) override + { + if (widget != WID_C_SETTINGS) return false; + + int row = GetRowFromWidget(pt.y, widget, WidgetDimensions::scaled.framerect.top, this->line_height); + if (row == INT_MAX) return false; + + const SettingDesc *desc = this->sandbox_settings[row]; + const IntSettingDesc *sd = desc->AsIntSetting(); + GuiShowTooltips(this, sd->GetHelp(), close_cond); + + return true; + } + void OnTimeout() override { + this->clicked_setting = nullptr; this->clicked = 0; this->SetDirty(); } @@ -410,13 +605,33 @@ struct CheatWindow : Window { /* Was 'cancel' pressed or nothing entered? */ if (!str.has_value() || str->empty()) return; - const CheatEntry *ce = &_cheats_ui[clicked_widget]; - int oldvalue = (int32_t)ReadValue(ce->variable, ce->type); - int value = atoi(str->c_str()); - *ce->been_used = true; - value = ce->proc(value, value - oldvalue); + if (this->valuewindow_entry != nullptr) { + const IntSettingDesc *sd = this->valuewindow_entry->AsIntSetting(); + + int32_t value; + if (!str->empty()) { + long long llvalue = atoll(str->c_str()); + + /* Save the correct currency-translated value */ + if (HasFlag(sd->flags, SF_GUI_CURRENCY)) llvalue /= GetCurrency().rate; + + value = ClampTo(llvalue); + } else { + value = sd->GetDefaultValue(); + } + + SetSettingValue(sd, value); + } else { + const CheatEntry *ce = &_cheats_ui[clicked_cheat]; + int oldvalue = static_cast(ReadValue(ce->variable, ce->type)); + int value = atoi(str->c_str()); + *ce->been_used = true; + value = ce->proc(value, value - oldvalue); + + if (value != oldvalue) WriteValue(ce->variable, ce->type, static_cast(value)); + } - if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64_t)value); + this->valuewindow_entry = nullptr; this->SetDirty(); } diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 1a6d96583c1a2..e955091c5bd4d 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -424,6 +424,8 @@ set_name:; c->name_2 = strp; MarkWholeScreenDirty(); + AI::BroadcastNewEvent(new ScriptEventCompanyRenamed(c->index, name)); + Game::NewEvent(new ScriptEventCompanyRenamed(c->index, name)); if (c->is_ai) { auto cni = std::make_unique(c); @@ -1184,6 +1186,11 @@ CommandCost CmdRenameCompany(DoCommandFlag flags, const std::string &text) } MarkWholeScreenDirty(); CompanyAdminUpdate(c); + + SetDParam(0, c->index); + std::string new_name = GetString(STR_COMPANY_NAME); + AI::BroadcastNewEvent(new ScriptEventCompanyRenamed(c->index, new_name)); + Game::NewEvent(new ScriptEventCompanyRenamed(c->index, new_name)); } return CommandCost(); @@ -1234,6 +1241,11 @@ CommandCost CmdRenamePresident(DoCommandFlag flags, const std::string &text) InvalidateWindowClassesData(WC_COMPANY, 1); MarkWholeScreenDirty(); CompanyAdminUpdate(c); + + SetDParam(0, c->index); + std::string new_name = GetString(STR_PRESIDENT_NAME); + AI::BroadcastNewEvent(new ScriptEventPresidentRenamed(c->index, new_name)); + Game::NewEvent(new ScriptEventPresidentRenamed(c->index, new_name)); } return CommandCost(); diff --git a/src/dropdown.cpp b/src/dropdown.cpp index 3fde9ef74fee5..38d50ff1b53cf 100644 --- a/src/dropdown.cpp +++ b/src/dropdown.cpp @@ -47,9 +47,9 @@ std::unique_ptr MakeDropDownListIconItem(const Dimension &dim, return std::make_unique(dim, sprite, palette, str, value, masked, shaded); } -std::unique_ptr MakeDropDownListCheckedItem(bool checked, StringID str, int value, bool masked, bool shaded) +std::unique_ptr MakeDropDownListCheckedItem(bool checked, StringID str, int value, bool masked, bool shaded, uint indent) { - return std::make_unique(checked, str, value, masked, shaded); + return std::make_unique(indent, checked, str, value, masked, shaded); } static constexpr NWidgetPart _nested_dropdown_menu_widgets[] = { diff --git a/src/dropdown_common_type.h b/src/dropdown_common_type.h index a851c216ec2c6..71becf9fa1813 100644 --- a/src/dropdown_common_type.h +++ b/src/dropdown_common_type.h @@ -169,10 +169,31 @@ class DropDownCheck : public TBase { } }; +/** + * Drop down indent component. + * @tparam TBase Base component. + * @tparam TEnd Position checkmark at end if true, or start if false. + */ +template +class DropDownIndent : public TBase { + uint indent; +public: + template + explicit DropDownIndent(uint indent, Args&&... args) : TBase(std::forward(args)...), indent(indent) {} + + uint Width() const override { return this->indent * WidgetDimensions::scaled.hsep_indent + this->TBase::Width(); } + + void Draw(const Rect &full, const Rect &r, bool sel, Colours bg_colour) const override + { + bool rtl = TEnd ^ (_current_text_dir == TD_RTL); + this->TBase::Draw(full, r.Indent(this->indent * WidgetDimensions::scaled.hsep_indent, rtl), sel, bg_colour); + } +}; + /* Commonly used drop down list items. */ using DropDownListDividerItem = DropDownDivider; using DropDownListStringItem = DropDownString; using DropDownListIconItem = DropDownIcon>; -using DropDownListCheckedItem = DropDownCheck>; +using DropDownListCheckedItem = DropDownIndent>>; #endif /* DROPDOWN_COMMON_TYPE_H */ diff --git a/src/dropdown_func.h b/src/dropdown_func.h index 6aee0066f76b8..7e520c21cea3f 100644 --- a/src/dropdown_func.h +++ b/src/dropdown_func.h @@ -21,6 +21,6 @@ std::unique_ptr MakeDropDownListStringItem(StringID str, int v std::unique_ptr MakeDropDownListStringItem(const std::string &str, int value, bool masked = false, bool shaded = false); std::unique_ptr MakeDropDownListIconItem(SpriteID sprite, PaletteID palette, StringID str, int value, bool masked = false, bool shaded = false); std::unique_ptr MakeDropDownListIconItem(const Dimension &dim, SpriteID sprite, PaletteID palette, StringID str, int value, bool masked = false, bool shaded = false); -std::unique_ptr MakeDropDownListCheckedItem(bool checked, StringID str, int value, bool masked = false, bool shaded = false); +std::unique_ptr MakeDropDownListCheckedItem(bool checked, StringID str, int value, bool masked = false, bool shaded = false, uint indent = 0); #endif /* DROPDOWN_FUNC_H */ diff --git a/src/group.h b/src/group.h index 39d9033d36ff3..8a6cc26939f20 100644 --- a/src/group.h +++ b/src/group.h @@ -62,11 +62,12 @@ struct GroupStatistics { static void UpdateAutoreplace(CompanyID company); }; -enum GroupFlags : uint8_t { - GF_REPLACE_PROTECTION, ///< If set to true, the global autoreplace has no effect on the group - GF_REPLACE_WAGON_REMOVAL, ///< If set, autoreplace will perform wagon removal on vehicles in this group. - GF_END, +enum class GroupFlags : uint8_t { + None = 0, + ReplaceProtection = 1U << 0, ///< If set, the global autoreplace has no effect on the group + ReplaceWagonRemoval = 1U << 1, ///< If set, autoreplace will perform wagon removal on vehicles in this group. }; +DECLARE_ENUM_AS_BIT_SET(GroupFlags) /** Group data. */ struct Group : GroupPool::PoolItem<&_group_pool> { @@ -74,7 +75,7 @@ struct Group : GroupPool::PoolItem<&_group_pool> { Owner owner; ///< Group Owner VehicleType vehicle_type; ///< Vehicle type of the group - uint8_t flags; ///< Group flags + GroupFlags flags = GroupFlags::None; ///< Group flags Livery livery; ///< Custom colour scheme for vehicles in this group GroupStatistics statistics; ///< NOSAVE: Statistics and caches on the vehicles in the group. diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index 6adde37974129..c37fc7eeb22af 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -355,7 +355,7 @@ std::tuple CmdCreateGroup(DoCommandFlag flags, VehicleType if (pg == nullptr) { g->livery.colour1 = c->livery[LS_DEFAULT].colour1; g->livery.colour2 = c->livery[LS_DEFAULT].colour2; - if (c->settings.renew_keep_length) SetBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + if (c->settings.renew_keep_length) g->flags |= GroupFlags::ReplaceWagonRemoval; } else { g->parent = pg->index; g->livery.colour1 = pg->livery.colour1; @@ -698,9 +698,9 @@ CommandCost CmdSetGroupLivery(DoCommandFlag flags, GroupID group_id, bool primar static void SetGroupFlag(Group *g, GroupFlags flag, bool set, bool children) { if (set) { - SetBit(g->flags, flag); + g->flags |= flag; } else { - ClrBit(g->flags, flag); + g->flags &= ~flag; } if (!children) return; @@ -724,7 +724,7 @@ CommandCost CmdSetGroupFlag(DoCommandFlag flags, GroupID group_id, GroupFlags fl Group *g = Group::GetIfValid(group_id); if (g == nullptr || g->owner != _current_company) return CMD_ERROR; - if (flag >= GroupFlags::GF_END) return CMD_ERROR; + if (flag != GroupFlags::ReplaceProtection && flag != GroupFlags::ReplaceWagonRemoval) return CMD_ERROR; if (flags & DC_EXEC) { SetGroupFlag(g, flag, value, recursive); diff --git a/src/group_cmd.h b/src/group_cmd.h index 81c6f4cdf2f2d..8a7d011f312a7 100644 --- a/src/group_cmd.h +++ b/src/group_cmd.h @@ -17,7 +17,7 @@ #include "vehiclelist_cmd.h" enum Colours : uint8_t; -enum GroupFlags : uint8_t; +enum class GroupFlags : uint8_t; /** Action for \c CmdAlterGroup. */ enum class AlterGroupMode : uint8_t { diff --git a/src/group_gui.cpp b/src/group_gui.cpp index abd69de72ebaf..aa62f1ee7dd92 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -584,7 +584,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow { /* If not a default group and the group has replace protection, show an enabled replace sprite. */ uint16_t protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN; - if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && HasBit(Group::Get(this->vli.index)->flags, GroupFlags::GF_REPLACE_PROTECTION)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; + if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && HasFlag(Group::Get(this->vli.index)->flags, GroupFlags::ReplaceProtection)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; this->GetWidget(WID_GL_REPLACE_PROTECTION)->SetSprite(protect_sprite + this->vli.vtype); /* Set text of "group by" dropdown widget. */ @@ -650,7 +650,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow { assert(g->owner == this->owner); - DrawGroupInfo(y1, r.left, r.right, g->index, it->level_mask, it->indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)); + DrawGroupInfo(y1, r.left, r.right, g->index, it->level_mask, it->indent, HasFlag(g->flags, GroupFlags::ReplaceProtection), g->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)); y1 += this->tiny_step_height; } @@ -868,7 +868,7 @@ class VehicleGroupWindow : public BaseVehicleListWindow { case WID_GL_REPLACE_PROTECTION: { const Group *g = Group::GetIfValid(this->vli.index); if (g != nullptr) { - Command::Post(this->vli.index, GroupFlags::GF_REPLACE_PROTECTION, !HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), _ctrl_pressed); + Command::Post(this->vli.index, GroupFlags::ReplaceProtection, !HasFlag(g->flags, GroupFlags::ReplaceProtection), _ctrl_pressed); } break; } diff --git a/src/industrytype.h b/src/industrytype.h index 5421a0bcb6dcc..301d9172394c1 100644 --- a/src/industrytype.h +++ b/src/industrytype.h @@ -130,7 +130,7 @@ struct IndustrySpec { uint16_t callback_mask; ///< Bitmask of industry callbacks that have to be called bool enabled; ///< entity still available (by default true).newgrf can disable it, though GRFFileProps grf_prop; ///< properties related to the grf file - std::vector random_sounds; ///< Random sounds; + std::vector random_sounds; ///< Random sounds; std::array, INDUSTRY_ORIGINAL_NUM_OUTPUTS> produced_cargo_label; ///< Cargo labels of produced cargo for default industries. std::array, INDUSTRY_ORIGINAL_NUM_INPUTS> accepts_cargo_label; ///< Cargo labels of accepted cargo for default industries. diff --git a/src/landscape.cpp b/src/landscape.cpp index 9f92912c913ca..f3dcebccf6e95 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -93,7 +93,7 @@ static const uint TILE_UPDATE_FREQUENCY = 1 << TILE_UPDATE_FREQUENCY_LOG; ///< * @ingroup SnowLineGroup * @see GetSnowLine() GameCreationSettings */ -static SnowLine *_snow_line = nullptr; +static std::unique_ptr _snow_line; /** * Map 2D viewport or smallmap coordinate to 3D world or tile coordinate. @@ -584,21 +584,12 @@ bool IsSnowLineSet() /** * Set a variable snow line, as loaded from a newgrf file. - * @param table the 12 * 32 byte table containing the snowline for each day + * @param snow_line The new snow line configuration. * @ingroup SnowLineGroup */ -void SetSnowLine(uint8_t table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]) +void SetSnowLine(std::unique_ptr &&snow_line) { - _snow_line = CallocT(1); - _snow_line->lowest_value = 0xFF; - memcpy(_snow_line->table, table, sizeof(_snow_line->table)); - - for (uint i = 0; i < SNOW_LINE_MONTHS; i++) { - for (uint j = 0; j < SNOW_LINE_DAYS; j++) { - _snow_line->highest_value = std::max(_snow_line->highest_value, table[i][j]); - _snow_line->lowest_value = std::min(_snow_line->lowest_value, table[i][j]); - } - } + _snow_line = std::move(snow_line); } /** @@ -640,7 +631,6 @@ uint8_t LowestSnowLine() */ void ClearSnowLine() { - free(_snow_line); _snow_line = nullptr; } diff --git a/src/landscape.h b/src/landscape.h index 98221c5019b09..db2a9781e47b1 100644 --- a/src/landscape.h +++ b/src/landscape.h @@ -22,12 +22,12 @@ static const uint SNOW_LINE_DAYS = 32; ///< Number of days in each month in th */ struct SnowLine { uint8_t table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]; ///< Height of the snow line each day of the year - uint8_t highest_value; ///< Highest snow line of the year - uint8_t lowest_value; ///< Lowest snow line of the year + uint8_t highest_value = 0; ///< Highest snow line of the year + uint8_t lowest_value = UINT8_MAX; ///< Lowest snow line of the year }; bool IsSnowLineSet(); -void SetSnowLine(uint8_t table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]); +void SetSnowLine(std::unique_ptr &&snow_line); uint8_t GetSnowLine(); uint8_t HighestSnowLine(); uint8_t LowestSnowLine(); diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index 8e2715e667169..546cf3047d7d8 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -390,7 +390,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Verlaat # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spel opsies STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Stellings STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF stellings diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index e54edbfcf76ea..9dc73345f484e 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -411,7 +411,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :انهاء # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :إعدادات اللعبه STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :الإعدادات STR_SETTINGS_MENU_AI_SETTINGS :اعدادات االذكاء الاصطناعي diff --git a/src/lang/basque.txt b/src/lang/basque.txt index 51b8f42dbd3e9..f2fb2ac8e832b 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -380,7 +380,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Irten # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Jokoaren aukerak STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Ezarpenak STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF ezarpenak diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index ed4646ab19ed6..1dfa0c9c2cb71 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -753,7 +753,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Выхад # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Наладкі гульні STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Наладкі STR_SETTINGS_MENU_AI_SETTINGS :Наладкі ШІ diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index a1d1345504a21..413b59c637aa4 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Gerar localidad STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Colocar casas # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opções do jogo STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Configurações STR_SETTINGS_MENU_AI_SETTINGS :Configurações de IA diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index f46313ea09e2b..f97c5b0f7f17b 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Генерир STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Постави къщи # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Игрови настройки STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Разширени настройки STR_SETTINGS_MENU_AI_SETTINGS :Настройки на ИИ diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index a49a58640469e..09ed6fd4c1072 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Genera poblacio STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Posa cases # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opcions de la partida STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Configuració STR_SETTINGS_MENU_AI_SETTINGS :Configuració de la IA diff --git a/src/lang/chuvash.txt b/src/lang/chuvash.txt index 883617ee47db6..7e09e5ba108f7 100644 --- a/src/lang/chuvash.txt +++ b/src/lang/chuvash.txt @@ -234,7 +234,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Вӗҫле # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Вӑййи майлаштару STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF майлаштару diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 2749e2959a7a4..a1bc554394087 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -488,7 +488,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Izlaz # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Postavke igre STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Postavke STR_SETTINGS_MENU_NEWGRF_SETTINGS :Postavke za NewGRF diff --git a/src/lang/czech.txt b/src/lang/czech.txt index 2eb7c6186fd4e..c879ea8c79a0c 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -518,7 +518,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generovat měst STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Budovat domy # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Možnosti hry STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Nastavení STR_SETTINGS_MENU_AI_SETTINGS :Nastavení AI diff --git a/src/lang/danish.txt b/src/lang/danish.txt index fba5dd33c6db1..1e93dcfb17415 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -172,7 +172,7 @@ STR_CRATES :{COMMA} kasse{P STR_COLOUR_DEFAULT :Standard ###length 17 STR_COLOUR_DARK_BLUE :Mørkeblå -STR_COLOUR_PALE_GREEN :Bleggrøn +STR_COLOUR_PALE_GREEN :Lysegrøn STR_COLOUR_PINK :Lyserød STR_COLOUR_YELLOW :Gul STR_COLOUR_RED :Rød @@ -190,7 +190,7 @@ STR_COLOUR_WHITE :Hvid STR_COLOUR_RANDOM :Tilfældig ###length 17 -STR_COLOUR_SECONDARY_DARK_BLUE :Mørkblå +STR_COLOUR_SECONDARY_DARK_BLUE :Mørkeblå STR_COLOUR_SECONDARY_PALE_GREEN :Lysegrøn STR_COLOUR_SECONDARY_SECONDARY_PINK :Lyserød STR_COLOUR_SECONDARY_YELLOW :Gul @@ -201,7 +201,7 @@ STR_COLOUR_SECONDARY_DARK_GREEN :Mørkegrøn STR_COLOUR_SECONDARY_BLUE :Blå STR_COLOUR_SECONDARY_CREAM :Fløde STR_COLOUR_SECONDARY_MAUVE :Lilla -STR_COLOUR_SECONDARY_PURPLE :Violet +STR_COLOUR_SECONDARY_PURPLE :Lilla STR_COLOUR_SECONDARY_ORANGE :Orange STR_COLOUR_SECONDARY_BROWN :Brun STR_COLOUR_SECONDARY_GREY :Grå @@ -277,7 +277,7 @@ STR_TOOLTIP_GROUP_ORDER :{BLACK}Vælg gr STR_TOOLTIP_SORT_ORDER :{BLACK}Vælg sorteringsorden (faldende/stigende) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Vælg sorteringskriterie STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Vælg filtreringskriterier -STR_BUTTON_SORT_BY :{BLACK}Sortér på +STR_BUTTON_SORT_BY :{BLACK}Sortér efter STR_BUTTON_CATCHMENT :{BLACK}Dækning STR_TOOLTIP_CATCHMENT :{BLACK}Aktiver visning af dækningsområde @@ -308,7 +308,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Ved at a # Query window STR_BUTTON_DEFAULT :{BLACK}Standard -STR_BUTTON_CANCEL :{BLACK}Annuller +STR_BUTTON_CANCEL :{BLACK}Annullér STR_BUTTON_OK :{BLACK}OK # On screen keyboard window @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Skab byer STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Placer huse # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opsætning STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Indstillinger STR_SETTINGS_MENU_AI_SETTINGS :AI indstillinger @@ -646,7 +645,7 @@ STR_COMPANY_LEAGUE_COMPANY_RANK :{YELLOW}#{NUM} STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Ingeniør STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Trafikbestyrer STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Trafikkoordinator -STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Routesuperviser +STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Rutesupervisor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Direktør STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Administrerende direktør STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Forretningschef @@ -931,7 +930,7 @@ STR_NEWS_STATION_NOW_ACCEPTS_CARGO_LIST :{WHITE}{STATION STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Licitation af tilskudsordning udløbet:{}{}{STRING} fra {STRING} til {STRING} vil ikke længere udløse tilskud. STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Tilskudsordning tilbagetrukket:{}{}{STRING} fra {STRING} til {STRING} modtager ikke længere tilskud. -STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Tilskudsordning i udbyd:{}{}Første {STRING} fra {STRING} til {STRING} vil tiltrække et {UNITS_YEARS_OR_MINUTES} tilskud fra den lokale myndighed! +STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Tilskudsordning i udbud:{}{}Første {STRING} fra {STRING} til {STRING} vil udløse et {UNITS_YEARS_OR_MINUTES}s tilskud fra den lokale myndighed! ###length 4 STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Servicetilskud tildelt til {STRING}!{}{}{STRING} fra {STRING} til {STRING} vil betale 50% ekstra for de næste {UNITS_YEARS_OR_MINUTES}! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Tilskudsordning tildelt {STRING}!{}{}{STRING} fra {STRING} til {STRING} vil betale dobbelt takster for den næste {UNITS_YEARS_OR_MINUTES}! @@ -1216,7 +1215,7 @@ STR_WARNING_NO_SUITABLE_AI :{WHITE}Der blev # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Indstillinger -STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter streng: +STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filterstreng: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Udvid alle STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Skjul alle STR_CONFIG_SETTING_RESET_ALL :{BLACK}Nulstil alle værdier @@ -1237,7 +1236,7 @@ STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Begrænser listen nedenfor så den kun viser ændrede indstillinger STR_CONFIG_SETTING_RESTRICT_BASIC :Grund Indstillinger STR_CONFIG_SETTING_RESTRICT_ADVANCED :Avancerede indstillinger -STR_CONFIG_SETTING_RESTRICT_ALL :Ekspert indstillinger / alle indstillinger +STR_CONFIG_SETTING_RESTRICT_ALL :Ekspertindstillinger / alle indstillinger STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Indstillinger med en anden værdi end standard STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Indstillinger med en anden værdi end dine nyt-spil indstillinger @@ -1277,7 +1276,7 @@ STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Højre STR_CONFIG_SETTING_SECONDS_VALUE :{COMMA}{NBSP}sekund{P 0 "" er} -STR_CONFIG_SETTING_INFINITE_MONEY :Ubegrænset penge: {STRING} +STR_CONFIG_SETTING_INFINITE_MONEY :Ubegrænsede penge: {STRING} STR_CONFIG_SETTING_INFINITE_MONEY_HELPTEXT :Tillad ubegrænset forbrug og deaktiver virksomheders konkurs STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maksimum startlån: {STRING} @@ -1354,7 +1353,7 @@ STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Indstil, hvor m STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Accelerationsmodel for tog: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Vælg fysik model for tog acceleration. Den "oprindelige" model straffer skråninger lige for alle køretøjer. Den "realistisk" model straffer skråninger og kurver afhængigt af forskellige egenskaber, så som længde og trækkraft -STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Køretøjs accelerations model: {STRING} +STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Køretøjers accelerationsmodel: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Vælg fysik model for køretøj acceleration. Den "oprindelige" model straffer skråninger lige for alle køretøjer. Den "realistisk" model straffer skråninger afhængigt af forskellige egenskaber af motoren, for eksempel 'trækkraft' STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Skrånings stejlhed for tog: {STRING} @@ -1373,13 +1372,13 @@ STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Tillad tilføje STR_CONFIG_SETTING_INFLATION :Inflation: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Aktiver inflation i økonomien, hvor omkostningerne er lidt hurtigere stigende end betalinger -STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maksimal bro længde: {STRING} +STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maksimal brolængde: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maksimal længde af broer -STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maksimal bro højde: {STRING} +STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maksimal brohøjde: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Maksimal højde der kan bygges bro over -STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maksimal tunnel længde: {STRING} +STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maksimal tunnellængde: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maksimal længde af tunneler STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Metode til manuel opførsel af primær industri: {STRING} @@ -1389,7 +1388,7 @@ STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :Ingen STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :Som andre industrier STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Efterforskning -STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Fladt område omkring industier: {STRING} +STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Fladt område omkring industrier: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Mængden af fladt område omkring en industri. Dette sikrer tom plads vil forblive tilgængelige omkring en industri for bygge spor osv. STR_CONFIG_SETTING_MULTIPINDTOWN :Tillad flere af samme slags industri per by: {STRING} @@ -1403,7 +1402,7 @@ STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :På køresiden STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :På højre ###length 2 -STR_CONFIG_SETTING_SHOWFINANCES :Vis finansvinduet i slutningen af året: {STRING} +STR_CONFIG_SETTING_SHOWFINANCES :Vis finansvinduet ved afslutningen af året: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_PERIOD :Vis økonomivindue i slutningen af perioden: {STRING} ###length 2 @@ -1421,7 +1420,7 @@ STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :midten STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :den fjerneste ende STR_CONFIG_SETTING_AUTOSCROLL :Panorér vindue når musen er ved kanten: {STRING} -STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Når den er aktiveret, vil skærmbilledet begynde at rulle, når musen er nær kanten af skærmen +STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Når dette er aktiveret, vil skærmbilledet begynde at rulle, når musen er nær kanten af skærmen ###length 4 STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Deaktiveret STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Hoved visningsport, kun i fuldskærm @@ -1438,7 +1437,7 @@ STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Tillad køb af STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Hvis et firma køber eksklusive transport rettigheder til en by, vil modstandernes stationer (passagerer og fragt) ikke modtage nogen fragt i 12 måneder STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT_MINUTES :Hvis et firma køber eksklusive transport rettigheder til en by, vil modstandernes stationer (passagerer og fragt) ikke modtage nogen fragt i 12 minutter -STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Tillad sponsorer bygninger: {STRING} +STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Tillad sponsorering af bygninger: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Tillad firmaer til at give penge til byerne for finansiering af nye huse STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Tillad finansiering af vejfornyelse: {STRING} @@ -1450,7 +1449,7 @@ STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Tillad overfør STR_CONFIG_SETTING_FREIGHT_TRAINS :Vægtfaktor for fragt for at simulere tunge tog: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Indstil effekten af fragt i togene. En højere værdi gør fragt i togene mere krævende for tog, især på bakker -STR_CONFIG_SETTING_PLANE_SPEED :Fly hastigheds-faktor: {STRING} +STR_CONFIG_SETTING_PLANE_SPEED :Flys hastighedsfaktor: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Indstil den relative hastighed af fly i forhold til andre køretøjstyper, for at reducere mængden af indkomst for transport med fly STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} @@ -1458,7 +1457,7 @@ STR_CONFIG_SETTING_PLANE_CRASHES :Antal flystyrt: STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Angiv sandsynligheden for at fly styrter ned.{}* Store fly har altid en risiko for at styrte når de lander på små lufthavne. ###length 3 STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ingen* -STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :reduceret +STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduceret STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_CROSSING_WITH_COMPETITOR :Tillad vejkryds - jernbaneoverskæringer med veje eller skinner ejet af konkurrenter: {STRING} @@ -1485,7 +1484,7 @@ STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Aktiveres denne STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Advar hvis et faretøj bliver væk: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Få meddelelser om køretøjer, der ikke til at finde en vej til deres destination -STR_CONFIG_SETTING_ORDER_REVIEW :Kontroller køretøjers ordreliste: {STRING} +STR_CONFIG_SETTING_ORDER_REVIEW :Kontrollér køretøjers ordreliste: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Hvis aktiveret, bliver ordrerne af køretøjerne regelmæssigt kontrolleret, og nogle åbenlyse problemer rapporteres med en nyhedsmeddelelse når de opdages ###length 3 STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Nej @@ -1518,14 +1517,14 @@ STR_CONFIG_SETTING_MINUTES_PER_YEAR_FROZEN :0 (kalendertid STR_CONFIG_SETTING_TOWN_CARGO_SCALE :Skala bygodsproduktion: {STRING} STR_CONFIG_SETTING_TOWN_CARGO_SCALE_HELPTEXT :Skaler byernes godsproduktion med denne procentdel -STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE :Skaler industri gods produktion: {STRING} +STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE :Skalér industrigodsproduktion: {STRING} STR_CONFIG_SETTING_INDUSTRY_CARGO_SCALE_HELPTEXT :Skaler industriens gods produktion med denne procentdel STR_CONFIG_SETTING_CARGO_SCALE_VALUE :{NUM}% STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Automatisk fornyelse af gamle køretøjer: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Når aktiveret, bliver et køretøjder nærmer sig sin afslutning af livet automatisk udskiftet, når betingelserne er opfyldt -STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automatisk forny når køretøjets alder er {STRING} max alder +STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automatisk fornyelse når køretøjets alder er {STRING} max alder STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relativ alder, hvor et køretøj bør betragtes til automatisk fornyelse ###length 2 STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} måned{P 0 "" er} før @@ -1535,7 +1534,7 @@ STR_CONFIG_SETTING_AUTORENEW_MONEY :Min. kontanter STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimal mængde penge, der skal forblive i banken, før man overvejer automatisk fornyelse af køretøjer STR_CONFIG_SETTING_ERRMSG_DURATION :Varighed af fejlmeddelelse: {STRING} -STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Varighed for visning fejlmeddelelser i en rød vindue. Bemærk, at nogle (kritisk) fejlmeddelelser ikke lukkes automatisk efter dette tidspunkt, men skal lukkes manuelt +STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Varighed for visning af fejlmeddelelser i et rødt vindue. Bemærk, at nogle (kritiske) fejlmeddelelser ikke lukkes automatisk efter dette tidspunkt, men skal lukkes manuelt STR_CONFIG_SETTING_HOVER_DELAY :Vis værktøjstip: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Forsinkelse inden tooltips vises, når musen føres over nogle den grænseflade . Alternativt tooltips er bundet til den højre museknap, når denne værdi er sat til 0 @@ -1557,7 +1556,7 @@ STR_CONFIG_SETTING_SHOW_CARGO_IN_LISTS_HELPTEXT :Hvis det er akt STR_CONFIG_SETTING_LANDSCAPE :Landskab: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Landskaber definerer grundlæggende gameplay-scenarier med forskellige godstyper og krav for byers vækst. NewGRF og spilscripts giver dog mulighed for yderligere styring. -STR_CONFIG_SETTING_LAND_GENERATOR :Landskabs generator: {STRING} +STR_CONFIG_SETTING_LAND_GENERATOR :Landskabsgenerator: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Den oprindelige generator afhænger af basen grafik sæt, og komponerer faste landskab former. TerraGenesis er en Perlin baseret generator med finere kontrol indstillinger ###length 2 STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original @@ -1583,7 +1582,7 @@ STR_CONFIG_SETTING_DESERT_COVERAGE :Ørkendækning: STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Vælg den omtrentlige mængde ørken i det tropiske landskab. Ørken påvirker også industriproduktion og byvækstkrav. Bruges kun under kortgenerering STR_CONFIG_SETTING_DESERT_COVERAGE_VALUE :{NUM}% -STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Tærrenets hårdhed (kun TerraGenesis) : {STRING} +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Terrænets hårdhed (kun TerraGenesis) : {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :Vælg formen og antallet af bakker. Glatte landskaber har færre, bredere bakker, mens barske landskaber har flere mindre bakker ###length 4 STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Meget blødt @@ -1595,7 +1594,7 @@ STR_CONFIG_SETTING_VARIETY :Forskelligheds STR_CONFIG_SETTING_VARIETY_HELPTEXT :Vælg om kortet indeholder både bjerge og flade områder. Jo højere sorten er, jo flere højdeforskelle mellem bjergrige og flade områder STR_CONFIG_SETTING_RIVER_AMOUNT :Floder antal: {STRING} -STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Vælg, hvor mange floder at skabe +STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Vælg, hvor mange floder der skal skabes STR_CONFIG_SETTING_TREE_PLACER :Algoritme ved placering af træer: {STRING} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Vælg fordelingen af træer på kortet: "Original" planter træer ensartet spredt, "forbedret" planter dem i grupper @@ -1605,7 +1604,7 @@ STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Forbedret STR_CONFIG_SETTING_ROAD_SIDE :Vejkøretøjer: {STRING} -STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Vælg køre side +STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Vælg køreside ###length 2 STR_CONFIG_SETTING_ROAD_SIDE_LEFT :Kør i venstre side @@ -1632,7 +1631,7 @@ STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Forbind landska STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Når der åbnes for konstruktionsværktøjer for en transporttype, skal landskabsværktøjer også åbnes STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Land farve brugt i det lille kort: {STRING} -STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Land farve brugt i det lille kort +STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Landfarve brugt på det lille kort ###length 3 STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Grøn STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Mørkegrøn @@ -1649,7 +1648,7 @@ STR_CONFIG_SETTING_LINKGRAPH_COLOURS_GREYSCALE :Gråtoner STR_CONFIG_SETTING_SCROLLMODE :Visningsport bevægelse: {STRING} STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT :Virkemåde for bevægelse af kortet. "Museposition låst"-mulighederne virker ikke på alle systemer, såsom webbaserede versioner, berøringsskærme, Linux med Wayland og andre ###length 4 -STR_CONFIG_SETTING_SCROLLMODE_DEFAULT :Bevæg syns vinduet med højre mussetast, musse position låst +STR_CONFIG_SETTING_SCROLLMODE_DEFAULT :Bevæg synsvinduet med højre mussetast, musseposition låst STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Bevæg kortet med højre mussetast, musse position låst STR_CONFIG_SETTING_SCROLLMODE_RMB :Bevæg kortet med højre musseknap STR_CONFIG_SETTING_SCROLLMODE_LMB :Bevæg kortet med venstre musseknap @@ -1684,9 +1683,9 @@ STR_CONFIG_SETTING_OSK_ACTIVATION :Tillad skærmta STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Vælg hvordan skærmtastature åbnes ved indtasting i redigeringfelter kun med markør. Dette er beregnet til små enheder uden egentlig tastatur ###length 4 STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Deaktiveret -STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Dobbelt click -STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Enkelt click (når fokuseret) -STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Enkelt click (umiddelbart) +STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Dobbeltklik +STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Enkeltklik (når fokuseret) +STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Enkeltklik (umiddelbart) STR_CONFIG_SETTING_USE_RELAY_SERVICE :Anvend relæ-tjeneste: {STRING} STR_CONFIG_SETTING_USE_RELAY_SERVICE_HELPTEXT :Hvis det mislykkes at skabe forbindelse til serveren, er det muligt at anvende en relæ-tjeneste til at skabe en forbindelse. "Aldrig" forbyder dette, "spørg" vil spørge først, "tillad" vil tillade det uden at spørge. @@ -1825,7 +1824,7 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Tillad computer STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Tillad computerstyrede spillere at deltage i multiplayer spil STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes før scriptet bliver stoppet: {STRING} -STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximale nummer af udregninger et script kan eksekvere i en tur +STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximale antal udregninger et script kan eksekvere i en omgang STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Maks hukommelsesforbrug per script: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :Hvor meget hukommelse et enkelt script må anvende før det bliver tvungent afbrudt. Det kan være nødvendigt at forøge dette for spil på store kort STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB @@ -1901,7 +1900,7 @@ STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Nye køretøjer STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Vis en avis, når en ny køretøjstype bliver tilgængelig STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Ændring i accepteret fragt: {STRING} -STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Vis meddelelser om stationer som ændrer accept af nogen godstyper +STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Vis meddelelser om stationer som ændrer accept af nogle godstyper STR_CONFIG_SETTING_NEWS_SUBSIDIES :Tilskudsordninger: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Vis en avis om tilskuds relaterede begivenheder @@ -1914,7 +1913,7 @@ STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Kortfattet STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Fuld STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Farvede nyheder dukker op i: {STRING} -STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Året hvor nyheds-annonceringer bliver udskrevet i farver. Før dette år, bruger det sort / hvid +STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Året hvor nyhedsannonceringer bliver udskrevet i farver. Før dette år, bruger det sort / hvid STR_CONFIG_SETTING_STARTING_YEAR :Start dato: {STRING} STR_CONFIG_SETTING_ENDING_YEAR :Slutår for pointoptælling: {STRING} @@ -1935,7 +1934,7 @@ STR_CONFIG_SETTING_ECONOMY_TYPE_FROZEN :Frossen STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Procentdel af deloverskud som skal betales i hovedsystemer: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Procentdel af indkomst givet til de mellemliggende dele i hovedsystemer, giver mere kontrol over indkomst -STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Når der trækkes, placer signaler hvert: {STRING} +STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Når der trækkes, placér signaler hvert: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Indstil afstanden på hvilke signaler vil blive bygget på et spor op til den næste forhindring (signal, kryds), hvis signalerne trækkes STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} felt{P 0 "" er} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Når der trækkes, hold fastlagt afstand mellem signaler: {STRING} @@ -1998,7 +1997,7 @@ STR_CONFIG_SETTING_TOOLBAR_POS :Placering af v STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horisontal placering af hovedværktøjlinjen i toppen af skærmen STR_CONFIG_SETTING_STATUSBAR_POS :Position af statusbar: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horisontal placering af statuslinjen i bunden af skærmen -STR_CONFIG_SETTING_SNAP_RADIUS :Vinduers fastgørelses radius: {STRING} +STR_CONFIG_SETTING_SNAP_RADIUS :Vinduers fastgørelsesradius: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Afstanden mellem vinduer før vinduet automatisk flyttes på linje med det nærliggende vindue STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 "" s} ###setting-zero-is-special @@ -2029,7 +2028,7 @@ STR_CONFIG_SETTING_SPRITE_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_SPRITE_ZOOM_LVL_NORMAL :1x STR_CONFIG_SETTING_TOWN_GROWTH :Byvækst tempo: {STRING} -STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Hastigheden af by vækst +STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Hastigheden af byvækst ###length 5 STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Ingen STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Langsom @@ -2135,9 +2134,9 @@ STR_CONFIG_SETTING_VEHICLES_ROUTING :Ruteplanlægnin STR_CONFIG_SETTING_VEHICLES_ORDERS :Ordre STR_CONFIG_SETTING_LIMITATIONS :Begrænsninger STR_CONFIG_SETTING_ACCIDENTS :Katastrofer / Ulykker -STR_CONFIG_SETTING_GENWORLD :Verden generation +STR_CONFIG_SETTING_GENWORLD :Verdensgeneration STR_CONFIG_SETTING_ENVIRONMENT :Miljø -STR_CONFIG_SETTING_ENVIRONMENT_TIME :tid +STR_CONFIG_SETTING_ENVIRONMENT_TIME :Tid STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :Myndigheder STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :Byer STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :Industrier @@ -2158,7 +2157,7 @@ STR_CONFIG_ERROR_ARRAY :{WHITE}... fejl STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... ugyldig værdi '{STRING}' for '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... efterfølgende karakterer i slutningen af indstilling '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignorerer NewGRF '{STRING}': identisk GRF ID med '{STRING}' -STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignorer ugyldig NewGRF '{STRING}': {STRING} +STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignorér ugyldig NewGRF '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :ikke fundet STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :usikker til fast brug STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :system NewGRF @@ -2166,9 +2165,9 @@ STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :inkompatibel me STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :ukendt STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... komprimeringsniveau '{STRING}' er ikke gyldigt STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... savegame format '{STRING}' er ikke tilgængeligt. Går tilbage til '{STRING}' -STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignorere Basis Grafik sæt '{STRING}': ikke fundet -STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignorere Basis Lyde sæt '{STRING}': ikke fundet -STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignorere Basis Musik sæt '{STRING}': ikke fundet +STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignorér Basis Grafiksæt '{STRING}': ikke fundet +STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignorere Basis Lydsæt '{STRING}': ikke fundet +STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignorere Basis Musiksæt '{STRING}': ikke fundet STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Utilstrækkelig hukommelse STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Allokering af {BYTES} spritecache fejlede. Spritecachen blev indskrænket til {BYTES}. Dette vil sænke OpenTTDs ydelse. Du kan forsøge at slå 32bpp grafik og/eller zoom-ind niveauer for at reducere hukommelseskravet @@ -2230,8 +2229,8 @@ STR_QUIT_NO :{BLACK}Nej # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Forlad spillet -STR_ABANDON_GAME_QUERY :{YELLOW}Er du sikker på du vil forlade dette spil ? -STR_ABANDON_SCENARIO_QUERY :{YELLOW}Er du sikker på, at du vil afslutte dette scenarie ? +STR_ABANDON_GAME_QUERY :{YELLOW}Er du sikker på du vil forlade dette spil? +STR_ABANDON_SCENARIO_QUERY :{YELLOW}Er du sikker på, at du vil afslutte dette scenarie? # Help window STR_HELP_WINDOW_CAPTION :{WHITE}Hjælp og manualer @@ -2253,12 +2252,12 @@ STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Spiller STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magisk bulldozer (nedriv ting, som normalt ikke kan fjernes): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tunneler kan krydse hinanden: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Jetfly vil ikke styrte (ofte) i små lufthavne: {ORANGE}{STRING} -STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Rediger den maksimale map højde: {ORANGE}{NUM} +STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Rediger den maksimale korthøjde: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Rediger den maksimale højde af bjerge på kortet -STR_CHEAT_CHANGE_DATE :{LTBLUE}Ændre dato: {ORANGE}{DATE_SHORT} +STR_CHEAT_CHANGE_DATE :{LTBLUE}Ændr dato: {ORANGE}{DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Skift år STR_CHEAT_SETUP_PROD :{LTBLUE}Aktiver modifikation af produktion: {ORANGE}{STRING} -STR_CHEAT_STATION_RATING :{LTBLUE}Ret stationsvurderinger til 100 %: {ORANGE}{STRING} +STR_CHEAT_STATION_RATING :{LTBLUE}Sæt stationsvurderinger til 100 %: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}{COMPANY} - Farvetema @@ -2661,7 +2660,7 @@ STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Søg på STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Søgeresultat ikke tilgængeligt på OpenTTD's indholdstjeneste for websteder som ikke er associeret med OpenTTD STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Du forlader OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Betingelserne for download af indhold fra eksterne websteder varierer.{}Du må referere til de eksterne sites for vejledning i hvordan indholdet skal installeres i OpenTTD.{} Ønsker du at fortsætte? -STR_CONTENT_FILTER_TITLE :{BLACK}søge filter: +STR_CONTENT_FILTER_TITLE :{BLACK}søgefilter: STR_CONTENT_OPEN_URL :{BLACK}Besøg hjemmeside STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Besøg hjemmesiden for dette indhold STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Download @@ -2925,7 +2924,7 @@ STR_ROAD_NAME_TRAM :Sporvej # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Retning af værksted -STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Vælg retning for værksted +STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Vælg retning af værksted STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Retning af sporvognsremise STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Vælg retning af sporvognsremise @@ -2946,7 +2945,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Byg kana STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Byg en sluse. Shift skifter mellem at bygge og vise prisoverslag. STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Byg en skibsdok (til køb og servicering af skibe). Shift skifter mellem at bygge og vise prisoverslag. STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Byg en havn. Ctrl muliggør sammenslutning af stationer. Shift skifter mellem at bygge og vise prisoverslag. -STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Placer en bøje, der kan bruges som yderligere navigationspunkt. Shift skifter mellem at bygge og vise prisoverslag. +STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Placér en bøje, der kan bruges som yderligere navigationspunkt. Shift skifter mellem at bygge og vise prisoverslag. STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Byg akvædukt. Tryk også på Shift for kun at vise omkostningsestimat STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Lav en kanal, med mindre CTRL-tasten bruges ved havniveau, da omgivelserne i stedet vil blive oversvømmet STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Placér floder. Ctrl+klik markerer området diagonalt. @@ -2972,7 +2971,7 @@ STR_AIRPORT_SMALL :Lille STR_AIRPORT_CITY :By STR_AIRPORT_METRO :Metropollufthavn STR_AIRPORT_INTERNATIONAL :International lufthavn -STR_AIRPORT_COMMUTER :Pendler lufthavn +STR_AIRPORT_COMMUTER :Pendlerlufthavn STR_AIRPORT_INTERCONTINENTAL :Interkontinental STR_AIRPORT_HELIPORT :Helikopterlandingsplads STR_AIRPORT_HELIDEPOT :Helikopterværksted @@ -2980,8 +2979,8 @@ STR_AIRPORT_HELISTATION :Helikopterplads STR_AIRPORT_CLASS_SMALL :Små lufthavne STR_AIRPORT_CLASS_LARGE :Store lufthavne -STR_AIRPORT_CLASS_HUB :Central lufthavne -STR_AIRPORT_CLASS_HELIPORTS :Helikopter lufthavne +STR_AIRPORT_CLASS_HUB :Centrale lufthavne +STR_AIRPORT_CLASS_HELIPORTS :Helikopterlufthavne STR_STATION_BUILD_NOISE :{BLACK}Genereret støj: {GOLD}{COMMA} @@ -3818,7 +3817,7 @@ STR_STATION_VIEW_SUPPLY_RATINGS_TITLE_MONTH :{BLACK}Forsynin STR_STATION_VIEW_SUPPLY_RATINGS_TITLE_MINUTE :{BLACK}Forsyninger pr. minut og lokal vurdering: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) -STR_STATION_VIEW_GROUP :{BLACK}Gruppér på +STR_STATION_VIEW_GROUP :{BLACK}Gruppér efter STR_STATION_VIEW_WAITING_STATION :Station: Ventende STR_STATION_VIEW_WAITING_AMOUNT :Mængde: Ventende STR_STATION_VIEW_PLANNED_STATION :Station: Planlagt @@ -3869,7 +3868,7 @@ STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOIN STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centrer skærmen over rutepunktets lokalitet. Ctrl+Klik åbner et nyt vindue ved rutepunktets lokalitet. STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Omdøb rutepunkt STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centrér skærmen ved bøjens placering. Ctrl+klik åbner et nyt vindue ved bøjens placering -STR_BUOY_VIEW_RENAME_TOOLTIP :{BLACK}Ændre navnet på bøjen +STR_BUOY_VIEW_RENAME_TOOLTIP :{BLACK}Ændr navnet på bøjen STR_EDIT_WAYPOINT_NAME :{WHITE}Omdøb rutepunkt @@ -3971,14 +3970,14 @@ STR_BUY_COMPANY_HOSTILE_TAKEOVER :{WHITE}I en fje # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastruktur for {COMPANY} -STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spor-stykker: +STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Sporstykker: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler -STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vej-stykker: +STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Vejstykker: STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}Sporvejsdele: -STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vand-felter: +STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Vandfelter: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanaler STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stationer: -STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Station felter +STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Stationsfelter STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Lufthavne STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR :{WHITE}{CURRENCY_LONG}/år STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD :{WHITE}{CURRENCY_LONG}/periode @@ -4817,7 +4816,7 @@ STR_AI_DEBUG_SETTINGS :{BLACK}Indstill STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Skift indstillinger for computerspilleren STR_AI_DEBUG_RELOAD :{BLACK}Genindlæs computerspiller STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Stop computerspilleren, genindlæs scriptet og genstart computerspilleren -STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK} Aktiver / deaktiver breakpoint funktionen, når en AI logmeddelelsen er lig breakpoint tekststrengen +STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK} Aktiver / deaktiver breakpoint funktionen, når en AI logmeddelelsen er lig breakpoint-tekststrengen STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Breakpiont slået til: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Breakpoint slået til STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Når en computerspillers log besked er lig denne tekststreng, vil spillet gå på standby. @@ -4826,8 +4825,8 @@ STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Vis matc STR_AI_DEBUG_CONTINUE :{BLACK}Fortsæt STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Sæt spillet i gang, og start den kunstige intelligens igen STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Se fejlretningsoutput af denne AI. Ctrl-klik for at åbne i et nyt vindue -STR_AI_GAME_SCRIPT :{BLACK}Spil Script -STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Tjek SpilScript-loggen. Ctrl+klik for at åbne i et nyt vindue +STR_AI_GAME_SCRIPT :{BLACK}Spilscript +STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Tjek Spilscript-loggen. Ctrl+klik for at åbne i et nyt vindue STR_ERROR_AI_NO_AI_FOUND :Ingen passende AI kan findes.{}Denne AI er en pladsholder, og vil ikke gøre noget.{} Du kan downloade indtil flere AI'er fra 'Online Indhold'-systemet. STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}En af de kørende scripts gik ned. Rapporter det venligst til script-udvikleren sammen med et skærmbillede af AI/spilscript-debugvinduet. @@ -4873,7 +4872,7 @@ STR_AI_LIST_URL :{LTBLUE}URL: {O STR_AI_LIST_ACCEPT :{BLACK}Godkend STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Vælg markeret script STR_AI_LIST_CANCEL :{BLACK}Afbryd -STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Skift ikke script'et +STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Skift ikke scriptet STR_SCREENSHOT_CAPTION :{WHITE}Tag skærmbillede STR_SCREENSHOT_SCREENSHOT :{BLACK}Normalt skærmbillede @@ -4886,7 +4885,7 @@ STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Minikort # Script Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametre STR_AI_SETTINGS_CAPTION_AI :AI -STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Spil Script +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Spilscript STR_AI_SETTINGS_CLOSE :{BLACK}Luk STR_AI_SETTINGS_RESET :{BLACK}Nulstil STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} @@ -4960,7 +4959,7 @@ STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... kunn STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... billede er for stort -STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Skalerings advarsel +STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Skaleringsadvarsel STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}At ændre størrelsen på kildebilledet anbefales ikke. Fortsæt genereringen? # Soundset messages diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index c1cdf8f5f223f..d6992e291e1c2 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Steden generere STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Huizen plaatsen # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spelopties STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Instellingen STR_SETTINGS_MENU_AI_SETTINGS :AI-instellingen diff --git a/src/lang/english.txt b/src/lang/english.txt index 4244c77792660..ede50e8dda295 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generate towns STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Place houses # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Game options STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Settings STR_SETTINGS_MENU_AI_SETTINGS :AI settings @@ -453,6 +452,11 @@ STR_SETTINGS_MENU_SANDBOX_OPTIONS :Sandbox options STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparency options STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Town names displayed STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Station names displayed +STR_SETTINGS_MENU_STATION_NAMES_TRAIN :Train stations +STR_SETTINGS_MENU_STATION_NAMES_LORRY :Lorry stops +STR_SETTINGS_MENU_STATION_NAMES_BUS :Bus stops +STR_SETTINGS_MENU_STATION_NAMES_SHIP :Docks +STR_SETTINGS_MENU_STATION_NAMES_PLANE :Airports STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Waypoint names displayed STR_SETTINGS_MENU_SIGNS_DISPLAYED :Signs displayed STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Competitor signs and names displayed diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index 808d75090924d..0f8293ca1e9ba 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generate towns STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Place houses # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Game options STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Settings STR_SETTINGS_MENU_AI_SETTINGS :AI settings diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 4f9098ce84617..3eb890b4cc60e 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generate towns STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Place houses # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Game options STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Settings STR_SETTINGS_MENU_AI_SETTINGS :AI settings diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index 382f08ce8ab9b..6350529f3b561 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -522,7 +522,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Forlasi # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Ludaj agordoj STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Agordoj STR_SETTINGS_MENU_AI_SETTINGS :AI agordoj diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index ce5bfad19358d..782bb9f8efb52 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -497,7 +497,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Välju # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Mängu seadistus STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Seaded STR_SETTINGS_MENU_AI_SETTINGS :TI seaded diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 546a5b9cf97ee..efe874b59e521 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -363,7 +363,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Gevst # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spæl møguleikar STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF innstillingar STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Gjøgnumskygnis møguleikar diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 70e1a090b866f..4ac5a3c8a1bdb 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Luo kuntia STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Sijoita taloja # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Pelin valinnat STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Asetukset STR_SETTINGS_MENU_AI_SETTINGS :Tekoälyasetukset diff --git a/src/lang/french.txt b/src/lang/french.txt index bc4beb5dea06f..083ac603b2b34 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Générer des v STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Placer des maisons # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Options du Jeu STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Paramètres STR_SETTINGS_MENU_AI_SETTINGS :Configuration des IAs diff --git a/src/lang/frisian.txt b/src/lang/frisian.txt index 4171b6df5b81d..ed7a8738b0505 100644 --- a/src/lang/frisian.txt +++ b/src/lang/frisian.txt @@ -384,7 +384,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Ofslute # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spulopsjes STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Ynstellings STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF-ynstellings diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index f58b25d474983..6b08d1342d411 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -571,7 +571,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Fàg an-seo # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Roghainnean a' gheama STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Roghainnean STR_SETTINGS_MENU_NEWGRF_SETTINGS :Roghainnean NewGRF diff --git a/src/lang/galician.txt b/src/lang/galician.txt index e8328eb13db06..1bec26f481389 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Xerar vilas STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Colocar casas # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opcións do xogo STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Opcións STR_SETTINGS_MENU_AI_SETTINGS :Axustes da IA diff --git a/src/lang/german.txt b/src/lang/german.txt index 0e438ebd7ae58..02bd2777a52b8 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Städte erzeuge STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Häuser platzieren # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spieleinstellungen STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Einstellungen STR_SETTINGS_MENU_AI_SETTINGS :KI-Einstellungen diff --git a/src/lang/greek.txt b/src/lang/greek.txt index 9113654770062..b2230c5774a4f 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -505,7 +505,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Δημιουρ STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Τοποθέτηση σπιτιών # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Επιλογές παιχνιδιού STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Ρυθμίσεις STR_SETTINGS_MENU_AI_SETTINGS :Ρυθμίσεις AI diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index 920d36ed2126a..4e78f3d85b7e7 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -425,7 +425,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :יציאה # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :אפשרויות המשחק STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :הגדרות STR_SETTINGS_MENU_AI_SETTINGS :הגדרות בינה מלאכותית diff --git a/src/lang/hindi.txt b/src/lang/hindi.txt index 7d7302e4b2528..b76518574cb4a 100644 --- a/src/lang/hindi.txt +++ b/src/lang/hindi.txt @@ -157,7 +157,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :निकास # Settings menu -###length 16 STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :समायोजन STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :पथ-संकेतों के नाम दिखायें STR_SETTINGS_MENU_TRANSPARENT_SIGNS :पारदर्शी संकेत diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index ad4843bf18ec2..98746046ffd00 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -505,7 +505,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Városok gener STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Házak elhelyezése # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Játékbeállítások STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Beállítások STR_SETTINGS_MENU_AI_SETTINGS :MI Beállítások diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index bc3f5f3c280da..b9e0bf47f9998 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -363,7 +363,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Hætta # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Stillingar STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF stillingar STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Gegnsæisstillingar diff --git a/src/lang/ido.txt b/src/lang/ido.txt index 65c3d47dedb2e..ae1d5f1512bca 100644 --- a/src/lang/ido.txt +++ b/src/lang/ido.txt @@ -295,7 +295,6 @@ STR_SCENEDIT_FILE_MENU_SEPARATOR : # Settings menu -###length 16 STR_SETTINGS_MENU_FULL_DETAIL :Plene detaloza STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Diafana konstrukturi diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index 12ef1e1b40f84..5e7f5bf3fe0b6 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -435,7 +435,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Keluar # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Pengaturan permainan STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Pengaturan STR_SETTINGS_MENU_AI_SETTINGS :Pengaturan AI diff --git a/src/lang/irish.txt b/src/lang/irish.txt index f0b16bcaa6f29..f3423aa16b6b2 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -398,7 +398,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Scoir # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Roghanna an chluiche STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Socruithe STR_SETTINGS_MENU_NEWGRF_SETTINGS :Socruithe NewGRF diff --git a/src/lang/italian.txt b/src/lang/italian.txt index d5fc873b921e3..347563f62145d 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generare città STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Mette case # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opzioni gioco STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Impostazioni STR_SETTINGS_MENU_AI_SETTINGS :Impostazioni IA diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 954446e72c02a..29569d5ac8b04 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -430,7 +430,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :OpenTTDを終 # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :ゲームオプション設定 STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :設定 STR_SETTINGS_MENU_AI_SETTINGS :AI設定 diff --git a/src/lang/korean.txt b/src/lang/korean.txt index e3cef2cb29ad7..c7cdef01820dc 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :도시 생성 STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :건물 건설 # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :게임 기본 설정 STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :설정 STR_SETTINGS_MENU_AI_SETTINGS :인공지능 설정 @@ -5098,7 +5097,7 @@ STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... 통 STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}역의 일부를 제거할 수 없습니다... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}철도역을 먼저 제거하세요 STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}버스 정류장을 제거할 수 없습니다... -STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}트럭 터미널을 제거할 수 없습니다... +STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}트럭 적하장을 제거할 수 없습니다... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}여객 전차역을 제거할 수 없습니다... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}화물 전차역을 제거할 수 없습니다... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}정류장을 먼저 제거하세요 diff --git a/src/lang/latin.txt b/src/lang/latin.txt index 7761d488e0943..a27d59c2a92fd 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -573,7 +573,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Exire # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Ludi optiones STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Electiones STR_SETTINGS_MENU_NEWGRF_SETTINGS :Optiones NewGRF diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index e449003f00392..dd861daa9ff4b 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -445,7 +445,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Izveidot pilsē STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Novietojiet mājas # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spēles opcijas STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Iestatījumi STR_SETTINGS_MENU_AI_SETTINGS :AI iestatījumi diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt index 7aefb89b6f7b3..c77194cd899ce 100644 --- a/src/lang/lithuanian.txt +++ b/src/lang/lithuanian.txt @@ -628,7 +628,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Išeiti # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Pagrindinės nuostatos STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Išplėstinės nuostatos STR_SETTINGS_MENU_AI_SETTINGS :DI nustatymai diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index 98ee8aa8f7966..9a357593aa443 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Stied generéir STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Haiser plazéiren # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spilloptiounen STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Astellungen STR_SETTINGS_MENU_AI_SETTINGS :KI Astellungen diff --git a/src/lang/macedonian.txt b/src/lang/macedonian.txt index c18366dd106e5..dd1727670bf98 100644 --- a/src/lang/macedonian.txt +++ b/src/lang/macedonian.txt @@ -361,7 +361,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Напушти # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :игра опции STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF подесувања STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :транспарентност опции diff --git a/src/lang/malay.txt b/src/lang/malay.txt index 636a116d3c516..8e8277a224474 100644 --- a/src/lang/malay.txt +++ b/src/lang/malay.txt @@ -366,7 +366,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Keluar # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Pilihan permainan STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Tetapan STR_SETTINGS_MENU_NEWGRF_SETTINGS :Tetapan NewGRF diff --git a/src/lang/maltese.txt b/src/lang/maltese.txt index c8780ec2d0f43..67fc0183e5663 100644 --- a/src/lang/maltese.txt +++ b/src/lang/maltese.txt @@ -275,7 +275,6 @@ STR_SCENEDIT_FILE_MENU_SEPARATOR : # Settings menu -###length 16 # File menu diff --git a/src/lang/marathi.txt b/src/lang/marathi.txt index e081de1170b83..8578e8a3eaa9d 100644 --- a/src/lang/marathi.txt +++ b/src/lang/marathi.txt @@ -355,7 +355,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :बंद क # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :खेळाचे पर्याय STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF पर्याय STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :पारदर्शकता पर्याय diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 1f08f52250476..96e8bb73c3015 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -445,7 +445,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generer byer STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Plasser hus # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spillinnstillinger STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Innstillinger STR_SETTINGS_MENU_AI_SETTINGS :KI-innstilinger diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt index 170ca46b420cd..fb1962cc3d620 100644 --- a/src/lang/norwegian_nynorsk.txt +++ b/src/lang/norwegian_nynorsk.txt @@ -389,7 +389,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Avslutt # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spelinstillingar STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Innstillinger STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF-innstillingar diff --git a/src/lang/persian.txt b/src/lang/persian.txt index fbaf81009ec3e..b9a78639181f3 100644 --- a/src/lang/persian.txt +++ b/src/lang/persian.txt @@ -379,7 +379,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :خروج # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :تنظیمات بازی STR_SETTINGS_MENU_NEWGRF_SETTINGS :تنظیمات NewGRF STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :گزینه های شفافیت diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 7c479ae562ba5..ddbaa1a380977 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -822,7 +822,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Tworzenie miast STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Stawianie budynków # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opcje gry STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Ustawienia STR_SETTINGS_MENU_AI_SETTINGS :Ustawienia SI diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 454e2b0a85d02..bd43e7b381a84 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Gerar localidad STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Colocar casas # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opções do Jogo STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Definições STR_SETTINGS_MENU_AI_SETTINGS :Definições de IA @@ -1317,7 +1316,7 @@ STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Configurar o n STR_CONFIG_SETTING_RECESSIONS :Recessões: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Se ativo, podem ocorrer recessões periodicamente. Durante uma recessão a produção em geral é mais baixa (e regressa aos níveis anteriores quando termina a recessão) -STR_CONFIG_SETTING_TRAIN_REVERSING :Desabilitar inversão de combóios nas estações: {STRING} +STR_CONFIG_SETTING_TRAIN_REVERSING :Desabilitar inversão de comboios nas estações: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Quando ativo, os comboios não podem inverter marcha em estações não-terminais, mesmo se existir um caminho mais curto para o próximo destino ao inverter STR_CONFIG_SETTING_DISASTERS :Desastres: {STRING} diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index 426ed4ec96924..ee6be24a439b1 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -442,7 +442,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :{BLACK}Generaț STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Plasează case # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opțiunile jocului STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Setări STR_SETTINGS_MENU_AI_SETTINGS :Setările AI diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 05d384f0fc9d9..9da9fd4634269 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -569,7 +569,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Создани STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Размещение зданий # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Основные настройки STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Расширенные настройки STR_SETTINGS_MENU_AI_SETTINGS :Настройки ИИ diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt index 2630767505692..8506021621d80 100644 --- a/src/lang/serbian.txt +++ b/src/lang/serbian.txt @@ -623,7 +623,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Izađi # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opcije STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Podešavanja STR_SETTINGS_MENU_AI_SETTINGS :Podešavanja VI diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index 26030758dc45d..bf0e0452bbe7c 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :生成城镇 STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :放置房屋 # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :游戏选项 STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :设置 STR_SETTINGS_MENU_AI_SETTINGS :AI 设置 diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index 98a437d690280..16b01c4456178 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -504,7 +504,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Ukončiť # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Možnosti hry STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Nastavenia STR_SETTINGS_MENU_AI_SETTINGS :Nastavenia AI diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index d9e94fdbd4163..5bb5a93b6bbcc 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -537,7 +537,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Izhod # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Možnosti igre STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Nastavitve STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF nastavitve diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 14f343d71ba6b..32d7d80e06842 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generar municip STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Colocar edificios # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opciones de juego STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Configuración STR_SETTINGS_MENU_AI_SETTINGS :Configuración de IA diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index dbd0e214ad2c0..7cf82fb39174a 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -444,7 +444,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generar localid STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Colocar edificios # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Opciones de juego STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Configuración STR_SETTINGS_MENU_AI_SETTINGS :Configuración de IA diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 1e7df69921073..0e4fdc01bd825 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Generera städe STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Placera ut hus # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Spelinställningar STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Inställningar STR_SETTINGS_MENU_AI_SETTINGS :Inställningar för AI diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index 98a82e5b09de4..9a066be57e782 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -438,7 +438,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :வெளிய # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :விளையாட்டு விருப்ப பேரம் STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :அமைப்புகள் STR_SETTINGS_MENU_AI_SETTINGS :AI அமைப்புகள் diff --git a/src/lang/thai.txt b/src/lang/thai.txt index 70fa9454ee9a6..91bf06142d2d9 100644 --- a/src/lang/thai.txt +++ b/src/lang/thai.txt @@ -388,7 +388,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :ออก # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :ตัวเลือกเกม STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :การตั้งค่า STR_SETTINGS_MENU_NEWGRF_SETTINGS :กำหนดค่า NewGRF diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index 99e0c770110ed..f97a86b1d872b 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :生成市鎮 STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :設置房屋 # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :遊戲選項 STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :設定 STR_SETTINGS_MENU_AI_SETTINGS :AI 設定 diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index a3e8dec0cf246..357881651aa60 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -441,7 +441,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :Oyundan Çık # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Seçenekler STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Ayarlar STR_SETTINGS_MENU_AI_SETTINGS :YZ ayarları diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index add1462265f22..a2d5026891852 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -576,7 +576,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Генерув STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Розміщення будинків # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Налаштування гри STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Налаштування STR_SETTINGS_MENU_AI_SETTINGS :Налаштування ШІ diff --git a/src/lang/urdu.txt b/src/lang/urdu.txt index ee80d6fc37b95..ae4582949314b 100644 --- a/src/lang/urdu.txt +++ b/src/lang/urdu.txt @@ -369,7 +369,6 @@ STR_SCENEDIT_FILE_MENU_QUIT :باہر نکل # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :کھیل کے اختیارات STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF اختیارات STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparency کے اختیارات diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index e5863254a6e8d..b393a42880e7f 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -443,7 +443,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Khởi tạo đ STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Sắp xếp nhà # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Cấu hình trò chơi STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Thiết Lập STR_SETTINGS_MENU_AI_SETTINGS :Thiết lập AI diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index 0ba51dea24aac..af3427ff311d5 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -442,7 +442,6 @@ STR_SCENEDIT_TOWN_MENU_BUILD_TOWN :Cynhyrchu trefi STR_SCENEDIT_TOWN_MENU_PACE_HOUSE :Gosod tai # Settings menu -###length 16 STR_SETTINGS_MENU_GAME_OPTIONS :Dewisiadau Gêm STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Gosodiadau STR_SETTINGS_MENU_AI_SETTINGS :Gosodiadau AI diff --git a/src/map.cpp b/src/map.cpp index c69ef4eadfe72..322c3879a3d18 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -24,8 +24,8 @@ /* static */ uint Map::size; ///< The number of tiles on the map /* static */ uint Map::tile_mask; ///< _map_size - 1 (to mask the mapsize) -/* static */ Tile::TileBase *Tile::base_tiles = nullptr; ///< Base tiles of the map -/* static */ Tile::TileExtended *Tile::extended_tiles = nullptr; ///< Extended tiles of the map +/* static */ std::unique_ptr Tile::base_tiles; ///< Base tiles of the map +/* static */ std::unique_ptr Tile::extended_tiles; ///< Extended tiles of the map /** @@ -53,11 +53,8 @@ Map::size = size_x * size_y; Map::tile_mask = Map::size - 1; - free(Tile::base_tiles); - free(Tile::extended_tiles); - - Tile::base_tiles = CallocT(Map::size); - Tile::extended_tiles = CallocT(Map::size); + Tile::base_tiles = std::make_unique(Map::size); + Tile::extended_tiles = std::make_unique(Map::size); AllocateWaterRegions(); } diff --git a/src/map_func.h b/src/map_func.h index b97df21c06099..45a5a3ee98b97 100644 --- a/src/map_func.h +++ b/src/map_func.h @@ -30,13 +30,13 @@ class Tile { * Look at docs/landscape.html for the exact meaning of the members. */ struct TileBase { - uint8_t type; ///< The type (bits 4..7), bridges (2..3), rainforest/desert (0..1) - uint8_t height; ///< The height of the northern corner. - uint16_t m2; ///< Primarily used for indices to towns, industries and stations - uint8_t m1; ///< Primarily used for ownership information - uint8_t m3; ///< General purpose - uint8_t m4; ///< General purpose - uint8_t m5; ///< General purpose + uint8_t type = 0; ///< The type (bits 4..7), bridges (2..3), rainforest/desert (0..1) + uint8_t height = 0; ///< The height of the northern corner. + uint16_t m2 = 0; ///< Primarily used for indices to towns, industries and stations + uint8_t m1 = 0; ///< Primarily used for ownership information + uint8_t m3 = 0; ///< General purpose + uint8_t m4 = 0; ///< General purpose + uint8_t m5 = 0; ///< General purpose }; static_assert(sizeof(TileBase) == 8); @@ -46,13 +46,13 @@ class Tile { * Look at docs/landscape.html for the exact meaning of the members. */ struct TileExtended { - uint8_t m6; ///< General purpose - uint8_t m7; ///< Primarily used for newgrf support - uint16_t m8; ///< General purpose + uint8_t m6 = 0; ///< General purpose + uint8_t m7 = 0; ///< Primarily used for newgrf support + uint16_t m8 = 0; ///< General purpose }; - static TileBase *base_tiles; ///< Pointer to the tile-array. - static TileExtended *extended_tiles; ///< Pointer to the extended tile-array. + static std::unique_ptr base_tiles; ///< Pointer to the tile-array. + static std::unique_ptr extended_tiles; ///< Pointer to the extended tile-array. TileIndex tile; ///< The tile to access the map data for. diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index 62e8854b449ae..2916cc78a5617 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -325,12 +325,11 @@ class NetworkGameWindow : public Window { /** Set this->list_pos to match this->server */ void UpdateListPos() { - this->list_pos = SLP_INVALID; - for (uint i = 0; i != this->servers.size(); i++) { - if (this->servers[i] == this->server) { - this->list_pos = i; - break; - } + auto it = std::ranges::find(this->servers, this->server); + if (it == std::end(this->servers)) { + this->list_pos = SLP_INVALID; + } else { + this->list_pos = static_cast(std::distance(std::begin(this->servers), it)); } } diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 3e76a943bb1f6..daa8344feaf0f 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -83,7 +83,7 @@ static uint32_t _ttdpatch_flags[8]; /** Indicates which are the newgrf features currently loaded ingame */ GRFLoadedFeatures _loaded_newgrf_features; -static const uint MAX_SPRITEGROUP = UINT8_MAX; ///< Maximum GRF-local ID for a spritegroup. +static constexpr uint MAX_SPRITEGROUP = GB(UINT16_MAX, 0, 15); ///< Maximum GRF-local ID for a spritegroup. /** Temporary data during loading of GRFs */ struct GrfProcessingState { @@ -101,6 +101,7 @@ struct GrfProcessingState { /* Global state */ GrfLoadingStage stage; ///< Current loading stage SpriteID spriteid; ///< First available SpriteID for loading realsprites. + uint8_t grf_version; ///< GRF version /* Local state in the file */ SpriteFile *file; ///< File of currently processed GRF file. @@ -112,7 +113,7 @@ struct GrfProcessingState { int skip_sprites; ///< Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file) /* Currently referenceable spritegroups */ - const SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1]; + std::unordered_map spritegroups; /** Clear temporary data before processing the next file in the current loading stage */ void ClearDataForNextFile() @@ -124,7 +125,7 @@ struct GrfProcessingState { this->spritesets[i].clear(); } - memset(this->spritegroups, 0, sizeof(this->spritegroups)); + spritegroups.clear(); } /** @@ -248,6 +249,9 @@ class ByteReader { uint16_t ReadExtendedByte() { + /* In GRFv9, all extended bytes become words. */ + if (_cur.grf_version >= 9) return this->ReadWord(); + uint16_t val = ReadByte(); return val == 0xFF ? ReadWord() : val; } @@ -264,6 +268,14 @@ class ByteReader { return this->ReadDWord(); } + uint16_t ReadID() + { + /* In GRFv9, many id-related bytes become words. */ + if (_cur.grf_version >= 9) return this->ReadWord(); + + return this->ReadByte(); + } + uint32_t ReadVarSize(uint8_t size) { switch (size) { @@ -324,7 +336,7 @@ struct GRFTempEngineData { CargoClasses cargo_allowed_required; ///< Bitmask of cargo classes that are required to be all present to allow a cargo as a refit. CargoClasses cargo_disallowed; ///< Bitmask of cargo classes that are disallowed as a refit. RailTypeLabel railtypelabel; - uint8_t roadtramtype; + uint16_t roadtramtype; const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'. Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied. uint8_t rv_max_speed; ///< Temporary storage of RV prop 15, maximum speed in mph/0.8 @@ -1002,10 +1014,11 @@ enum ChangeInfoResult { CIR_DISABLED, ///< GRF was disabled due to error CIR_UNHANDLED, ///< Variable was parsed but unread CIR_UNKNOWN, ///< Variable is unknown + CIR_REMOVED, ///< Property did exist but has been removed. CIR_INVALID_ID, ///< Attempt to modify an invalid ID }; -typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader &buf); +using ChangeInfoHandler = ChangeInfoResult(uint first, uint last, int prop, ByteReader &buf); /** * Define properties common to all vehicles @@ -1051,18 +1064,18 @@ static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteRe /** * Define properties for rail vehicles - * @param engine :ocal ID of the first vehicle. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first vehicle. + * @param last Local ID of the last vehicle. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - for (int i = 0; i < numinfo; i++) { - Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, engine + i); + for (uint id = first; id < last; ++id) { + Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -1070,7 +1083,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop switch (prop) { case 0x05: { // Track type - uint8_t tracktype = buf.ReadByte(); + uint16_t tracktype = buf.ReadID(); if (tracktype < _cur.grffile->railtype_list.size()) { _gted[e->index].railtypelabel = _cur.grffile->railtype_list[tracktype]; @@ -1158,10 +1171,11 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop case 0x15: { // Cargo type _gted[e->index].defaultcargo_grf = _cur.grffile; - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); - if (ctype == 0xFF) { - /* 0xFF is specified as 'use first refittable' */ + if (_cur.grf_version < 9 && ctype == UINT8_MAX) ctype = UINT16_MAX; + if (ctype == UINT16_MAX) { + /* 0xFF/0xFFFF is specified as 'use first refittable' */ ei->cargo_type = INVALID_CARGO; } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ @@ -1234,6 +1248,7 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop break; case 0x1D: { // Refit cargo + if (_cur.grf_version >= 9) return CIR_REMOVED; uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); @@ -1316,13 +1331,13 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop case 0x2C: // CTT refit include list case 0x2D: { // CTT refit exclude list - uint8_t count = buf.ReadByte(); + uint16_t count = buf.ReadID(); _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0); if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur.grffile; CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoID ctype = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (IsValidCargoID(ctype)) SetBit(ctt, ctype); } break; @@ -1359,18 +1374,18 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop /** * Define properties for road vehicles - * @param engine Local ID of the first vehicle. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first vehicle. + * @param last Local ID of the last vehicle. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - for (int i = 0; i < numinfo; i++) { - Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, engine + i); + for (uint id = first; id < last; ++id) { + Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -1380,7 +1395,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop case 0x05: // Road/tram type /* RoadTypeLabel is looked up later after the engine's road/tram * flag is set, however 0 means the value has not been set. */ - _gted[e->index].roadtramtype = buf.ReadByte() + 1; + _gted[e->index].roadtramtype = buf.ReadID() + 1; break; case 0x08: // Speed (1 unit is 0.5 kmh) @@ -1419,10 +1434,11 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop case 0x10: { // Cargo type _gted[e->index].defaultcargo_grf = _cur.grffile; - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); - if (ctype == 0xFF) { - /* 0xFF is specified as 'use first refittable' */ + if (_cur.grf_version < 9 && ctype == UINT8_MAX) ctype = UINT16_MAX; + if (ctype == UINT16_MAX) { + /* 0xFF/0xFFFF is specified as 'use first refittable' */ ei->cargo_type = INVALID_CARGO; } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ @@ -1438,7 +1454,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop break; case 0x12: // SFX - rvi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte()); + rvi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadID()); break; case PROP_ROADVEH_POWER: // Power in units of 10 HP. @@ -1454,6 +1470,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop break; case 0x16: { // Cargoes available for refitting + if (_cur.grf_version >= 9) return CIR_REMOVED; uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); @@ -1525,13 +1542,13 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop case 0x24: // CTT refit include list case 0x25: { // CTT refit exclude list - uint8_t count = buf.ReadByte(); + uint16_t count = buf.ReadID(); _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0); if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur.grffile; CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoID ctype = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (IsValidCargoID(ctype)) SetBit(ctt, ctype); } break; @@ -1564,18 +1581,18 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop /** * Define properties for ships - * @param engine Local ID of the first vehicle. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first vehicle. + * @param last Local ID of the last vehicle. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - for (int i = 0; i < numinfo; i++) { - Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, engine + i); + for (uint id = first; id < last; ++id) { + Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -1614,10 +1631,11 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop case 0x0C: { // Cargo type _gted[e->index].defaultcargo_grf = _cur.grffile; - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); - if (ctype == 0xFF) { - /* 0xFF is specified as 'use first refittable' */ + if (_cur.grf_version < 9 && ctype == UINT8_MAX) ctype = UINT16_MAX; + if (ctype == UINT16_MAX) { + /* 0xFF/0xFFFF is specified as 'use first refittable' */ ei->cargo_type = INVALID_CARGO; } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ @@ -1637,10 +1655,11 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop break; case 0x10: // SFX - svi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte()); + svi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadID()); break; case 0x11: { // Cargoes available for refitting + if (_cur.grf_version >= 9) return CIR_REMOVED; uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); @@ -1708,13 +1727,13 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop case 0x1E: // CTT refit include list case 0x1F: { // CTT refit exclude list - uint8_t count = buf.ReadByte(); + uint16_t count = buf.ReadID(); _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0); if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur.grffile; CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoID ctype = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (IsValidCargoID(ctype)) SetBit(ctt, ctype); } break; @@ -1755,18 +1774,18 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop /** * Define properties for aircraft - * @param engine Local ID of the aircraft. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first vehicle. + * @param last Local ID of the last vehicle. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - for (int i = 0; i < numinfo; i++) { - Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, engine + i); + for (uint id = first; id < last; ++id) { + Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -1828,10 +1847,11 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int break; case 0x12: // SFX - avi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte()); + avi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadID()); break; case 0x13: { // Cargoes available for refitting + if (_cur.grf_version >= 9) return CIR_REMOVED; uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); @@ -1881,13 +1901,13 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int case 0x1D: // CTT refit include list case 0x1E: { // CTT refit exclude list - uint8_t count = buf.ReadByte(); + uint16_t count = buf.ReadID(); _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0); if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur.grffile; CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoID ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoID ctype = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (IsValidCargoID(ctype)) SetBit(ctt, ctype); } break; @@ -1924,30 +1944,30 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int /** * Define properties for stations - * @param stid StationID of the first station tile. - * @param numinfo Number of subsequent station tiles to change the property for. + * @param first Local ID of the first station. + * @param last Local ID of the last station. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (stid + numinfo > NUM_STATIONS_PER_GRF) { - GrfMsg(1, "StationChangeInfo: Station {} is invalid, max {}, ignoring", stid + numinfo, NUM_STATIONS_PER_GRF); + if (last > NUM_STATIONS_PER_GRF) { + GrfMsg(1, "StationChangeInfo: Station {} is invalid, max {}, ignoring", last, NUM_STATIONS_PER_GRF); return CIR_INVALID_ID; } /* Allocate station specs if necessary */ - if (_cur.grffile->stations.size() < stid + numinfo) _cur.grffile->stations.resize(stid + numinfo); + if (_cur.grffile->stations.size() < last) _cur.grffile->stations.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &statspec = _cur.grffile->stations[stid + i]; + for (uint id = first; id < last; ++id) { + auto &statspec = _cur.grffile->stations[id]; /* Check that the station we are modifying is defined. */ if (statspec == nullptr && prop != 0x08) { - GrfMsg(2, "StationChangeInfo: Attempt to modify undefined station {}, ignoring", stid + i); + GrfMsg(2, "StationChangeInfo: Attempt to modify undefined station {}, ignoring", id); return CIR_INVALID_ID; } @@ -2008,7 +2028,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte /* Number of layouts must be even, alternating X and Y */ if (statspec->renderdata.size() & 1) { - GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", stid + i); + GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", id); statspec->renderdata.pop_back(); } break; @@ -2019,7 +2039,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get(); if (srcstatspec == nullptr) { - GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy sprite layout to {}.", srcid, stid + i); + GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy sprite layout to {}.", srcid, id); continue; } @@ -2073,7 +2093,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get(); if (srcstatspec == nullptr) { - GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy tile layout to {}.", srcid, stid + i); + GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy tile layout to {}.", srcid, id); continue; } @@ -2099,7 +2119,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte } case 0x12: // Cargo types for random triggers - if (_cur.grffile->grf_version >= 7) { + if (_cur.grf_version >= 7) { statspec->cargo_triggers = TranslateRefitMask(buf.ReadDWord()); } else { statspec->cargo_triggers = (CargoTypes)buf.ReadDWord(); @@ -2165,7 +2185,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte /* Number of layouts must be even, alternating X and Y */ if (statspec->renderdata.size() & 1) { - GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", stid + i); + GrfMsg(1, "StationChangeInfo: Station {} defines an odd number of sprite layouts, dropping the last item", id); statspec->renderdata.pop_back(); } break; @@ -2204,23 +2224,23 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte /** * Define properties for water features - * @param id Type of the first water feature. - * @param numinfo Number of subsequent water feature ids to change the property for. + * @param first Local ID of the first water feature. + * @param last Local ID of the last water feature. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult CanalChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (id + numinfo > CF_END) { - GrfMsg(1, "CanalChangeInfo: Canal feature 0x{:02X} is invalid, max {}, ignoring", id + numinfo, CF_END); + if (last > CF_END) { + GrfMsg(1, "CanalChangeInfo: Canal feature 0x{:02X} is invalid, max {}, ignoring", last, CF_END); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { - CanalProperties *cp = &_cur.grffile->canal_local_properties[id + i]; + for (uint id = first; id < last; ++id) { + CanalProperties *cp = &_cur.grffile->canal_local_properties[id]; switch (prop) { case 0x08: @@ -2242,23 +2262,23 @@ static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteRead /** * Define properties for bridges - * @param brid BridgeID of the bridge. - * @param numinfo Number of subsequent bridgeIDs to change the property for. + * @param first Local ID of the first bridge. + * @param last Local ID of the last bridge. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult BridgeChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (brid + numinfo > MAX_BRIDGES) { - GrfMsg(1, "BridgeChangeInfo: Bridge {} is invalid, max {}, ignoring", brid + numinfo, MAX_BRIDGES); + if (last > MAX_BRIDGES) { + GrfMsg(1, "BridgeChangeInfo: Bridge {} is invalid, max {}, ignoring", last, MAX_BRIDGES); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { - BridgeSpec *bridge = &_bridge[brid + i]; + for (uint id = first; id < last; ++id) { + BridgeSpec *bridge = &_bridge[id]; switch (prop) { case 0x08: { // Year of availability @@ -2363,12 +2383,15 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader &buf) ChangeInfoResult ret = CIR_SUCCESS; switch (prop) { - case 0x09: - case 0x0B: - case 0x0C: case 0x0D: case 0x0E: case 0x0F: + if (_cur.grf_version >= 9) return CIR_REMOVED; + [[fallthrough]]; + + case 0x09: + case 0x0B: + case 0x0C: case 0x11: case 0x14: case 0x15: @@ -2393,6 +2416,7 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader &buf) break; case 0x1E: + if (_cur.grf_version >= 9) return CIR_REMOVED; buf.ReadDWord(); break; @@ -2401,14 +2425,21 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader &buf) break; case 0x20: { - uint8_t count = buf.ReadByte(); - for (uint8_t j = 0; j < count; j++) buf.ReadByte(); + uint16_t count = buf.ReadID(); + for (uint16_t j = 0; j < count; j++) { + buf.ReadID(); + } break; } - case 0x23: - buf.Skip(buf.ReadByte() * 2); + case 0x23: { + uint16_t count = buf.ReadID(); + for (uint16_t j = 0; j < count; ++j) { + buf.ReadID(); + buf.ReadByte(); + } break; + } default: ret = CIR_UNKNOWN; @@ -2419,26 +2450,26 @@ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader &buf) /** * Define properties for houses - * @param hid HouseID of the house. - * @param numinfo Number of subsequent houseIDs to change the property for. + * @param first Local ID of the first house. + * @param last Local ID of the last house. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (hid + numinfo > NUM_HOUSES_PER_GRF) { - GrfMsg(1, "TownHouseChangeInfo: Too many houses loaded ({}), max ({}). Ignoring.", hid + numinfo, NUM_HOUSES_PER_GRF); + if (last > NUM_HOUSES_PER_GRF) { + GrfMsg(1, "TownHouseChangeInfo: Too many houses loaded ({}), max ({}). Ignoring.", last, NUM_HOUSES_PER_GRF); return CIR_INVALID_ID; } /* Allocate house specs if they haven't been allocated already. */ - if (_cur.grffile->housespec.size() < hid + numinfo) _cur.grffile->housespec.resize(hid + numinfo); + if (_cur.grffile->housespec.size() < last) _cur.grffile->housespec.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &housespec = _cur.grffile->housespec[hid + i]; + for (uint id = first; id < last; ++id) { + auto &housespec = _cur.grffile->housespec[id]; if (prop != 0x08 && housespec == nullptr) { /* If the house property 08 is not yet set, ignore this property */ @@ -2453,11 +2484,11 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt if (subs_id == 0xFF) { /* Instead of defining a new house, a substitute house id * of 0xFF disables the old house with the current id. */ - if (hid + i < NEW_HOUSE_OFFSET) HouseSpec::Get(hid + i)->enabled = false; + if (id < NEW_HOUSE_OFFSET) HouseSpec::Get(id)->enabled = false; continue; } else if (subs_id >= NEW_HOUSE_OFFSET) { /* The substitute id must be one of the original houses. */ - GrfMsg(2, "TownHouseChangeInfo: Attempt to use new house {} as substitute house for {}. Ignoring.", subs_id, hid + i); + GrfMsg(2, "TownHouseChangeInfo: Attempt to use new house {} as substitute house for {}. Ignoring.", subs_id, id); continue; } @@ -2467,7 +2498,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt housespec = std::make_unique(*HouseSpec::Get(subs_id)); housespec->enabled = true; - housespec->grf_prop.local_id = hid + i; + housespec->grf_prop.local_id = id; housespec->grf_prop.subst_id = subs_id; housespec->grf_prop.grfid = _cur.grffile->grfid; housespec->grf_prop.grffile = _cur.grffile; @@ -2514,10 +2545,12 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt case 0x0D: // Passenger acceptance case 0x0E: // Mail acceptance + if (_cur.grf_version >= 9) return CIR_REMOVED; housespec->cargo_acceptance[prop - 0x0D] = buf.ReadByte(); break; case 0x0F: { // Goods/candy, food/fizzy drinks acceptance + if (_cur.grf_version >= 9) return CIR_REMOVED; int8_t goods = buf.ReadByte(); /* If value of goods is negative, it means in fact food or, if in toyland, fizzy_drink acceptance. @@ -2559,11 +2592,11 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt /* The house being overridden must be an original house. */ if (override >= NEW_HOUSE_OFFSET) { - GrfMsg(2, "TownHouseChangeInfo: Attempt to override new house {} with house id {}. Ignoring.", override, hid + i); + GrfMsg(2, "TownHouseChangeInfo: Attempt to override new house {} with house id {}. Ignoring.", override, id); continue; } - _house_mngr.Add(hid + i, _cur.grffile->grfid, override); + _house_mngr.Add(id, _cur.grffile->grfid, override); break; } @@ -2602,6 +2635,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt break; case 0x1E: { // Accepted cargo types + if (_cur.grf_version >= 9) return CIR_REMOVED; uint32_t cargotypes = buf.ReadDWord(); /* Check if the cargo types should not be changed */ @@ -2609,7 +2643,8 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt for (uint j = 0; j < HOUSE_ORIGINAL_NUM_ACCEPTS; j++) { /* Get the cargo number from the 'list' */ - uint8_t cargo_part = GB(cargotypes, 8 * j, 8); + uint16_t cargo_part = GB(cargotypes, 8 * j, 8); + if (cargo_part == UINT8_MAX) cargo_part = UINT16_MAX; CargoID cargo = GetCargoTranslation(cargo_part, _cur.grffile); if (!IsValidCargoID(cargo)) { @@ -2628,9 +2663,9 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt break; case 0x20: { // Cargo acceptance watch list - uint8_t count = buf.ReadByte(); - for (uint8_t j = 0; j < count; j++) { - CargoID cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + uint16_t count = buf.ReadID(); + for (uint j = 0; j < count; j++) { + CargoID cargo = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (IsValidCargoID(cargo)) SetBit(housespec->watched_cargoes, cargo); } break; @@ -2646,7 +2681,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt break; case 0x23: { // variable length cargo types accepted - uint count = buf.ReadByte(); + uint count = buf.ReadID(); if (count > lengthof(housespec->accepts_cargo)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG); error->param_value[1] = prop; @@ -2657,7 +2692,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt * any risks of array overrun. */ for (uint i = 0; i < lengthof(housespec->accepts_cargo); i++) { if (i < count) { - housespec->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + housespec->accepts_cargo[i] = GetCargoTranslation(buf.ReadID(), _cur.grffile); housespec->cargo_acceptance[i] = buf.ReadByte(); } else { housespec->accepts_cargo[i] = INVALID_CARGO; @@ -2697,25 +2732,25 @@ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, Byt /** * Load a cargo- or railtype-translation table. - * @param gvid ID of the global variable. This is basically only checked for zerones. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first ID of the first translation table entry. + * @param last ID of the last translation table entry. * @param buf The property value. * @param gettable Function to get storage for the translation table. * @param name Name of the table for debug output. * @return ChangeInfoResult. */ template -static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader &buf, TGetTableFunc gettable, std::string_view name) +static ChangeInfoResult LoadTranslationTable(uint first, uint last, ByteReader &buf, TGetTableFunc gettable, std::string_view name) { - if (gvid != 0) { + if (first != 0) { GrfMsg(1, "LoadTranslationTable: {} translation table must start at zero", name); return CIR_INVALID_ID; } std::vector &translation_table = gettable(*_cur.grffile); translation_table.clear(); - translation_table.reserve(numinfo); - for (int i = 0; i < numinfo; i++) { + translation_table.reserve(last); + for (uint id = first; id < last; ++id) { translation_table.push_back(T(BSWAP32(buf.ReadDWord()))); } @@ -2745,27 +2780,27 @@ static std::string ReadDWordAsString(ByteReader &reader) /** * Define properties for global variables - * @param gvid ID of the global variable. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first ID of the first global var. + * @param last ID of the last global var. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, ByteReader &buf) { /* Properties which are handled as a whole */ switch (prop) { case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.cargo_list; }, "Cargo"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.cargo_list; }, "Cargo"); case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.railtype_list; }, "Rail type"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.railtype_list; }, "Rail type"); case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.roadtype_list; }, "Road type"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.roadtype_list; }, "Road type"); case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.tramtype_list; }, "Tram type"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.tramtype_list; }, "Tram type"); default: break; @@ -2773,22 +2808,21 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By /* Properties which are handled per item */ ChangeInfoResult ret = CIR_SUCCESS; - for (int i = 0; i < numinfo; i++) { + for (uint id = first; id < last; ++id) { switch (prop) { case 0x08: { // Cost base factor int factor = buf.ReadByte(); - uint price = gvid + i; - if (price < PR_END) { - _cur.grffile->price_base_multipliers[price] = std::min(factor - 8, MAX_PRICE_MODIFIER); + if (id < PR_END) { + _cur.grffile->price_base_multipliers[id] = std::min(factor - 8, MAX_PRICE_MODIFIER); } else { - GrfMsg(1, "GlobalVarChangeInfo: Price {} out of range, ignoring", price); + GrfMsg(1, "GlobalVarChangeInfo: Price {} out of range, ignoring", id); } break; } case 0x0A: { // Currency display names - uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); + uint curidx = GetNewgrfCurrencyIdConverted(id); if (curidx < CURRENCY_END) { AddStringForMapping(GRFStringID{buf.ReadWord()}, [curidx](StringID str) { _currency_specs[curidx].name = str; @@ -2801,7 +2835,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } case 0x0B: { // Currency multipliers - uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); + uint curidx = GetNewgrfCurrencyIdConverted(id); uint32_t rate = buf.ReadDWord(); if (curidx < CURRENCY_END) { @@ -2816,7 +2850,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } case 0x0C: { // Currency options - uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); + uint curidx = GetNewgrfCurrencyIdConverted(id); uint16_t options = buf.ReadWord(); if (curidx < CURRENCY_END) { @@ -2832,7 +2866,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } case 0x0D: { // Currency prefix symbol - uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); + uint curidx = GetNewgrfCurrencyIdConverted(id); std::string prefix = ReadDWordAsString(buf); if (curidx < CURRENCY_END) { @@ -2844,7 +2878,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } case 0x0E: { // Currency suffix symbol - uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); + uint curidx = GetNewgrfCurrencyIdConverted(id); std::string suffix = ReadDWordAsString(buf); if (curidx < CURRENCY_END) { @@ -2856,7 +2890,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } case 0x0F: { // Euro introduction dates - uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); + uint curidx = GetNewgrfCurrencyIdConverted(id); TimerGameCalendar::Year year_euro{buf.ReadWord()}; if (curidx < CURRENCY_END) { @@ -2868,29 +2902,33 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By } case 0x10: // Snow line height table - if (numinfo > 1 || IsSnowLineSet()) { - GrfMsg(1, "GlobalVarChangeInfo: The snowline can only be set once ({})", numinfo); + if (last > 1 || IsSnowLineSet()) { + GrfMsg(1, "GlobalVarChangeInfo: The snowline can only be set once ({})", last); } else if (buf.Remaining() < SNOW_LINE_MONTHS * SNOW_LINE_DAYS) { GrfMsg(1, "GlobalVarChangeInfo: Not enough entries set in the snowline table ({})", buf.Remaining()); } else { - uint8_t table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]; + auto snow_line = std::make_unique(); for (uint i = 0; i < SNOW_LINE_MONTHS; i++) { for (uint j = 0; j < SNOW_LINE_DAYS; j++) { - table[i][j] = buf.ReadByte(); - if (_cur.grffile->grf_version >= 8) { - if (table[i][j] != 0xFF) table[i][j] = table[i][j] * (1 + _settings_game.construction.map_height_limit) / 256; + uint8_t &level = snow_line->table[i][j]; + level = buf.ReadByte(); + if (_cur.grf_version >= 8) { + if (level != 0xFF) level = level * (1 + _settings_game.construction.map_height_limit) / 256; } else { - if (table[i][j] >= 128) { + if (level >= 128) { /* no snow */ - table[i][j] = 0xFF; + level = 0xFF; } else { - table[i][j] = table[i][j] * (1 + _settings_game.construction.map_height_limit) / 128; + level = level * (1 + _settings_game.construction.map_height_limit) / 128; } } + + snow_line->highest_value = std::max(snow_line->highest_value, level); + snow_line->lowest_value = std::min(snow_line->lowest_value, level); } } - SetSnowLine(table); + SetSnowLine(std::move(snow_line)); } break; @@ -2903,7 +2941,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By case 0x13: // Gender translation table case 0x14: // Case translation table case 0x15: { // Plural form translation - uint curidx = gvid + i; // The current index, i.e. language. + uint curidx = id; // The current index, i.e. language. const LanguageMetadata *lang = curidx < MAX_LANG ? GetLanguage(curidx) : nullptr; if (lang == nullptr) { GrfMsg(1, "GlobalVarChangeInfo: Language {} is not known, ignoring", curidx); @@ -2971,21 +3009,21 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, By return ret; } -static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult GlobalVarReserveInfo(uint first, uint last, int prop, ByteReader &buf) { /* Properties which are handled as a whole */ switch (prop) { case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.cargo_list; }, "Cargo"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.cargo_list; }, "Cargo"); case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.railtype_list; }, "Rail type"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.railtype_list; }, "Rail type"); case 0x16: // Road type translation table; loading during both reservation and activation stage (in case it is selected depending on defined roadtypes) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.roadtype_list; }, "Road type"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.roadtype_list; }, "Road type"); case 0x17: // Tram type translation table; loading during both reservation and activation stage (in case it is selected depending on defined tramtypes) - return LoadTranslationTable(gvid, numinfo, buf, [](GRFFile &grf) -> std::vector & { return grf.tramtype_list; }, "Tram type"); + return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.tramtype_list; }, "Tram type"); default: break; @@ -2993,7 +3031,8 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B /* Properties which are handled per item */ ChangeInfoResult ret = CIR_SUCCESS; - for (int i = 0; i < numinfo; i++) { + + for (uint id = first; id < last; ++id) { switch (prop) { case 0x08: // Cost base factor case 0x15: // Plural form translation @@ -3042,32 +3081,32 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, B /** * Define properties for cargoes - * @param cid Local ID of the cargo. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first ID of the first cargo. + * @param last ID of the last cargo. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult CargoChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (cid + numinfo > NUM_CARGO) { - GrfMsg(2, "CargoChangeInfo: Cargo type {} out of range (max {})", cid + numinfo, NUM_CARGO - 1); + if (last > NUM_CARGO) { + GrfMsg(2, "CargoChangeInfo: Cargo type {} out of range (max {})", last, NUM_CARGO - 1); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { - CargoSpec *cs = CargoSpec::Get(cid + i); + for (uint id = first; id < last; ++id) { + CargoSpec *cs = CargoSpec::Get(id); switch (prop) { case 0x08: // Bit number of cargo cs->bitnum = buf.ReadByte(); if (cs->IsValid()) { cs->grffile = _cur.grffile; - SetBit(_cargo_mask, cid + i); + SetBit(_cargo_mask, id); } else { - ClrBit(_cargo_mask, cid + i); + ClrBit(_cargo_mask, id); } BuildCargoLabelMap(); break; @@ -3200,13 +3239,13 @@ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteRea /** * Define properties for sound effects - * @param sid Local ID of the sound. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first sound. + * @param last Local ID of the last sound. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult SoundEffectChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; @@ -3215,13 +3254,13 @@ static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, B return CIR_INVALID_ID; } - if (sid + numinfo - ORIGINAL_SAMPLE_COUNT > _cur.grffile->num_sounds) { - GrfMsg(1, "SoundEffectChangeInfo: Attempting to change undefined sound effect ({}), max ({}). Ignoring.", sid + numinfo, ORIGINAL_SAMPLE_COUNT + _cur.grffile->num_sounds); + if (last - ORIGINAL_SAMPLE_COUNT > _cur.grffile->num_sounds) { + GrfMsg(1, "SoundEffectChangeInfo: Attempting to change undefined sound effect ({}), max ({}). Ignoring.", last, ORIGINAL_SAMPLE_COUNT + _cur.grffile->num_sounds); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { - SoundEntry *sound = GetSound(sid + i + _cur.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT); + for (uint id = first; id < last; ++id) { + SoundEntry *sound = GetSound(first + _cur.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT); switch (prop) { case 0x08: // Relative volume @@ -3278,13 +3317,21 @@ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader &buf) case 0x0A: case 0x0B: case 0x0C: + if (_cur.grf_version >= 9) return CIR_REMOVED; + [[fallthrough]]; + case 0x0F: buf.ReadWord(); break; - case 0x13: - buf.Skip(buf.ReadByte() * 2); + case 0x13: { + uint16_t count = buf.ReadID(); + for (uint16_t j = 0; j < count; ++j) { + buf.ReadID(); + buf.ReadByte(); + } break; + } default: ret = CIR_UNKNOWN; @@ -3295,26 +3342,26 @@ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader &buf) /** * Define properties for industry tiles - * @param indtid Local ID of the industry tile. - * @param numinfo Number of subsequent industry tile IDs to change the property for. + * @param first Local ID of the first industry tile. + * @param last Local ID of the last industry tile. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (indtid + numinfo > NUM_INDUSTRYTILES_PER_GRF) { - GrfMsg(1, "IndustryTilesChangeInfo: Too many industry tiles loaded ({}), max ({}). Ignoring.", indtid + numinfo, NUM_INDUSTRYTILES_PER_GRF); + if (last > NUM_INDUSTRYTILES_PER_GRF) { + GrfMsg(1, "IndustryTilesChangeInfo: Too many industry tiles loaded ({}), max ({}). Ignoring.", last, NUM_INDUSTRYTILES_PER_GRF); return CIR_INVALID_ID; } /* Allocate industry tile specs if they haven't been allocated already. */ - if (_cur.grffile->indtspec.size() < indtid + numinfo) _cur.grffile->indtspec.resize(indtid + numinfo); + if (_cur.grffile->indtspec.size() < last) _cur.grffile->indtspec.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &tsp = _cur.grffile->indtspec[indtid + i]; + for (uint id = first; id < last; ++id) { + auto &tsp = _cur.grffile->indtspec[id]; if (prop != 0x08 && tsp == nullptr) { ChangeInfoResult cir = IgnoreIndustryTileProperty(prop, buf); @@ -3327,7 +3374,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr uint8_t subs_id = buf.ReadByte(); if (subs_id >= NEW_INDUSTRYTILEOFFSET) { /* The substitute id must be one of the original industry tile. */ - GrfMsg(2, "IndustryTilesChangeInfo: Attempt to use new industry tile {} as substitute industry tile for {}. Ignoring.", subs_id, indtid + i); + GrfMsg(2, "IndustryTilesChangeInfo: Attempt to use new industry tile {} as substitute industry tile for {}. Ignoring.", subs_id, id); continue; } @@ -3343,11 +3390,11 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr tsp->anim_production = INDUSTRYTILE_NOANIM; tsp->anim_next = INDUSTRYTILE_NOANIM; - tsp->grf_prop.local_id = indtid + i; + tsp->grf_prop.local_id = id; tsp->grf_prop.subst_id = subs_id; tsp->grf_prop.grfid = _cur.grffile->grfid; tsp->grf_prop.grffile = _cur.grffile; - _industile_mngr.AddEntityID(indtid + i, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot + _industile_mngr.AddEntityID(id, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot } break; } @@ -3357,17 +3404,19 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr /* The industry being overridden must be an original industry. */ if (ovrid >= NEW_INDUSTRYTILEOFFSET) { - GrfMsg(2, "IndustryTilesChangeInfo: Attempt to override new industry tile {} with industry tile id {}. Ignoring.", ovrid, indtid + i); + GrfMsg(2, "IndustryTilesChangeInfo: Attempt to override new industry tile {} with industry tile id {}. Ignoring.", ovrid, id); continue; } - _industile_mngr.Add(indtid + i, _cur.grffile->grfid, ovrid); + _industile_mngr.Add(id, _cur.grffile->grfid, ovrid); break; } case 0x0A: // Tile acceptance case 0x0B: case 0x0C: { + if (_cur.grf_version >= 9) return CIR_REMOVED; + uint16_t acctp = buf.ReadWord(); tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur.grffile); tsp->acceptance[prop - 0x0A] = Clamp(GB(acctp, 8, 8), 0, 16); @@ -3401,7 +3450,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr break; case 0x13: { // variable length cargo acceptance - uint8_t num_cargoes = buf.ReadByte(); + uint16_t num_cargoes = buf.ReadID(); if (num_cargoes > std::size(tsp->acceptance)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG); error->param_value[1] = prop; @@ -3409,7 +3458,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr } for (uint i = 0; i < std::size(tsp->acceptance); i++) { if (i < num_cargoes) { - tsp->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + tsp->accepts_cargo[i] = GetCargoTranslation(buf.ReadID(), _cur.grffile); /* Tile acceptance can be negative to counteract the INDTILE_SPECIAL_ACCEPTS_ALL_CARGO flag */ tsp->acceptance[i] = (int8_t)buf.ReadByte(); } else { @@ -3441,10 +3490,13 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader &buf) ChangeInfoResult ret = CIR_SUCCESS; switch (prop) { + case 0x12: + if (_cur.grf_version >= 9) return CIR_REMOVED; + [[fallthrough]]; + case 0x09: case 0x0B: case 0x0F: - case 0x12: case 0x13: case 0x14: case 0x17: @@ -3455,10 +3507,13 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader &buf) buf.ReadByte(); break; + case 0x10: // INDUSTRY_ORIGINAL_NUM_OUTPUTS bytes + if (_cur.grf_version >= 9) return CIR_REMOVED; + [[fallthrough]]; + case 0x0C: case 0x0D: case 0x0E: - case 0x10: // INDUSTRY_ORIGINAL_NUM_OUTPUTS bytes case 0x1B: case 0x1F: case 0x24: @@ -3466,10 +3521,13 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader &buf) break; case 0x11: // INDUSTRY_ORIGINAL_NUM_INPUTS bytes + 1 - case 0x1A: case 0x1C: case 0x1D: case 0x1E: + if (_cur.grf_version >= 9) return CIR_REMOVED; + [[fallthrough]]; + + case 0x1A: case 0x20: case 0x23: buf.ReadDWord(); @@ -3502,10 +3560,21 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader &buf) case 0x15: case 0x25: - case 0x26: - case 0x27: - buf.Skip(buf.ReadByte()); + case 0x26: { + uint16_t count = buf.ReadID(); + for (uint16_t j = 0; j < count; ++j) { + buf.ReadID(); + } + break; + } + + case 0x27: { + uint16_t count = buf.ReadID(); + for (uint16_t j = 0; j < count; ++j) { + buf.ReadByte(); + } break; + } case 0x28: { int num_inputs = buf.ReadByte(); @@ -3553,26 +3622,26 @@ static bool ValidateIndustryLayout(const IndustryTileLayout &layout) /** * Define properties for industries - * @param indid Local ID of the industry. - * @param numinfo Number of subsequent industry IDs to change the property for. + * @param first Local ID of the first industry. + * @param last Local ID of the last industry. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (indid + numinfo > NUM_INDUSTRYTYPES_PER_GRF) { - GrfMsg(1, "IndustriesChangeInfo: Too many industries loaded ({}), max ({}). Ignoring.", indid + numinfo, NUM_INDUSTRYTYPES_PER_GRF); + if (last > NUM_INDUSTRYTYPES_PER_GRF) { + GrfMsg(1, "IndustriesChangeInfo: Too many industries loaded ({}), max ({}). Ignoring.", last, NUM_INDUSTRYTYPES_PER_GRF); return CIR_INVALID_ID; } /* Allocate industry specs if they haven't been allocated already. */ - if (_cur.grffile->industryspec.size() < indid + numinfo) _cur.grffile->industryspec.resize(indid + numinfo); + if (_cur.grffile->industryspec.size() < last) _cur.grffile->industryspec.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &indsp = _cur.grffile->industryspec[indid + i]; + for (uint id = first; id < last; ++id) { + auto &indsp = _cur.grffile->industryspec[id]; if (prop != 0x08 && indsp == nullptr) { ChangeInfoResult cir = IgnoreIndustryProperty(prop, buf); @@ -3586,11 +3655,11 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, if (subs_id == 0xFF) { /* Instead of defining a new industry, a substitute industry id * of 0xFF disables the old industry with the current id. */ - _industry_specs[indid + i].enabled = false; + _industry_specs[id].enabled = false; continue; } else if (subs_id >= NEW_INDUSTRYOFFSET) { /* The substitute id must be one of the original industry. */ - GrfMsg(2, "_industry_specs: Attempt to use new industry {} as substitute industry for {}. Ignoring.", subs_id, indid + i); + GrfMsg(2, "_industry_specs: Attempt to use new industry {} as substitute industry for {}. Ignoring.", subs_id, id); continue; } @@ -3601,7 +3670,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, indsp = std::make_unique(_origin_industry_specs[subs_id]); indsp->enabled = true; - indsp->grf_prop.local_id = indid + i; + indsp->grf_prop.local_id = id; indsp->grf_prop.subst_id = subs_id; indsp->grf_prop.grfid = _cur.grffile->grfid; indsp->grf_prop.grffile = _cur.grffile; @@ -3617,11 +3686,11 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, /* The industry being overridden must be an original industry. */ if (ovrid >= NEW_INDUSTRYOFFSET) { - GrfMsg(2, "IndustriesChangeInfo: Attempt to override new industry {} with industry id {}. Ignoring.", ovrid, indid + i); + GrfMsg(2, "IndustriesChangeInfo: Attempt to override new industry {} with industry id {}. Ignoring.", ovrid, id); continue; } indsp->grf_prop.override = ovrid; - _industry_mngr.Add(indid + i, _cur.grffile->grfid, ovrid); + _industry_mngr.Add(id, _cur.grffile->grfid, ovrid); break; } @@ -3638,7 +3707,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, for (uint k = 0;; k++) { if (bytes_read >= definition_size) { - GrfMsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry {}.", indid); + GrfMsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry {}.", id); /* Avoid warning twice */ definition_size = UINT32_MAX; } @@ -3655,12 +3724,12 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, bytes_read += 2; if (type >= lengthof(_origin_industry_specs)) { - GrfMsg(1, "IndustriesChangeInfo: Invalid original industry number for layout import, industry {}", indid); + GrfMsg(1, "IndustriesChangeInfo: Invalid original industry number for layout import, industry {}", id); DisableGrf(STR_NEWGRF_ERROR_INVALID_ID); return CIR_DISABLED; } if (laynbr >= _origin_industry_specs[type].layouts.size()) { - GrfMsg(1, "IndustriesChangeInfo: Invalid original industry layout index for layout import, industry {}", indid); + GrfMsg(1, "IndustriesChangeInfo: Invalid original industry layout index for layout import, industry {}", id); DisableGrf(STR_NEWGRF_ERROR_INVALID_ID); return CIR_DISABLED; } @@ -3689,7 +3758,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid); if (tempid == INVALID_INDUSTRYTILE) { - GrfMsg(2, "IndustriesChangeInfo: Attempt to use industry tile {} with industry id {}, not yet defined. Ignoring.", local_tile_id, indid); + GrfMsg(2, "IndustriesChangeInfo: Attempt to use industry tile {} with industry id {}, not yet defined. Ignoring.", local_tile_id, id); } else { /* Declared as been valid, can be used */ it.gfx = tempid; @@ -3705,13 +3774,13 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, * Since GRF version 8 the position is interpreted as pair of independent int8. * For GRF version < 8 we need to emulate the old shifting behaviour. */ - if (_cur.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1; + if (_cur.grf_version < 8 && it.ti.x < 0) it.ti.y += 1; } } if (!ValidateIndustryLayout(layout)) { /* The industry layout was not valid, so skip this one. */ - GrfMsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id {}. Ignoring", indid); + GrfMsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id {}. Ignoring", id); new_num_layouts--; j--; } else { @@ -3745,6 +3814,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, break; case 0x10: // Production cargo types + if (_cur.grf_version >= 9) return CIR_REMOVED; for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_OUTPUTS; j++) { indsp->produced_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); indsp->produced_cargo_label[j] = CT_INVALID; @@ -3752,6 +3822,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, break; case 0x11: // Acceptance cargo types + if (_cur.grf_version >= 9) return CIR_REMOVED; for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_INPUTS; j++) { indsp->accepts_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); indsp->accepts_cargo_label[j] = CT_INVALID; @@ -3761,6 +3832,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, case 0x12: // Production multipliers case 0x13: + if (_cur.grf_version >= 9) return CIR_REMOVED; indsp->production_rate[prop - 0x12] = buf.ReadByte(); break; @@ -3769,12 +3841,12 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, break; case 0x15: { // Random sound effects - uint8_t num_sounds = buf.ReadByte(); + uint16_t num_sounds = buf.ReadID(); - std::vector sounds; + std::vector sounds; sounds.reserve(num_sounds); - for (uint8_t j = 0; j < num_sounds; ++j) { - sounds.push_back(buf.ReadByte()); + for (uint16_t j = 0; j < num_sounds; ++j) { + sounds.push_back(buf.ReadID()); } indsp->random_sounds = std::move(sounds); @@ -3808,11 +3880,12 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, case 0x1C: // Input cargo multipliers for the three input cargo types case 0x1D: case 0x1E: { - uint32_t multiples = buf.ReadDWord(); - indsp->input_cargo_multiplier[prop - 0x1C][0] = GB(multiples, 0, 16); - indsp->input_cargo_multiplier[prop - 0x1C][1] = GB(multiples, 16, 16); - break; - } + if (_cur.grf_version >= 9) return CIR_REMOVED; + uint32_t multiples = buf.ReadDWord(); + indsp->input_cargo_multiplier[prop - 0x1C][0] = GB(multiples, 0, 16); + indsp->input_cargo_multiplier[prop - 0x1C][1] = GB(multiples, 16, 16); + break; + } case 0x1F: // Industry name AddStringForMapping(GRFStringID{buf.ReadWord()}, &indsp->name); @@ -3844,7 +3917,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } case 0x25: { // variable length produced cargoes - uint8_t num_cargoes = buf.ReadByte(); + uint16_t num_cargoes = buf.ReadID(); if (num_cargoes > std::size(indsp->produced_cargo)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG); error->param_value[1] = prop; @@ -3852,7 +3925,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } for (size_t i = 0; i < std::size(indsp->produced_cargo); i++) { if (i < num_cargoes) { - CargoID cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoID cargo = GetCargoTranslation(buf.ReadID(), _cur.grffile); indsp->produced_cargo[i] = cargo; } else { indsp->produced_cargo[i] = INVALID_CARGO; @@ -3863,7 +3936,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } case 0x26: { // variable length accepted cargoes - uint8_t num_cargoes = buf.ReadByte(); + uint16_t num_cargoes = buf.ReadID(); if (num_cargoes > std::size(indsp->accepts_cargo)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG); error->param_value[1] = prop; @@ -3871,7 +3944,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } for (size_t i = 0; i < std::size(indsp->accepts_cargo); i++) { if (i < num_cargoes) { - CargoID cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoID cargo = GetCargoTranslation(buf.ReadID(), _cur.grffile); indsp->accepts_cargo[i] = cargo; } else { indsp->accepts_cargo[i] = INVALID_CARGO; @@ -3882,7 +3955,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, } case 0x27: { // variable length production rates - uint8_t num_cargoes = buf.ReadByte(); + uint16_t num_cargoes = buf.ReadID(); if (num_cargoes > lengthof(indsp->production_rate)) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG); error->param_value[1] = prop; @@ -3927,29 +4000,29 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, /** * Define properties for airports - * @param airport Local ID of the airport. - * @param numinfo Number of subsequent airport IDs to change the property for. + * @param first Local ID of the first airport. + * @param last Local ID of the last airport. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (airport + numinfo > NUM_AIRPORTS_PER_GRF) { - GrfMsg(1, "AirportChangeInfo: Too many airports, trying id ({}), max ({}). Ignoring.", airport + numinfo, NUM_AIRPORTS_PER_GRF); + if (last > NUM_AIRPORTS_PER_GRF) { + GrfMsg(1, "AirportChangeInfo: Too many airports, trying id ({}), max ({}). Ignoring.", last, NUM_AIRPORTS_PER_GRF); return CIR_INVALID_ID; } /* Allocate industry specs if they haven't been allocated already. */ - if (_cur.grffile->airportspec.size() < airport + numinfo) _cur.grffile->airportspec.resize(airport + numinfo); + if (_cur.grffile->airportspec.size() < last) _cur.grffile->airportspec.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &as = _cur.grffile->airportspec[airport + i]; + for (uint id = first; id < last; ++id) { + auto &as = _cur.grffile->airportspec[id]; if (as == nullptr && prop != 0x08 && prop != 0x09) { - GrfMsg(2, "AirportChangeInfo: Attempt to modify undefined airport {}, ignoring", airport + i); + GrfMsg(2, "AirportChangeInfo: Attempt to modify undefined airport {}, ignoring", id); return CIR_INVALID_ID; } @@ -3959,11 +4032,11 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B if (subs_id == 0xFF) { /* Instead of defining a new airport, an airport id * of 0xFF disables the old airport with the current id. */ - AirportSpec::GetWithoutOverride(airport + i)->enabled = false; + AirportSpec::GetWithoutOverride(id)->enabled = false; continue; } else if (subs_id >= NEW_AIRPORT_OFFSET) { /* The substitute id must be one of the original airports. */ - GrfMsg(2, "AirportChangeInfo: Attempt to use new airport {} as substitute airport for {}. Ignoring.", subs_id, airport + i); + GrfMsg(2, "AirportChangeInfo: Attempt to use new airport {} as substitute airport for {}. Ignoring.", subs_id, id); continue; } @@ -3974,12 +4047,12 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B as = std::make_unique(*AirportSpec::GetWithoutOverride(subs_id)); as->enabled = true; - as->grf_prop.local_id = airport + i; + as->grf_prop.local_id = id; as->grf_prop.subst_id = subs_id; as->grf_prop.grfid = _cur.grffile->grfid; as->grf_prop.grffile = _cur.grffile; /* override the default airport */ - _airport_mngr.Add(airport + i, _cur.grffile->grfid, subs_id); + _airport_mngr.Add(id, _cur.grffile->grfid, subs_id); } break; } @@ -4019,7 +4092,7 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid); if (tempid == INVALID_AIRPORTTILE) { - GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, airport + i); + GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, id); } else { /* Declared as been valid, can be used */ tile.gfx = tempid; @@ -4127,26 +4200,26 @@ static ChangeInfoResult IgnoreObjectProperty(uint prop, ByteReader &buf) /** * Define properties for objects - * @param id Local ID of the object. - * @param numinfo Number of subsequent objectIDs to change the property for. + * @param first Local ID of the first object. + * @param last Local ID of the last object. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult ObjectChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (id + numinfo > NUM_OBJECTS_PER_GRF) { - GrfMsg(1, "ObjectChangeInfo: Too many objects loaded ({}), max ({}). Ignoring.", id + numinfo, NUM_OBJECTS_PER_GRF); + if (last > NUM_OBJECTS_PER_GRF) { + GrfMsg(1, "ObjectChangeInfo: Too many objects loaded ({}), max ({}). Ignoring.", last, NUM_OBJECTS_PER_GRF); return CIR_INVALID_ID; } /* Allocate object specs if they haven't been allocated already. */ - if (_cur.grffile->objectspec.size() < id + numinfo) _cur.grffile->objectspec.resize(id + numinfo); + if (_cur.grffile->objectspec.size() < last) _cur.grffile->objectspec.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &spec = _cur.grffile->objectspec[id + i]; + for (uint id = first; id < last; ++id) { + auto &spec = _cur.grffile->objectspec[id]; if (prop != 0x08 && spec == nullptr) { /* If the object property 08 is not yet set, ignore this property */ @@ -4186,7 +4259,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea case 0x0C: // Size spec->size = buf.ReadByte(); if (GB(spec->size, 0, 4) == 0 || GB(spec->size, 4, 4) == 0) { - GrfMsg(0, "ObjectChangeInfo: Invalid object size requested (0x{:X}) for object id {}. Ignoring.", spec->size, id + i); + GrfMsg(0, "ObjectChangeInfo: Invalid object size requested (0x{:X}) for object id {}. Ignoring.", spec->size, id); spec->size = OBJECT_SIZE_1X1; } break; @@ -4237,7 +4310,7 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea case 0x17: // Views spec->views = buf.ReadByte(); if (spec->views != 1 && spec->views != 2 && spec->views != 4) { - GrfMsg(2, "ObjectChangeInfo: Invalid number of views ({}) for object id {}. Ignoring.", spec->views, id + i); + GrfMsg(2, "ObjectChangeInfo: Invalid number of views ({}) for object id {}. Ignoring.", spec->views, id); spec->views = 1; } break; @@ -4257,25 +4330,25 @@ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteRea /** * Define properties for railtypes - * @param id ID of the railtype. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first railtype. + * @param last Local ID of the last railtype. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; extern RailTypeInfo _railtypes[RAILTYPE_END]; - if (id + numinfo > RAILTYPE_END) { - GrfMsg(1, "RailTypeChangeInfo: Rail type {} is invalid, max {}, ignoring", id + numinfo, RAILTYPE_END); + if (last > RAILTYPE_END) { + GrfMsg(1, "RailTypeChangeInfo: Rail type {} is invalid, max {}, ignoring", last, RAILTYPE_END); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { - RailType rt = _cur.grffile->railtype_map[id + i]; + for (uint id = first; id < last; ++id) { + RailType rt = _cur.grffile->railtype_map[id]; if (rt == INVALID_RAILTYPE) return CIR_INVALID_ID; RailTypeInfo *rti = &_railtypes[rt]; @@ -4289,7 +4362,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR case 0x09: { // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8) GRFStringID str{buf.ReadWord()}; AddStringForMapping(str, &rti->strings.toolbar_caption); - if (_cur.grffile->grf_version < 8) { + if (_cur.grf_version < 8) { AddStringForMapping(str, &rti->strings.name); } break; @@ -4319,7 +4392,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR /* Rail type compatibility bits are added to the existing bits * to allow multiple GRFs to modify compatibility with the * default rail types. */ - int n = buf.ReadByte(); + int n = buf.ReadID(); for (int j = 0; j != n; j++) { RailTypeLabel label = buf.ReadDWord(); RailType resolved_rt = GetRailTypeByLabel(BSWAP32(label), false); @@ -4381,7 +4454,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR case 0x1D: // Alternate rail type label list /* Skipped here as this is loaded during reservation stage. */ - for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord(); + for (int j = buf.ReadID(); j != 0; j--) buf.ReadDWord(); break; default: @@ -4393,18 +4466,18 @@ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteR return ret; } -static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RailTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; extern RailTypeInfo _railtypes[RAILTYPE_END]; - if (id + numinfo > RAILTYPE_END) { - GrfMsg(1, "RailTypeReserveInfo: Rail type {} is invalid, max {}, ignoring", id + numinfo, RAILTYPE_END); + if (last > RAILTYPE_END) { + GrfMsg(1, "RailTypeReserveInfo: Rail type {} is invalid, max {}, ignoring", last, RAILTYPE_END); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { + for (uint id = first; id < last; ++id) { switch (prop) { case 0x08: // Label of rail type { @@ -4417,7 +4490,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte rt = AllocateRailType(rtl); } - _cur.grffile->railtype_map[id + i] = rt; + _cur.grffile->railtype_map[id] = rt; break; } @@ -4434,21 +4507,21 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte break; case 0x1D: // Alternate rail type label list - if (_cur.grffile->railtype_map[id + i] != INVALID_RAILTYPE) { - int n = buf.ReadByte(); + if (_cur.grffile->railtype_map[id] != INVALID_RAILTYPE) { + int n = buf.ReadID(); for (int j = 0; j != n; j++) { - _railtypes[_cur.grffile->railtype_map[id + i]].alternate_labels.push_back(BSWAP32(buf.ReadDWord())); + _railtypes[_cur.grffile->railtype_map[id]].alternate_labels.push_back(BSWAP32(buf.ReadDWord())); } break; } - GrfMsg(1, "RailTypeReserveInfo: Ignoring property 1D for rail type {} because no label was set", id + i); + GrfMsg(1, "RailTypeReserveInfo: Ignoring property 1D for rail type {} because no label was set", id); [[fallthrough]]; case 0x0E: // Compatible railtype list case 0x0F: // Powered railtype list case 0x18: // Railtype list required for date introduction case 0x19: // Introduced railtype list - for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord(); + for (int j = buf.ReadID(); j != 0; j--) buf.ReadDWord(); break; case 0x10: // Rail Type flags @@ -4475,26 +4548,26 @@ static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, Byte /** * Define properties for roadtypes - * @param id ID of the roadtype. - * @param numinfo Number of subsequent IDs to change the property for. + * @param first Local ID of the first roadtype. + * @param last Local ID of the last roadtype. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ -static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf, RoadTramType rtt) +static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf, RoadTramType rtt) { ChangeInfoResult ret = CIR_SUCCESS; extern RoadTypeInfo _roadtypes[ROADTYPE_END]; std::array &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; - if (id + numinfo > ROADTYPE_END) { - GrfMsg(1, "RoadTypeChangeInfo: Road type {} is invalid, max {}, ignoring", id + numinfo, ROADTYPE_END); + if (last > ROADTYPE_END) { + GrfMsg(1, "RoadTypeChangeInfo: Road type {} is invalid, max {}, ignoring", last, ROADTYPE_END); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { - RoadType rt = type_map[id + i]; + for (uint id = first; id < last; ++id) { + RoadType rt = type_map[id]; if (rt == INVALID_ROADTYPE) return CIR_INVALID_ID; RoadTypeInfo *rti = &_roadtypes[rt]; @@ -4531,7 +4604,7 @@ static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteR /* Road type compatibility bits are added to the existing bits * to allow multiple GRFs to modify compatibility with the * default road types. */ - int n = buf.ReadByte(); + int n = buf.ReadID(); for (int j = 0; j != n; j++) { RoadTypeLabel label = buf.ReadDWord(); RoadType resolved_rt = GetRoadTypeByLabel(BSWAP32(label), false); @@ -4586,7 +4659,7 @@ static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteR case 0x1D: // Alternate road type label list /* Skipped here as this is loaded during reservation stage. */ - for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord(); + for (int j = buf.ReadID(); j != 0; j--) buf.ReadDWord(); break; default: @@ -4598,30 +4671,30 @@ static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteR return ret; } -static ChangeInfoResult RoadTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf) { - return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_ROAD); + return RoadTypeChangeInfo(first, last, prop, buf, RTT_ROAD); } -static ChangeInfoResult TramTypeChangeInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult TramTypeChangeInfo(uint first, uint last, int prop, ByteReader &buf) { - return RoadTypeChangeInfo(id, numinfo, prop, buf, RTT_TRAM); + return RoadTypeChangeInfo(first, last, prop, buf, RTT_TRAM); } -static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf, RoadTramType rtt) +static ChangeInfoResult RoadTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf, RoadTramType rtt) { ChangeInfoResult ret = CIR_SUCCESS; extern RoadTypeInfo _roadtypes[ROADTYPE_END]; std::array &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; - if (id + numinfo > ROADTYPE_END) { - GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid, max {}, ignoring", id + numinfo, ROADTYPE_END); + if (last > ROADTYPE_END) { + GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid, max {}, ignoring", last, ROADTYPE_END); return CIR_INVALID_ID; } - for (int i = 0; i < numinfo; i++) { + for (uint id = first; id < last; ++id) { switch (prop) { case 0x08: { // Label of road type RoadTypeLabel rtl = buf.ReadDWord(); @@ -4632,11 +4705,11 @@ static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, Byte /* Set up new road type */ rt = AllocateRoadType(rtl, rtt); } else if (GetRoadTramType(rt) != rtt) { - GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid type (road/tram), ignoring", id + numinfo); + GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid type (road/tram), ignoring", id); return CIR_INVALID_ID; } - type_map[id + i] = rt; + type_map[id] = rt; break; } case 0x09: // Toolbar caption of roadtype @@ -4652,20 +4725,20 @@ static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, Byte break; case 0x1D: // Alternate road type label list - if (type_map[id + i] != INVALID_ROADTYPE) { - int n = buf.ReadByte(); + if (type_map[id] != INVALID_ROADTYPE) { + int n = buf.ReadID(); for (int j = 0; j != n; j++) { - _roadtypes[type_map[id + i]].alternate_labels.push_back(BSWAP32(buf.ReadDWord())); + _roadtypes[type_map[id]].alternate_labels.push_back(BSWAP32(buf.ReadDWord())); } break; } - GrfMsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type {} because no label was set", id + i); + GrfMsg(1, "RoadTypeReserveInfo: Ignoring property 1D for road type {} because no label was set", id); /* FALL THROUGH */ case 0x0F: // Powered roadtype list case 0x18: // Roadtype list required for date introduction case 0x19: // Introduced roadtype list - for (int j = buf.ReadByte(); j != 0; j--) buf.ReadDWord(); + for (int j = buf.ReadID(); j != 0; j--) buf.ReadDWord(); break; case 0x10: // Road Type flags @@ -4687,33 +4760,33 @@ static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, Byte return ret; } -static ChangeInfoResult RoadTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RoadTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf) { - return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_ROAD); + return RoadTypeReserveInfo(first, last, prop, buf, RTT_ROAD); } -static ChangeInfoResult TramTypeReserveInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult TramTypeReserveInfo(uint first, uint last, int prop, ByteReader &buf) { - return RoadTypeReserveInfo(id, numinfo, prop, buf, RTT_TRAM); + return RoadTypeReserveInfo(first, last, prop, buf, RTT_TRAM); } -static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (airtid + numinfo > NUM_AIRPORTTILES_PER_GRF) { - GrfMsg(1, "AirportTileChangeInfo: Too many airport tiles loaded ({}), max ({}). Ignoring.", airtid + numinfo, NUM_AIRPORTTILES_PER_GRF); + if (last > NUM_AIRPORTTILES_PER_GRF) { + GrfMsg(1, "AirportTileChangeInfo: Too many airport tiles loaded ({}), max ({}). Ignoring.", last, NUM_AIRPORTTILES_PER_GRF); return CIR_INVALID_ID; } /* Allocate airport tile specs if they haven't been allocated already. */ - if (_cur.grffile->airtspec.size() < airtid + numinfo) _cur.grffile->airtspec.resize(airtid + numinfo); + if (_cur.grffile->airtspec.size() < last) _cur.grffile->airtspec.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &tsp = _cur.grffile->airtspec[airtid + i]; + for (uint id = first; id < last; ++id) { + auto &tsp = _cur.grffile->airtspec[id]; if (prop != 0x08 && tsp == nullptr) { - GrfMsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile {}. Ignoring.", airtid + i); + GrfMsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile {}. Ignoring.", id); return CIR_INVALID_ID; } @@ -4722,7 +4795,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro uint8_t subs_id = buf.ReadByte(); if (subs_id >= NEW_AIRPORTTILE_OFFSET) { /* The substitute id must be one of the original airport tiles. */ - GrfMsg(2, "AirportTileChangeInfo: Attempt to use new airport tile {} as substitute airport tile for {}. Ignoring.", subs_id, airtid + i); + GrfMsg(2, "AirportTileChangeInfo: Attempt to use new airport tile {} as substitute airport tile for {}. Ignoring.", subs_id, id); continue; } @@ -4734,11 +4807,11 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro tsp->animation.status = ANIM_STATUS_NO_ANIMATION; - tsp->grf_prop.local_id = airtid + i; + tsp->grf_prop.local_id = id; tsp->grf_prop.subst_id = subs_id; tsp->grf_prop.grfid = _cur.grffile->grfid; tsp->grf_prop.grffile = _cur.grffile; - _airporttile_mngr.AddEntityID(airtid + i, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot + _airporttile_mngr.AddEntityID(id, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot } break; } @@ -4748,11 +4821,11 @@ static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int pro /* The airport tile being overridden must be an original airport tile. */ if (override >= NEW_AIRPORTTILE_OFFSET) { - GrfMsg(2, "AirportTileChangeInfo: Attempt to override new airport tile {} with airport tile id {}. Ignoring.", override, airtid + i); + GrfMsg(2, "AirportTileChangeInfo: Attempt to override new airport tile {} with airport tile id {}. Ignoring.", override, id); continue; } - _airporttile_mngr.Add(airtid + i, _cur.grffile->grfid, override); + _airporttile_mngr.Add(id, _cur.grffile->grfid, override); break; } @@ -4822,22 +4895,22 @@ static ChangeInfoResult IgnoreRoadStopProperty(uint prop, ByteReader &buf) return ret; } -static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, ByteReader &buf) +static ChangeInfoResult RoadStopChangeInfo(uint first, uint last, int prop, ByteReader &buf) { ChangeInfoResult ret = CIR_SUCCESS; - if (id + numinfo > NUM_ROADSTOPS_PER_GRF) { - GrfMsg(1, "RoadStopChangeInfo: RoadStop {} is invalid, max {}, ignoring", id + numinfo, NUM_ROADSTOPS_PER_GRF); + if (last > NUM_ROADSTOPS_PER_GRF) { + GrfMsg(1, "RoadStopChangeInfo: RoadStop {} is invalid, max {}, ignoring", last, NUM_ROADSTOPS_PER_GRF); return CIR_INVALID_ID; } - if (_cur.grffile->roadstops.size() < id + numinfo) _cur.grffile->roadstops.resize(id + numinfo); + if (_cur.grffile->roadstops.size() < last) _cur.grffile->roadstops.resize(last); - for (int i = 0; i < numinfo; i++) { - auto &rs = _cur.grffile->roadstops[id + i]; + for (uint id = first; id < last; ++id) { + auto &rs = _cur.grffile->roadstops[id]; if (rs == nullptr && prop != 0x08) { - GrfMsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop {}, ignoring", id + i); + GrfMsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop {}, ignoring", id); ChangeInfoResult cir = IgnoreRoadStopProperty(prop, buf); if (cir > ret) ret = cir; continue; @@ -4925,6 +4998,10 @@ static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uin GrfMsg(1, "{}: Ignoring property 0x{:02X} of feature 0x{:02X} (not implemented)", caller, property, feature); return false; + case CIR_REMOVED: + GrfMsg(0, "{}: Ignoring property 0x{:02X} of feature 0x{:02X} (removed)", caller, property, feature); + return true; + case CIR_UNKNOWN: GrfMsg(0, "{}: Unknown property 0x{:02X} of feature 0x{:02X}, disabling", caller, property, feature); [[fallthrough]]; @@ -4952,7 +5029,7 @@ static void FeatureChangeInfo(ByteReader &buf) * B property what property to change, depends on the feature * V new-info new bytes of info (variable size; depends on properties) */ - static const VCI_Handler handler[] = { + static ChangeInfoHandler * const handler[] = { /* GSF_TRAINS */ RailVehicleChangeInfo, /* GSF_ROADVEHICLES */ RoadVehicleChangeInfo, /* GSF_SHIPS */ ShipVehicleChangeInfo, @@ -4975,12 +5052,12 @@ static void FeatureChangeInfo(ByteReader &buf) /* GSF_TRAMTYPES */ TramTypeChangeInfo, /* GSF_ROADSTOPS */ RoadStopChangeInfo, }; - static_assert(GSF_END == lengthof(handler)); + static_assert(GSF_END == std::size(handler)); uint8_t feature = buf.ReadByte(); uint8_t numprops = buf.ReadByte(); - uint numinfo = buf.ReadByte(); - uint engine = buf.ReadExtendedByte(); + uint16_t numinfo = buf.ReadID(); + uint16_t engine = buf.ReadExtendedByte(); if (feature >= GSF_END) { GrfMsg(1, "FeatureChangeInfo: Unsupported feature 0x{:02X}, skipping", feature); @@ -5001,7 +5078,7 @@ static void FeatureChangeInfo(ByteReader &buf) while (numprops-- && buf.HasData()) { uint8_t prop = buf.ReadByte(); - ChangeInfoResult cir = handler[feature](engine, numinfo, prop, buf); + ChangeInfoResult cir = handler[feature](engine, engine + numinfo, prop, buf); if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return; } } @@ -5011,7 +5088,7 @@ static void SafeChangeInfo(ByteReader &buf) { uint8_t feature = buf.ReadByte(); uint8_t numprops = buf.ReadByte(); - uint numinfo = buf.ReadByte(); + uint16_t numinfo = buf.ReadID(); buf.ReadExtendedByte(); // id if (feature == GSF_BRIDGES && numprops == 1) { @@ -5051,7 +5128,7 @@ static void ReserveChangeInfo(ByteReader &buf) if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES && feature != GSF_ROADTYPES && feature != GSF_TRAMTYPES) return; uint8_t numprops = buf.ReadByte(); - uint8_t numinfo = buf.ReadByte(); + uint16_t numinfo = buf.ReadID(); uint16_t index = buf.ReadExtendedByte(); while (numprops-- && buf.HasData()) { @@ -5061,23 +5138,23 @@ static void ReserveChangeInfo(ByteReader &buf) switch (feature) { default: NOT_REACHED(); case GSF_CARGOES: - cir = CargoChangeInfo(index, numinfo, prop, buf); + cir = CargoChangeInfo(index, index + numinfo, prop, buf); break; case GSF_GLOBALVAR: - cir = GlobalVarReserveInfo(index, numinfo, prop, buf); + cir = GlobalVarReserveInfo(index, index + numinfo, prop, buf); break; case GSF_RAILTYPES: - cir = RailTypeReserveInfo(index, numinfo, prop, buf); + cir = RailTypeReserveInfo(index, index + numinfo, prop, buf); break; case GSF_ROADTYPES: - cir = RoadTypeReserveInfo(index, numinfo, prop, buf); + cir = RoadTypeReserveInfo(index, index + numinfo, prop, buf); break; case GSF_TRAMTYPES: - cir = TramTypeReserveInfo(index, numinfo, prop, buf); + cir = TramTypeReserveInfo(index, index + numinfo, prop, buf); break; } @@ -5158,7 +5235,7 @@ static const SpriteGroup *GetCallbackResultGroup(uint16_t value) { /* Old style callback results (only valid for version < 8) have the highest byte 0xFF to signify it is a callback result. * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */ - if (_cur.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) { + if (_cur.grf_version < 8 && GB(value, 8, 8) == 0xFF) { value &= ~0xFF00; } else { value &= ~0x8000; @@ -5177,11 +5254,11 @@ static const SpriteGroup *GetCallbackResultGroup(uint16_t value) /* Helper function to either create a callback or link to a previously * defined spritegroup. */ -static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint16_t groupid) +static const SpriteGroup *GetGroupFromGroupID(uint16_t setid, uint8_t type, uint16_t groupid, bool allow_callback = true) { - if (HasBit(groupid, 15)) return GetCallbackResultGroup(groupid); + if (allow_callback && HasBit(groupid, 15)) return GetCallbackResultGroup(groupid); - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { + if (groupid > MAX_SPRITEGROUP || !_cur.spritegroups.contains(groupid)) { GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid); return nullptr; } @@ -5237,8 +5314,13 @@ static void NewSpriteGroup(ByteReader &buf) return; } - uint8_t setid = buf.ReadByte(); - uint8_t type = buf.ReadByte(); + uint16_t setid = buf.ReadID(); + if (HasBit(setid, 15)) { + GrfMsg(1, "NewSpriteGroup: Invalid action 2 ID 0x{:04X}, skipping", setid); + return; + } + + uint8_t type = buf.ReadByte(); /* Sprite Groups are created here but they are allocated from a pool, so * we do not need to delete anything if there is an exception from the @@ -5279,9 +5361,9 @@ static void NewSpriteGroup(ByteReader &buf) adjust.variable = buf.ReadByte(); if (adjust.variable == 0x7E) { /* Link subroutine group */ - adjust.subroutine = GetGroupFromGroupID(setid, type, buf.ReadByte()); - } else { - adjust.parameter = IsInsideMM(adjust.variable, 0x60, 0x80) ? buf.ReadByte() : 0; + adjust.subroutine = GetGroupFromGroupID(setid, type, buf.ReadID(), false); + } else if (IsInsideMM(adjust.variable, 0x60, 0x80)) { + adjust.parameter = _cur.grf_version < 9 ? buf.ReadByte() : buf.ReadDWord(); } varadjust = buf.ReadByte(); @@ -5302,7 +5384,7 @@ static void NewSpriteGroup(ByteReader &buf) } while (HasBit(varadjust, 5)); std::vector ranges; - ranges.resize(buf.ReadByte()); + ranges.resize(buf.ReadID()); for (auto &range : ranges) { range.group = GetGroupFromGroupID(setid, type, buf.ReadWord()); range.low = buf.ReadVarSize(varsize); @@ -5376,7 +5458,7 @@ static void NewSpriteGroup(ByteReader &buf) group->cmp_mode = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY; group->lowest_randbit = buf.ReadByte(); - uint8_t num_groups = buf.ReadByte(); + uint16_t num_groups = buf.ReadID(); if (!HasExactlyOneBit(num_groups)) { GrfMsg(1, "NewSpriteGroup: Random Action 2 nrand should be power of 2"); } @@ -5531,8 +5613,7 @@ static void NewSpriteGroup(ByteReader &buf) return; } for (uint i = 0; i < group->num_input; i++) { - uint8_t rawcargo = buf.ReadByte(); - CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile); + CargoID cargo = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (!IsValidCargoID(cargo)) { /* The mapped cargo is invalid. This is permitted at this point, * as long as the result is not used. Mark it invalid so this @@ -5553,8 +5634,7 @@ static void NewSpriteGroup(ByteReader &buf) return; } for (uint i = 0; i < group->num_output; i++) { - uint8_t rawcargo = buf.ReadByte(); - CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile); + CargoID cargo = GetCargoTranslation(buf.ReadID(), _cur.grffile); if (!IsValidCargoID(cargo)) { /* Mark this result as invalid to use */ group->version = 0xFF; @@ -5599,11 +5679,16 @@ std::span GetCargoTranslationTable(const GRFFile &grffile) return GetClimateIndependentCargoTranslationTable(); } -static CargoID TranslateCargo(uint8_t feature, uint8_t ctype) +static CargoID TranslateCargo(uint8_t feature, uint16_t ctype) { + if (_cur.grf_version < 9) { + if (ctype == UINT8_MAX - 1) ctype = UINT16_MAX - 1; + if (ctype == UINT8_MAX) ctype = UINT16_MAX; + } + /* Special cargo types for purchase list and stations */ - if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA; - if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE; + if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == UINT16_MAX - 1) return SpriteGroupCargo::SG_DEFAULT_NA; + if (ctype == UINT16_MAX) return SpriteGroupCargo::SG_PURCHASE; auto cargo_list = GetCargoTranslationTable(*_cur.grffile); @@ -5633,7 +5718,7 @@ static CargoID TranslateCargo(uint8_t feature, uint8_t ctype) static bool IsValidGroupID(uint16_t groupid, const char *function) { - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { + if (groupid > MAX_SPRITEGROUP || !_cur.spritegroups.contains(groupid)) { GrfMsg(1, "{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid); return false; } @@ -5641,7 +5726,16 @@ static bool IsValidGroupID(uint16_t groupid, const char *function) return true; } -static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idcount) +static void SkipMapSpriteGroupCargo(ByteReader &buf) +{ + uint16_t cidcount = buf.ReadID(); + for (uint c = 0; c < cidcount; c++) { + buf.ReadID(); + buf.ReadWord(); + } +} + +static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint16_t idcount) { static std::vector last_engines; // Engine IDs are remembered in case the next action is a wagon override. bool wagover = false; @@ -5650,7 +5744,7 @@ static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idco if (HasBit(idcount, 7)) { wagover = true; /* Strip off the flag */ - idcount = GB(idcount, 0, 7); + idcount = GB(idcount, 0, 15); if (last_engines.empty()) { GrfMsg(0, "VehicleMapSpriteGroup: WagonOverride: No engine to do override with"); @@ -5678,9 +5772,9 @@ static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idco if (!wagover) last_engines[i] = engines[i]; } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID(); for (uint c = 0; c < cidcount; c++) { - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) continue; @@ -5720,7 +5814,7 @@ static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idco } -static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void CanalMapSpriteGroup(ByteReader &buf, uint16_t idcount) { std::vector cfs; cfs.reserve(idcount); @@ -5728,7 +5822,7 @@ static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount) cfs.push_back(buf.ReadExtendedByte()); } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID(); buf.Skip(cidcount * 3); uint16_t groupid = buf.ReadWord(); @@ -5746,7 +5840,7 @@ static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount) } -static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void StationMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->stations.empty()) { GrfMsg(1, "StationMapSpriteGroup: No stations defined, skipping"); @@ -5759,9 +5853,9 @@ static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) stations.push_back(buf.ReadExtendedByte()); } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID(); for (uint c = 0; c < cidcount; c++) { - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) continue; @@ -5805,7 +5899,7 @@ static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) } -static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void TownHouseMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->housespec.empty()) { GrfMsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping"); @@ -5819,8 +5913,7 @@ static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount) } /* Skip the cargo type section, we only care about the default group */ - uint8_t cidcount = buf.ReadByte(); - buf.Skip(cidcount * 3); + SkipMapSpriteGroupCargo(buf); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return; @@ -5837,7 +5930,7 @@ static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void IndustryMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->industryspec.empty()) { GrfMsg(1, "IndustryMapSpriteGroup: No industries defined, skipping"); @@ -5851,8 +5944,7 @@ static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount) } /* Skip the cargo type section, we only care about the default group */ - uint8_t cidcount = buf.ReadByte(); - buf.Skip(cidcount * 3); + SkipMapSpriteGroupCargo(buf); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return; @@ -5869,7 +5961,7 @@ static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void IndustrytileMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->indtspec.empty()) { GrfMsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping"); @@ -5883,8 +5975,7 @@ static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount) } /* Skip the cargo type section, we only care about the default group */ - uint8_t cidcount = buf.ReadByte(); - buf.Skip(cidcount * 3); + SkipMapSpriteGroupCargo(buf); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return; @@ -5901,7 +5992,7 @@ static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void CargoMapSpriteGroup(ByteReader &buf, uint16_t idcount) { std::vector cargoes; cargoes.reserve(idcount); @@ -5910,8 +6001,7 @@ static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount) } /* Skip the cargo type section, we only care about the default group */ - uint8_t cidcount = buf.ReadByte(); - buf.Skip(cidcount * 3); + SkipMapSpriteGroupCargo(buf); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "CargoMapSpriteGroup")) return; @@ -5928,7 +6018,7 @@ static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void ObjectMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->objectspec.empty()) { GrfMsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping"); @@ -5941,14 +6031,14 @@ static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) objects.push_back(buf.ReadExtendedByte()); } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID(); for (uint c = 0; c < cidcount; c++) { - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) continue; /* The only valid option here is purchase list sprite groups. */ - if (ctype != 0xFF) { + if (TranslateCargo(GSF_OBJECTS, ctype) != SpriteGroupCargo::SG_PURCHASE) { GrfMsg(1, "ObjectMapSpriteGroup: Invalid cargo bitnum {} for objects, skipping.", ctype); continue; } @@ -5988,7 +6078,7 @@ static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void RailTypeMapSpriteGroup(ByteReader &buf, uint16_t idcount) { std::vector railtypes; railtypes.reserve(idcount); @@ -5997,9 +6087,9 @@ static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount) railtypes.push_back(id < RAILTYPE_END ? _cur.grffile->railtype_map[id] : INVALID_RAILTYPE); } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID();; for (uint c = 0; c < cidcount; c++) { - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "RailTypeMapSpriteGroup")) continue; @@ -6020,7 +6110,7 @@ static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount) buf.ReadWord(); } -static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramType rtt) +static void RoadTypeMapSpriteGroup(ByteReader &buf, uint16_t idcount, RoadTramType rtt) { std::array &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; @@ -6031,9 +6121,9 @@ static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramTyp roadtypes.push_back(id < ROADTYPE_END ? type_map[id] : INVALID_ROADTYPE); } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID(); for (uint c = 0; c < cidcount; c++) { - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "RoadTypeMapSpriteGroup")) continue; @@ -6054,7 +6144,7 @@ static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramTyp buf.ReadWord(); } -static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void AirportMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->airportspec.empty()) { GrfMsg(1, "AirportMapSpriteGroup: No airports defined, skipping"); @@ -6068,8 +6158,7 @@ static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount) } /* Skip the cargo type section, we only care about the default group */ - uint8_t cidcount = buf.ReadByte(); - buf.Skip(cidcount * 3); + SkipMapSpriteGroupCargo(buf); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return; @@ -6086,7 +6175,7 @@ static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void AirportTileMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->airtspec.empty()) { GrfMsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping"); @@ -6100,8 +6189,7 @@ static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount) } /* Skip the cargo type section, we only care about the default group */ - uint8_t cidcount = buf.ReadByte(); - buf.Skip(cidcount * 3); + SkipMapSpriteGroupCargo(buf); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return; @@ -6118,7 +6206,7 @@ static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount) } } -static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) +static void RoadStopMapSpriteGroup(ByteReader &buf, uint16_t idcount) { if (_cur.grffile->roadstops.empty()) { GrfMsg(1, "RoadStopMapSpriteGroup: No roadstops defined, skipping"); @@ -6131,9 +6219,9 @@ static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) roadstops.push_back(buf.ReadExtendedByte()); } - uint8_t cidcount = buf.ReadByte(); + uint16_t cidcount = buf.ReadID(); for (uint c = 0; c < cidcount; c++) { - uint8_t ctype = buf.ReadByte(); + uint16_t ctype = buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) continue; @@ -6194,7 +6282,7 @@ static void FeatureMapSpriteGroup(ByteReader &buf) * W def-cid default cargo ID (sprite group ID) */ uint8_t feature = buf.ReadByte(); - uint8_t idcount = buf.ReadByte(); + uint16_t idcount = buf.ReadID(); if (feature >= GSF_END) { GrfMsg(1, "FeatureMapSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature); @@ -6204,7 +6292,7 @@ static void FeatureMapSpriteGroup(ByteReader &buf) /* If idcount is zero, this is a feature callback */ if (idcount == 0) { /* Skip number of cargo ids? */ - buf.ReadByte(); + buf.ReadID(); uint16_t groupid = buf.ReadWord(); if (!IsValidGroupID(groupid, "FeatureMapSpriteGroup")) return; @@ -6304,7 +6392,7 @@ static void FeatureNewName(ByteReader &buf) * S data new texts, each of them zero-terminated, after * which the next name begins. */ - bool new_scheme = _cur.grffile->grf_version >= 7; + bool new_scheme = _cur.grf_version >= 7; uint8_t feature = buf.ReadByte(); if (feature >= GSF_END && feature != 0x48) { @@ -6313,15 +6401,19 @@ static void FeatureNewName(ByteReader &buf) } uint8_t lang = buf.ReadByte(); - uint8_t num = buf.ReadByte(); + uint16_t num = buf.ReadID(); bool generic = HasBit(lang, 7); uint16_t id; - if (generic) { - id = buf.ReadWord(); - } else if (feature <= GSF_AIRCRAFT) { - id = buf.ReadExtendedByte(); + if (_cur.grf_version < 9) { + if (generic) { + id = buf.ReadWord(); + } else if (feature <= GSF_AIRCRAFT) { + id = buf.ReadExtendedByte(); + } else { + id = buf.ReadByte(); + } } else { - id = buf.ReadByte(); + id = buf.ReadWord(); } ClrBit(lang, 7); @@ -7004,7 +7096,7 @@ static void SkipIf(ByteReader &buf) return; } - uint8_t numsprites = buf.ReadByte(); + uint16_t numsprites = buf.ReadID(); /* numsprites can be a GOTO label if it has been defined in the GRF * file. The jump will always be the first matching label that follows @@ -7028,6 +7120,9 @@ static void SkipIf(ByteReader &buf) _cur.file->SeekTo(choice->pos, SEEK_SET); _cur.nfo_line = choice->nfo_line; return; + } else if (HasBit(numsprites, 15)) { + GrfMsg(1, "SkipIf: Label 0x{:X} not found, ignoring.", GB(numsprites, 0, 15)); + return; } GrfMsg(2, "SkipIf: Skipping {} sprites, test was true", numsprites); @@ -7055,11 +7150,13 @@ static void ScanInfo(ByteReader &buf) _cur.grfconfig->ident.grfid = grfid; - if (grf_version < 2 || grf_version > 8) { + if (grf_version < 2 || grf_version > 9) { SetBit(_cur.grfconfig->flags, GCF_INVALID); Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID {:08X}) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur.grfconfig->filename, StrMakeValid(name), BSWAP32(grfid), grf_version); } + _cur.grf_version = grf_version; + /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ if (GB(grfid, 0, 8) == 0xFF) SetBit(_cur.grfconfig->flags, GCF_SYSTEM); @@ -7074,6 +7171,13 @@ static void ScanInfo(ByteReader &buf) _cur.skip_sprites = -1; } +/* Skip Action 0x08 */ +static void SkipGRFInfo(ByteReader &buf) +{ + /* Even though we are skipping the Action 8 information, we still need to switch to the correct GRF version. */ + _cur.grf_version = buf.ReadByte(); +} + /* Action 0x08 */ static void GRFInfo(ByteReader &buf) { @@ -7098,6 +7202,7 @@ static void GRFInfo(ByteReader &buf) _cur.grffile->grfid = grfid; } + _cur.grf_version = version; _cur.grffile->grf_version = version; _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED; @@ -7131,10 +7236,10 @@ static void SpriteReplace(ByteReader &buf) * B num-sprites How many sprites are in this set * W first-sprite First sprite number to replace */ - uint8_t num_sets = buf.ReadByte(); + uint16_t num_sets = buf.ReadID(); for (uint i = 0; i < num_sets; i++) { - uint8_t num_sprites = buf.ReadByte(); + uint16_t num_sprites = buf.ReadID(); uint16_t first_sprite = buf.ReadWord(); GrfMsg(2, "SpriteReplace: [Set {}] Changing {} sprites, beginning with {}", @@ -7170,11 +7275,11 @@ static void SpriteReplace(ByteReader &buf) /* Action 0x0A (SKIP) */ static void SkipActA(ByteReader &buf) { - uint8_t num_sets = buf.ReadByte(); + uint16_t num_sets = buf.ReadID(); for (uint i = 0; i < num_sets; i++) { /* Skip the sprites this replaces */ - _cur.skip_sprites += buf.ReadByte(); + _cur.skip_sprites += buf.ReadID(); /* But ignore where they go */ buf.ReadWord(); } @@ -7222,7 +7327,7 @@ static void GRFLoadError(ByteReader &buf) uint8_t message_id = buf.ReadByte(); /* Skip the error if it isn't valid for the current language. */ - if (!CheckGrfLangID(lang, _cur.grffile->grf_version)) return; + if (!CheckGrfLangID(lang, _cur.grf_version)) return; /* Skip the error until the activation stage unless bit 7 of the severity * is set. */ @@ -7758,7 +7863,7 @@ static void SafeGRFInhibit(ByteReader &buf) * B num Number of GRFIDs that follow * D grfids GRFIDs of the files to deactivate */ - uint8_t num = buf.ReadByte(); + uint16_t num = buf.ReadID(); for (uint i = 0; i < num; i++) { uint32_t grfid = buf.ReadDWord(); @@ -7780,10 +7885,10 @@ static void GRFInhibit(ByteReader &buf) { /* <0E> * - * B num Number of GRFIDs that follow + * W num Number of GRFIDs that follow * D grfids GRFIDs of the files to deactivate */ - uint8_t num = buf.ReadByte(); + uint16_t num = buf.ReadID(); for (uint i = 0; i < num; i++) { uint32_t grfid = buf.ReadDWord(); @@ -7818,7 +7923,7 @@ static void FeatureTownName(ByteReader &buf) if (HasBit(id, 7)) { /* Final definition */ ClrBit(id, 7); - bool new_scheme = _cur.grffile->grf_version >= 7; + bool new_scheme = _cur.grf_version >= 7; uint8_t lang = buf.ReadByte(); StringID style = STR_UNDEFINED; @@ -7884,11 +7989,16 @@ static void DefineGotoLabel(ByteReader &buf) * B label The label to define * V comment Optional comment - ignored */ - uint8_t nfo_label = buf.ReadByte(); + uint16_t nfo_label = buf.ReadID(); + + if (_cur.grf_version >= 9 && !HasBit(nfo_label, 15)) { + GrfMsg(0, "DefineGotoLabel: GOTO target with invalid label 0x{:04X}, ignoring", nfo_label); + return; + } _cur.grffile->labels.emplace_back(nfo_label, _cur.nfo_line, _cur.file->GetPos()); - GrfMsg(2, "DefineGotoLabel: GOTO target with label 0x{:02X}", nfo_label); + GrfMsg(2, "DefineGotoLabel: GOTO target with label 0x{:04X}", nfo_label); } /** @@ -8046,6 +8156,11 @@ static void SkipAct11(ByteReader &buf) GrfMsg(3, "SkipAct11: Skipping {} sprites", _cur.skip_sprites); } +static bool IsValidUnicodePoint(char32_t c) +{ + return c <= 0x10FFFF && (c & 0xFFFE) != 0xFFFE && (c < 0xFDD0 || c > 0xFDEF); +} + /** Action 0x12 */ static void LoadFontGlyph(ByteReader &buf) { @@ -8056,12 +8171,12 @@ static void LoadFontGlyph(ByteReader &buf) * B num_char Number of consecutive glyphs * W base_char First character index */ - uint8_t num_def = buf.ReadByte(); + uint16_t num_def = buf.ReadID(); for (uint i = 0; i < num_def; i++) { FontSize size = (FontSize)buf.ReadByte(); - uint8_t num_char = buf.ReadByte(); - uint16_t base_char = buf.ReadWord(); + uint16_t num_char = buf.ReadID(); + uint32_t base_char = _cur.grf_version < 9 ? buf.ReadWord() : buf.ReadDWord(); if (size >= FS_END) { GrfMsg(1, "LoadFontGlyph: Size {} is not supported, ignoring", size); @@ -8070,7 +8185,7 @@ static void LoadFontGlyph(ByteReader &buf) GrfMsg(7, "LoadFontGlyph: Loading {} glyph(s) at 0x{:04X} for size {}", num_char, base_char, size); for (uint c = 0; c < num_char; c++) { - if (size < FS_END) SetUnicodeGlyph(size, base_char + c, _cur.spriteid); + if (size < FS_END && IsValidUnicodePoint(base_char) && IsValidUnicodePoint(base_char + c)) SetUnicodeGlyph(size, base_char + c, _cur.spriteid); _cur.nfo_line++; LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line); } @@ -8087,17 +8202,17 @@ static void SkipAct12(ByteReader &buf) * B num_char Number of consecutive glyphs * W base_char First character index */ - uint8_t num_def = buf.ReadByte(); + uint16_t num_def = buf.ReadID(); for (uint i = 0; i < num_def; i++) { /* Ignore 'size' byte */ buf.ReadByte(); /* Sum up number of characters */ - _cur.skip_sprites += buf.ReadByte(); + _cur.skip_sprites += buf.ReadID(); - /* Ignore 'base_char' word */ - buf.ReadWord(); + /* Ignore 'base_char' (d)word. */ + _cur.grf_version < 9 ? buf.ReadWord() : buf.ReadDWord(); } GrfMsg(3, "SkipAct12: Skipping {} sprites", _cur.skip_sprites); @@ -8135,8 +8250,8 @@ static void TranslateGRFStrings(ByteReader &buf) * new_scheme has to be true as well, which will also be implicitly the case for version 8 * and higher. A language id of 0x7F will be overridden by a non-generic id, so this will * not change anything if a string has been provided specifically for this language. */ - uint8_t language = _cur.grffile->grf_version >= 8 ? buf.ReadByte() : 0x7F; - uint8_t num_strings = buf.ReadByte(); + uint8_t language = _cur.grf_version >= 8 ? buf.ReadByte() : 0x7F; + uint16_t num_strings = buf.ReadID(); uint16_t first_id = buf.ReadWord(); if (!((first_id >= 0xD000 && first_id + num_strings <= 0xD400) || (first_id >= 0xD800 && first_id + num_strings <= 0xE000))) { @@ -9611,7 +9726,7 @@ static void DecodeSpecialSprite(uint8_t *buf, uint num, GrfLoadingStage stage) /* 0x05 */ { SkipAct5, SkipAct5, SkipAct5, SkipAct5, SkipAct5, GraphicsNew, }, /* 0x06 */ { nullptr, nullptr, nullptr, CfgApply, CfgApply, CfgApply, }, /* 0x07 */ { nullptr, nullptr, nullptr, nullptr, SkipIf, SkipIf, }, - /* 0x08 */ { ScanInfo, nullptr, nullptr, GRFInfo, GRFInfo, GRFInfo, }, + /* 0x08 */ { ScanInfo, SkipGRFInfo, SkipGRFInfo, GRFInfo, GRFInfo, GRFInfo, }, /* 0x09 */ { nullptr, nullptr, nullptr, SkipIf, SkipIf, SkipIf, }, /* 0x0A */ { SkipActA, SkipActA, SkipActA, SkipActA, SkipActA, SpriteReplace, }, /* 0x0B */ { nullptr, nullptr, nullptr, GRFLoadError, GRFLoadError, GRFLoadError, }, @@ -9675,6 +9790,7 @@ static void LoadNewGRFFileFromFile(GRFConfig *config, GrfLoadingStage stage, Spr { _cur.file = &file; _cur.grfconfig = config; + _cur.grf_version = 2; Debug(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '{}'", config->filename); diff --git a/src/newgrf.h b/src/newgrf.h index 27afc3e77c069..2faedd6a70fb8 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -97,11 +97,11 @@ enum GrfSpecFeature { static const uint32_t INVALID_GRFID = 0xFFFFFFFF; struct GRFLabel { - uint8_t label; + uint16_t label; uint32_t nfo_line; size_t pos; - GRFLabel(uint8_t label, uint32_t nfo_line, size_t pos) : label(label), nfo_line(nfo_line), pos(pos) {} + GRFLabel(uint16_t label, uint32_t nfo_line, size_t pos) : label(label), nfo_line(nfo_line), pos(pos) {} }; /** Dynamic data of a loaded NewGRF */ diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index 7b6aba7475d27..56defabd87c4a 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -77,7 +77,7 @@ uint16_t GetCargoCallback(CallbackID callback, uint32_t param1, uint32_t param2, * For GRF version >= 7 \a cargo is always a translated cargo bit. * @return CargoID or INVALID_CARGO if the cargo is not available. */ -CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit) +CargoID GetCargoTranslation(uint16_t cargo, const GRFFile *grffile, bool usebit) { /* We can't use GetCargoTranslationTable here as the usebit flag changes behviour. */ /* Pre-version 7 uses the bitnum lookup from (standard in v8) instead of climate dependent in some places.. */ diff --git a/src/newgrf_cargo.h b/src/newgrf_cargo.h index e77401a26bc16..eae7f7690ca49 100644 --- a/src/newgrf_cargo.h +++ b/src/newgrf_cargo.h @@ -31,7 +31,7 @@ struct GRFFile; SpriteID GetCustomCargoSprite(const CargoSpec *cs); uint16_t GetCargoCallback(CallbackID callback, uint32_t param1, uint32_t param2, const CargoSpec *cs); -CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit = false); +CargoID GetCargoTranslation(uint16_t cargo, const GRFFile *grffile, bool usebit = false); std::span GetClimateDependentCargoTranslationTable(); std::span GetClimateIndependentCargoTranslationTable(); diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 1b8596659efbd..44442984de713 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -268,7 +268,7 @@ const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const } uint32_t mask = ((uint)this->groups.size() - 1) << this->lowest_randbit; - uint8_t index = (scope->GetRandomBits() & mask) >> this->lowest_randbit; + uint16_t index = (scope->GetRandomBits() & mask) >> this->lowest_randbit; return SpriteGroup::Resolve(this->groups[index], object, false); } diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 2efc98dbdceb5..0f81d2792e1ac 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -148,8 +148,8 @@ struct DeterministicSpriteGroupAdjust { DeterministicSpriteGroupAdjustOperation operation; DeterministicSpriteGroupAdjustType type; uint8_t variable; - uint8_t parameter; ///< Used for variables between 0x60 and 0x7F inclusive. uint8_t shift_num; + uint32_t parameter; ///< Used for variables between 0x60 and 0x7F inclusive. uint32_t and_mask; uint32_t add_val; uint32_t divmod_val; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index e1547c8ff3ed2..4c4872ad15222 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -404,7 +404,7 @@ TownScopeResolver *StationResolverObject::GetTown() return this->st->GetNewGRFVariable(this->ro, variable, parameter, available); } -uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const +uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variable, uint32_t parameter, bool &available) const { switch (variable) { case 0x48: { // Accepted cargo types @@ -470,7 +470,7 @@ uint32_t Station::GetNewGRFVariable(const ResolverObject &object, uint8_t variab return UINT_MAX; } -uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [[maybe_unused]] uint8_t parameter, bool &available) const +uint32_t Waypoint::GetNewGRFVariable(const ResolverObject &, uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const { switch (variable) { case 0x48: return 0; // Accepted cargo types diff --git a/src/pathfinder/aystar.h b/src/pathfinder/aystar.h index f8830c61c40e3..d88e15f25767b 100644 --- a/src/pathfinder/aystar.h +++ b/src/pathfinder/aystar.h @@ -16,12 +16,6 @@ #ifndef AYSTAR_H #define AYSTAR_H -#include "../track_func.h" - -#include "../misc/hashtable.hpp" -#include "../misc/binaryheap.hpp" -#include "../misc/dbg_helpers.h" - #include "yapf/nodelist.hpp" #include "yapf/yapf_node.hpp" @@ -44,8 +38,6 @@ using AyStarNode = CYapfNodeKeyTrackDir; struct PathNode : CYapfNodeT { }; -bool CheckIgnoreFirstTile(const PathNode *node); - struct AyStar; /** diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 87e4e21240752..c087a020868a8 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3201,12 +3201,11 @@ bool AfterLoadGame() if (c->settings.renew_keep_length) SetBit(wagon_removal, c->index); } for (Group *g : Group::Iterate()) { - if (g->flags != 0) { + if (to_underlying(g->flags) != 0) { /* Convert old replace_protection value to flag. */ - g->flags = 0; - SetBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION); + g->flags = GroupFlags::ReplaceProtection; } - if (HasBit(wagon_removal, g->owner)) SetBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + if (HasBit(wagon_removal, g->owner)) g->flags |= GroupFlags::ReplaceWagonRemoval; } } diff --git a/src/script/api/ai_changelog.hpp b/src/script/api/ai_changelog.hpp index b07b85c749b0d..ecc51d807223b 100644 --- a/src/script/api/ai_changelog.hpp +++ b/src/script/api/ai_changelog.hpp @@ -19,6 +19,8 @@ * * API additions: * \li AIEventVehicleCrashed::GetVictims + * \li AIEventCompanyRenamed + * \li AIEventPresidentRenamed * * \b 14.0 * diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp index 396772628822a..655cfac0b6cce 100644 --- a/src/script/api/game_changelog.hpp +++ b/src/script/api/game_changelog.hpp @@ -19,6 +19,8 @@ * * API additions: * \li GSEventVehicleCrashed::GetVictims + * \li GSEventCompanyRenamed + * \li GSEventPresidentRenamed * * \b 14.0 * diff --git a/src/script/api/script_event.hpp b/src/script/api/script_event.hpp index 2ff813aa8161d..09fbb643eb59d 100644 --- a/src/script/api/script_event.hpp +++ b/src/script/api/script_event.hpp @@ -57,6 +57,8 @@ class ScriptEvent : public ScriptObject { ET_STORYPAGE_BUTTON_CLICK, ET_STORYPAGE_TILE_SELECT, ET_STORYPAGE_VEHICLE_SELECT, + ET_COMPANY_RENAMED, + ET_PRESIDENT_RENAMED, }; /** diff --git a/src/script/api/script_event_types.hpp b/src/script/api/script_event_types.hpp index 776a31ff8dd34..95e22cd00322a 100644 --- a/src/script/api/script_event_types.hpp +++ b/src/script/api/script_event_types.hpp @@ -346,6 +346,48 @@ class ScriptEventCompanyNew : public ScriptEvent { ScriptCompany::CompanyID owner; ///< The new company. }; +/** + * Event Company Renamed, indicating a company has changed name. + * @api ai game + */ +class ScriptEventCompanyRenamed : public ScriptEvent { +public: +#ifndef DOXYGEN_API + /** + * @param owner The company that is renamed. + */ + ScriptEventCompanyRenamed(CompanyID company, const std::string &new_name) : + ScriptEvent(ET_COMPANY_RENAMED), + company(static_cast(company)), + new_name(new_name) + {} +#endif /* DOXYGEN_API */ + + /** + * Convert an ScriptEvent to the real instance. + * @param instance The instance to convert. + * @return The converted instance. + */ + static ScriptEventCompanyRenamed *Convert(ScriptEvent *instance) { return static_cast(instance); } + + /** + * Get the CompanyID of the company that has been renamed. + * @return The CompanyID of the company. + */ + ScriptCompany::CompanyID GetCompanyID() { return this->company; } + + /** + * Get the new name of the company. + * @return The new name of the company. + */ + std::optional GetNewName() { return this->new_name; } + +private: + + ScriptCompany::CompanyID company; ///< The company that was renamed. + std::string new_name; ///< The new name of the company. +}; + /** * Event Company In Trouble, indicating a company is in trouble and might go * bankrupt soon. @@ -1331,4 +1373,48 @@ class ScriptEventStoryPageVehicleSelect : public ScriptEvent { VehicleID vehicle_id; }; + +/** + * Event President Renamed, indicating a company's president's name has changed. + * This event is not sent to the company for who the president's name changed. + * @api ai game + */ +class ScriptEventPresidentRenamed : public ScriptEvent { +public: +#ifndef DOXYGEN_API + /** + * @param company The company of the president. + * @param new_name The new name of the president. + */ + ScriptEventPresidentRenamed(CompanyID company, const std::string &new_name) : + ScriptEvent(ET_PRESIDENT_RENAMED), + company(static_cast(company)), + new_name(new_name) + {} +#endif /* DOXYGEN_API */ + + /** + * Convert an ScriptEvent to the real instance. + * @param instance The instance to convert. + * @return The converted instance. + */ + static ScriptEventPresidentRenamed *Convert(ScriptEvent *instance) { return static_cast(instance); } + + /** + * Get the CompanyID of the company that got its president renamed. + * @return The CompanyID of the company. + */ + ScriptCompany::CompanyID GetCompanyID() { return this->company; } + + /** + * Get the new name of the president. + * @return The new name of the president. + */ + std::optional GetNewName() { return this->new_name; } + +private: + ScriptCompany::CompanyID company; ///< The company of the renamed president. + std::string new_name; ///< The new name of the president. +}; + #endif /* SCRIPT_EVENT_TYPES_HPP */ diff --git a/src/script/api/script_group.cpp b/src/script/api/script_group.cpp index 3f36fb6fca6e2..f75b41a30eafb 100644 --- a/src/script/api/script_group.cpp +++ b/src/script/api/script_group.cpp @@ -98,14 +98,14 @@ EnforceCompanyModeValid(false); EnforcePrecondition(false, IsValidGroup(group_id)); - return ScriptObject::Command::Do(group_id, GroupFlags::GF_REPLACE_PROTECTION, enable, false); + return ScriptObject::Command::Do(group_id, GroupFlags::ReplaceProtection, enable, false); } /* static */ bool ScriptGroup::GetAutoReplaceProtection(GroupID group_id) { if (!IsValidGroup(group_id)) return false; - return HasBit(::Group::Get(group_id)->flags, GroupFlags::GF_REPLACE_PROTECTION); + return HasFlag(::Group::Get(group_id)->flags, GroupFlags::ReplaceProtection); } /* static */ SQInteger ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id) diff --git a/src/settings.cpp b/src/settings.cpp index 40b372212c6ca..6665d171afcc5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1622,6 +1622,7 @@ void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const } SetWindowClassesDirty(WC_GAME_OPTIONS); + if (HasFlag(this->flags, SF_SANDBOX)) SetWindowClassesDirty(WC_CHEATS); if (_save_config) SaveToConfig(); } @@ -1704,6 +1705,27 @@ const SettingDesc *GetSettingFromName(const std::string_view name) return GetCompanySettingFromName(name); } +/** + * Get a collection of settings matching a custom filter. + * @param func Function to filter each setting. + * @returns Vector containing the list of collections. + */ +std::vector GetFilteredSettingCollection(std::function func) +{ + std::vector collection; + + for (const auto &table : GenericSettingTables()) { + for (const auto &desc : table) { + const auto sd = GetSettingDesc(desc); + if (!func(*sd)) continue; + + collection.push_back(sd); + } + } + + return collection; +} + /** * Network-safe changing of settings (server-only). * @param flags operation to perform diff --git a/src/settings_internal.h b/src/settings_internal.h index 73801837db675..083dffab2be18 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -401,4 +401,6 @@ void GetSaveLoadFromSettingTable(SettingTable settings, std::vector &s bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame = false); bool SetSettingValue(const StringSettingDesc *sd, const std::string value, bool force_newgame = false); +std::vector GetFilteredSettingCollection(std::function func); + #endif /* SETTINGS_INTERNAL_H */ diff --git a/src/station_base.h b/src/station_base.h index ea0d4b546548a..9d22745986b14 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -573,7 +573,7 @@ struct Station final : SpecializedStation { return IsAirportTile(tile) && GetStationIndex(tile) == this->index; } - uint32_t GetNewGRFVariable(const ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const override; + uint32_t GetNewGRFVariable(const ResolverObject &object, uint8_t variable, uint32_t parameter, bool &available) const override; void GetTileArea(TileArea *ta, StationType type) const override; }; diff --git a/src/table/build_industry.h b/src/table/build_industry.h index ff459c51bb543..2268094b36c9e 100644 --- a/src/table/build_industry.h +++ b/src/table/build_industry.h @@ -1032,16 +1032,16 @@ static const std::vector _tile_table_sugar_mine { #undef MK /** Array with saw sound, for sawmill */ -static const std::initializer_list _sawmill_sounds = { SND_28_SAWMILL }; +static const std::initializer_list _sawmill_sounds = { SND_28_SAWMILL }; /** Array with whistle sound, for factory */ -static const std::initializer_list _factory_sounds = { SND_03_FACTORY }; +static const std::initializer_list _factory_sounds = { SND_03_FACTORY }; /** Array with 3 animal sounds, for farms */ -static const std::initializer_list _farm_sounds = { SND_24_FARM_1, SND_25_FARM_2, SND_26_FARM_3 }; +static const std::initializer_list _farm_sounds = { SND_24_FARM_1, SND_25_FARM_2, SND_26_FARM_3 }; /** Array with... hem... a sound of toyland */ -static const std::initializer_list _plastic_mine_sounds = { SND_33_PLASTIC_MINE }; +static const std::initializer_list _plastic_mine_sounds = { SND_33_PLASTIC_MINE }; enum IndustryTypes { IT_COAL_MINE = 0, diff --git a/src/table/settings/misc_settings.ini b/src/table/settings/misc_settings.ini index 45051908e0221..7c95c28ccb208 100644 --- a/src/table/settings/misc_settings.ini +++ b/src/table/settings/misc_settings.ini @@ -12,6 +12,7 @@ extern std::string _config_language_file; static constexpr std::initializer_list _support8bppmodes{"no", "system", "hardware"}; static constexpr std::initializer_list _display_opt_modes{"SHOW_TOWN_NAMES", "SHOW_STATION_NAMES", "SHOW_SIGNS", "FULL_ANIMATION", "", "FULL_DETAIL", "WAYPOINTS", "SHOW_COMPETITOR_SIGNS"}; +static constexpr std::initializer_list _facility_display_opt_modes{"TRAIN", "TRUCK_STOP", "BUS_STOP", "AIRPORT", "DOCK"}; #ifdef WITH_COCOA extern bool _allow_hidpi_window; @@ -64,6 +65,13 @@ var = _display_opt def = (1 << DO_SHOW_TOWN_NAMES | 1 << DO_SHOW_STATION_NAMES | 1 << DO_SHOW_SIGNS | 1 << DO_FULL_ANIMATION | 1 << DO_FULL_DETAIL | 1 << DO_SHOW_WAYPOINT_NAMES | 1 << DO_SHOW_COMPETITOR_SIGNS) full = _display_opt_modes +[SDTG_MMANY] +name = ""facility_display_opt"" +type = SLE_UINT8 +var = _facility_display_opt +def = (1 << FACIL_TRAIN | 1 << FACIL_TRUCK_STOP | 1 << FACIL_BUS_STOP | 1 << FACIL_AIRPORT | 1 << FACIL_DOCK) +full = _facility_display_opt_modes + [SDTG_BOOL] name = ""fullscreen"" var = _fullscreen diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 51ad8849c3b47..fe8a32eb6bb14 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -236,6 +236,11 @@ enum OptionMenuEntries { OME_TRANSPARENCIES, OME_SHOW_TOWNNAMES, OME_SHOW_STATIONNAMES, + OME_SHOW_STATIONNAMES_TRAIN, + OME_SHOW_STATIONNAMES_LORRY, + OME_SHOW_STATIONNAMES_BUS, + OME_SHOW_STATIONNAMES_SHIP, + OME_SHOW_STATIONNAMES_PLANE, OME_SHOW_WAYPOINTNAMES, OME_SHOW_SIGNS, OME_SHOW_COMPETITOR_SIGNS, @@ -271,6 +276,11 @@ static CallBackFunction ToolbarOptionsClick(Window *w) list.push_back(MakeDropDownListDividerItem()); list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_TOWN_NAMES), STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES)); list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_STATION_NAMES), STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES)); + list.push_back(MakeDropDownListCheckedItem((_facility_display_opt & FACIL_TRAIN) != 0, STR_SETTINGS_MENU_STATION_NAMES_TRAIN, OME_SHOW_STATIONNAMES_TRAIN, false, false, 1)); + list.push_back(MakeDropDownListCheckedItem((_facility_display_opt & FACIL_TRUCK_STOP) != 0, STR_SETTINGS_MENU_STATION_NAMES_LORRY, OME_SHOW_STATIONNAMES_LORRY, false, false, 1)); + list.push_back(MakeDropDownListCheckedItem((_facility_display_opt & FACIL_BUS_STOP) != 0, STR_SETTINGS_MENU_STATION_NAMES_BUS, OME_SHOW_STATIONNAMES_BUS, false, false, 1)); + list.push_back(MakeDropDownListCheckedItem((_facility_display_opt & FACIL_DOCK) != 0, STR_SETTINGS_MENU_STATION_NAMES_SHIP, OME_SHOW_STATIONNAMES_SHIP, false, false, 1)); + list.push_back(MakeDropDownListCheckedItem((_facility_display_opt & FACIL_AIRPORT) != 0, STR_SETTINGS_MENU_STATION_NAMES_PLANE, OME_SHOW_STATIONNAMES_PLANE, false, false, 1)); list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES), STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES)); list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_SIGNS), STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS)); list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS), STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS)); @@ -284,6 +294,19 @@ static CallBackFunction ToolbarOptionsClick(Window *w) return CBF_NONE; } +/** + * Toggle display station names for a facility. + * @param facility Facility to toggle. + */ +static void ToggleFacilityDisplay(const uint8_t facility) +{ + if ((_facility_display_opt & facility) == 0) { + SETBITS(_facility_display_opt, facility); + } else { + CLRBITS(_facility_display_opt, facility); + } +} + /** * Handle click on one of the entries in the Options button menu. * @@ -303,6 +326,11 @@ static CallBackFunction MenuClickSettings(int index) case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break; case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break; + case OME_SHOW_STATIONNAMES_TRAIN: ToggleFacilityDisplay(FACIL_TRAIN); break; + case OME_SHOW_STATIONNAMES_LORRY: ToggleFacilityDisplay(FACIL_TRUCK_STOP); break; + case OME_SHOW_STATIONNAMES_BUS: ToggleFacilityDisplay(FACIL_BUS_STOP); break; + case OME_SHOW_STATIONNAMES_SHIP: ToggleFacilityDisplay(FACIL_DOCK); break; + case OME_SHOW_STATIONNAMES_PLANE: ToggleFacilityDisplay(FACIL_AIRPORT); break; case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break; case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break; case OME_SHOW_COMPETITOR_SIGNS: diff --git a/src/transparency.h b/src/transparency.h index 782c009f22983..9274fd4d457d0 100644 --- a/src/transparency.h +++ b/src/transparency.h @@ -38,6 +38,7 @@ extern TransparencyOptionBits _transparency_opt; extern TransparencyOptionBits _transparency_lock; extern TransparencyOptionBits _invisibility_opt; extern uint8_t _display_opt; +extern uint8_t _facility_display_opt; /** * Check if the transparency option bit is set diff --git a/src/transparency_gui.cpp b/src/transparency_gui.cpp index d10c6c12d0c05..256a4e7e1a1c3 100644 --- a/src/transparency_gui.cpp +++ b/src/transparency_gui.cpp @@ -24,6 +24,7 @@ TransparencyOptionBits _transparency_opt; ///< The bits that should be transpar TransparencyOptionBits _transparency_lock; ///< Prevent these bits from flipping with X. TransparencyOptionBits _invisibility_opt; ///< The bits that should be invisible. uint8_t _display_opt; ///< What do we want to draw/do? +uint8_t _facility_display_opt; ///< What station facilities to draw. class TransparenciesWindow : public Window { diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index c620f44110265..0c3144d003ebe 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -93,7 +93,7 @@ static void CloseWindowsConsoleThread() #include "../safeguards.h" -static void *_dedicated_video_mem; +static std::unique_ptr _dedicated_video_mem; /* Whether a fork has been done. */ bool _dedicated_forks; @@ -108,11 +108,11 @@ std::optional VideoDriver_Dedicated::Start(const StringList &) this->UpdateAutoResolution(); int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); - _dedicated_video_mem = (bpp == 0) ? nullptr : MallocT(static_cast(_cur_resolution.width) * _cur_resolution.height * (bpp / 8)); + if (bpp != 0) _dedicated_video_mem = std::make_unique(static_cast(_cur_resolution.width) * _cur_resolution.height * (bpp / 8)); _screen.width = _screen.pitch = _cur_resolution.width; _screen.height = _cur_resolution.height; - _screen.dst_ptr = _dedicated_video_mem; + _screen.dst_ptr = _dedicated_video_mem.get(); ScreenSizeChanged(); BlitterFactory::GetCurrentBlitter()->PostResize(); @@ -139,7 +139,7 @@ void VideoDriver_Dedicated::Stop() #ifdef _WIN32 CloseWindowsConsoleThread(); #endif - free(_dedicated_video_mem); + _dedicated_video_mem = nullptr; } void VideoDriver_Dedicated::MakeDirty(int, int, int, int) {} diff --git a/src/viewport.cpp b/src/viewport.cpp index 341845bee79e1..c12b05f0a35cd 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1448,6 +1448,7 @@ static void ViewportAddKdtreeSigns(DrawPixelInfo *dpi) case ViewportSignKdtreeItem::VKI_STATION: { if (!show_stations) break; const BaseStation *st = BaseStation::Get(item.id.station); + if ((_facility_display_opt & st->facilities) == 0) break; /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ if (!show_competitors && _local_company != st->owner && st->owner != OWNER_NONE) break; diff --git a/src/waypoint_base.h b/src/waypoint_base.h index cbf2e1e608899..26fc84c759348 100644 --- a/src/waypoint_base.h +++ b/src/waypoint_base.h @@ -41,7 +41,7 @@ struct Waypoint final : SpecializedStation { return IsRailWaypointTile(tile) && GetStationIndex(tile) == this->index; } - uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint8_t parameter, bool &available) const override; + uint32_t GetNewGRFVariable(const struct ResolverObject &object, uint8_t variable, uint32_t parameter, bool &available) const override; void GetTileArea(TileArea *ta, StationType type) const override; diff --git a/src/widgets/cheat_widget.h b/src/widgets/cheat_widget.h index 204358e6a50d0..93c492d1edfe4 100644 --- a/src/widgets/cheat_widget.h +++ b/src/widgets/cheat_widget.h @@ -14,6 +14,7 @@ enum CheatWidgets : WidgetID { WID_C_NOTE, ///< Note on top of panel for use of cheat. WID_C_PANEL, ///< Panel where all cheats are shown in. + WID_C_SETTINGS, ///< Panel where sandbox settings are shown. }; #endif /* WIDGETS_CHEAT_WIDGET_H */