Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-09-28 02:33:49 +05:00
926 changed files with 37901 additions and 27368 deletions
+74 -91
View File
@@ -21,6 +21,7 @@
#include "town.h"
#include "cheat_type.h"
#include "newgrf_badge.h"
#include "newgrf_badge_gui.h"
#include "newgrf_industries.h"
#include "newgrf_text.h"
#include "newgrf_debug.h"
@@ -48,6 +49,7 @@
#include "timer/timer.h"
#include "timer/timer_window.h"
#include "hotkeys.h"
#include "core/string_consumer.hpp"
#include "widgets/industry_widget.h"
@@ -109,13 +111,14 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
if (indspec->callback_mask.Test(IndustryCallbackMask::CargoSuffix)) {
TileIndex t = (cst != CST_FUND) ? ind->location.tile : INVALID_TILE;
uint16_t callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast<Industry *>(ind), ind_type, t);
std::array<int32_t, 16> regs100;
uint16_t callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast<Industry *>(ind), ind_type, t, regs100);
if (callback == CALLBACK_FAILED) return;
if (indspec->grf_prop.grffile->grf_version < 8) {
if (GB(callback, 0, 8) == 0xFF) return;
if (callback < 0x400) {
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback, regs100);
suffix.display = CSD_CARGO_AMOUNT_TEXT;
return;
}
@@ -123,18 +126,30 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
return;
} else { // GRF version 8 or higher.
if (callback == 0x400) return;
if (callback == 0x401) {
suffix.display = CSD_CARGO;
return;
switch (callback) {
case 0x400:
return;
case 0x401:
suffix.display = CSD_CARGO;
return;
case 0x40E:
suffix.display = CSD_CARGO_TEXT;
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
return;
case 0x40F:
suffix.display = CSD_CARGO_AMOUNT_TEXT;
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
return;
default:
break;
}
if (callback < 0x400) {
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback, 6);
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback, regs100);
suffix.display = CSD_CARGO_AMOUNT_TEXT;
return;
}
if (callback >= 0x800 && callback < 0xC00) {
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback - 0x800, 6);
suffix.text = GetGRFStringWithTextStack(indspec->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback - 0x800, regs100);
suffix.display = CSD_CARGO_TEXT;
return;
}
@@ -184,12 +199,12 @@ static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixTy
}
switch (use_input) {
case CARGOSUFFIX_OUT:
// Handle INDUSTRY_ORIGINAL_NUM_OUTPUTS cargoes
/* Handle INDUSTRY_ORIGINAL_NUM_OUTPUTS cargoes */
if (IsValidCargoType(cargoes[0])) GetCargoSuffix(3, cst, ind, ind_type, indspec, suffixes[0]);
if (IsValidCargoType(cargoes[1])) GetCargoSuffix(4, cst, ind, ind_type, indspec, suffixes[1]);
break;
case CARGOSUFFIX_IN:
// Handle INDUSTRY_ORIGINAL_NUM_INPUTS cargoes
/* Handle INDUSTRY_ORIGINAL_NUM_INPUTS cargoes */
if (IsValidCargoType(cargoes[0])) GetCargoSuffix(0, cst, ind, ind_type, indspec, suffixes[0]);
if (IsValidCargoType(cargoes[1])) GetCargoSuffix(1, cst, ind, ind_type, indspec, suffixes[1]);
if (IsValidCargoType(cargoes[2])) GetCargoSuffix(2, cst, ind, ind_type, indspec, suffixes[2]);
@@ -252,25 +267,6 @@ void SortIndustryTypes()
std::sort(_sorted_industry_types.begin(), _sorted_industry_types.end(), IndustryTypeNameSorter);
}
/**
* Command callback. In case of failure to build an industry, show an error message.
* @param result Result of the command.
* @param tile Tile where the industry is placed.
* @param indtype Industry type.
*/
void CcBuildIndustry(Commands, const CommandCost &result, TileIndex tile, IndustryType indtype, uint32_t, bool, uint32_t)
{
if (result.Succeeded()) return;
if (indtype < NUM_INDUSTRYTYPES) {
const IndustrySpec *indsp = GetIndustrySpec(indtype);
if (indsp->enabled) {
ShowErrorMessage(GetEncodedString(STR_ERROR_CAN_T_BUILD_HERE, indsp->name),
GetEncodedString(result.GetErrorMessage()), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE);
}
}
}
static constexpr NWidgetPart _nested_build_industry_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
@@ -424,7 +420,7 @@ class BuildIndustryWindow : public Window {
if (numcargo > 0) {
cargostring = GetString(prefixstr, CargoSpec::Get(cargolist[firstcargo])->name, cargo_suffix[firstcargo].text) + cargostring;
} else {
cargostring = GetString(prefixstr, STR_JUST_NOTHING, "");
cargostring = GetString(prefixstr, STR_JUST_NOTHING, ""sv);
}
return cargostring;
@@ -474,7 +470,7 @@ public:
for (const auto &indtype : this->list) {
d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(indtype)->name));
}
resize.height = std::max<uint>({this->legend.height, d.height, count.height}) + padding.height;
fill.height = resize.height = std::max<uint>({this->legend.height, d.height, count.height}) + padding.height;
d.width += this->badge_classes.GetTotalColumnsWidth() + this->legend.width + WidgetDimensions::scaled.hsep_wide + WidgetDimensions::scaled.hsep_normal + count.width + padding.width;
d.height = 5 * resize.height;
size = maxdim(size, d);
@@ -633,15 +629,19 @@ public:
/* Get the additional purchase info text, if it has not already been queried. */
if (indsp->callback_mask.Test(IndustryCallbackMask::FundMoreText)) {
uint16_t callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, nullptr, this->selected_type, INVALID_TILE);
std::array<int32_t, 16> regs100;
uint16_t callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, nullptr, this->selected_type, INVALID_TILE, regs100);
if (callback_res != CALLBACK_FAILED && callback_res != 0x400) {
if (callback_res > 0x400) {
std::string str;
if (callback_res == 0x40F) {
str = GetGRFStringWithTextStack(indsp->grf_prop.grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
} else if (callback_res > 0x400) {
ErrorUnknownCallbackResult(indsp->grf_prop.grfid, CBID_INDUSTRY_FUND_MORE_TEXT, callback_res);
} else {
std::string str = GetGRFStringWithTextStack(indsp->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, 6);
if (!str.empty()) {
DrawStringMultiLine(ir, str, TC_YELLOW);
}
str = GetGRFStringWithTextStack(indsp->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, regs100);
}
if (!str.empty()) {
DrawStringMultiLine(ir, str, TC_YELLOW);
}
}
}
@@ -785,7 +785,7 @@ public:
AutoRestoreBackup backup_generating_world(_generating_world, true);
AutoRestoreBackup backup_ignore_industry_restritions(_ignore_industry_restrictions, true);
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, this->selected_type, layout_index, false, seed);
Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
_cm_funding_layout = InteractiveRandomRange((uint32_t)indsp->layouts.size());
} else {
success = Command<CMD_BUILD_INDUSTRY>::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed);
@@ -795,7 +795,7 @@ public:
if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
}
IntervalTimer<TimerWindow> update_interval = {std::chrono::seconds(3), [this](auto) {
const IntervalTimer<TimerWindow> update_interval = {std::chrono::seconds(3), [this](auto) {
citymania::UpdateIndustryHighlight();
if (_game_mode == GM_EDITOR) return;
if (this->selected_type == IT_INVALID) return;
@@ -918,10 +918,10 @@ public:
this->InitNested(window_number);
NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_IV_VIEWPORT);
nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZOOM_LVL_INDUSTRY));
nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ScaleZoomGUI(ZoomLevel::Industry));
const Industry *i = Industry::Get(window_number);
if (!i->IsCargoProduced()) this->DisableWidget(WID_IV_GRAPH);
if (!i->IsCargoProduced() && !i->IsCargoAccepted()) this->DisableWidget(WID_IV_GRAPH);
this->InvalidateData();
}
@@ -959,7 +959,7 @@ public:
SpriteID icon = CargoSpec::Get(cargo_type)->GetCargoIcon();
Dimension d = GetSpriteSize(icon);
Rect ir = r.WithWidth(this->cargo_icon_size.width, rtl).WithHeight(GetCharacterHeight(FS_NORMAL));
DrawSprite(icon, PAL_NONE, CenterBounds(ir.left, ir.right, d.width), CenterBounds(ir.top, ir.bottom, this->cargo_icon_size.height));
DrawSprite(icon, PAL_NONE, CentreBounds(ir.left, ir.right, d.width), CentreBounds(ir.top, ir.bottom, this->cargo_icon_size.height));
}
std::string GetAcceptedCargoString(const Industry::AcceptedCargo &ac, const CargoSuffix &suffix) const
@@ -1065,16 +1065,20 @@ public:
/* Get the extra message for the GUI */
if (ind->callback_mask.Test(IndustryCallbackMask::WindowMoreText)) {
uint16_t callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->location.tile);
std::array<int32_t, 16> regs100;
uint16_t callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->location.tile, regs100);
if (callback_res != CALLBACK_FAILED && callback_res != 0x400) {
if (callback_res > 0x400) {
std::string str;
if (callback_res == 0x40F) {
str = GetGRFStringWithTextStack(ind->grf_prop.grffile, static_cast<GRFStringID>(regs100[0]), std::span{regs100}.subspan(1));
} else if (callback_res > 0x400) {
ErrorUnknownCallbackResult(ind->grf_prop.grfid, CBID_INDUSTRY_WINDOW_MORE_TEXT, callback_res);
} else {
std::string str = GetGRFStringWithTextStack(ind->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, 6);
if (!str.empty()) {
ir.top += WidgetDimensions::scaled.vsep_wide;
ir.top = DrawStringMultiLine(ir, str, TC_YELLOW);
}
str = GetGRFStringWithTextStack(ind->grf_prop.grffile, GRFSTR_MISC_GRF_TEXT + callback_res, regs100);
}
if (!str.empty()) {
ir.top += WidgetDimensions::scaled.vsep_wide;
ir.top = DrawStringMultiLine(ir, str, TC_YELLOW);
}
}
}
@@ -1224,8 +1228,9 @@ public:
}
}
void OnMouseWheel(int wheel) override
void OnMouseWheel(int wheel, WidgetID widget) override
{
if (widget != WID_IV_VIEWPORT) return;
if (_settings_client.gui.scrollwheel_scrolling != SWS_OFF) {
DoZoomInOutWindow(wheel < 0 ? ZOOM_IN : ZOOM_OUT, this);
}
@@ -1236,16 +1241,17 @@ public:
if (!str.has_value() || str->empty()) return;
Industry *i = Industry::Get(this->window_number);
uint value = atoi(str->c_str());
auto value = ParseInteger(*str, 10, true);
if (!value.has_value()) return;
switch (this->editbox_line) {
case IL_NONE: NOT_REACHED();
case IL_MULTIPLIER:
i->prod_level = ClampU(RoundDivSU(value * PRODLEVEL_DEFAULT, 100), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
i->prod_level = ClampU(RoundDivSU(*value * PRODLEVEL_DEFAULT, 100), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM);
break;
default:
i->produced[this->editbox_line - IL_RATE1].rate = ClampU(RoundDivSU(value, 8), 0, 255);
i->produced[this->editbox_line - IL_RATE1].rate = ClampU(RoundDivSU(*value, 8), 0, 255);
break;
}
UpdateIndustryProduction(i);
@@ -1312,7 +1318,7 @@ static constexpr NWidgetPart _nested_industry_view_widgets[] = {
EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_VIEW_PRODUCTION_GRAPH, STR_INDUSTRY_VIEW_PRODUCTION_GRAPH_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GRAPH), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_INDUSTRY_VIEW_CARGO_GRAPH, STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP),
NWidget(WWT_RESIZEBOX, COLOUR_CREAM),
EndContainer(),
};
@@ -1413,10 +1419,6 @@ static bool CargoFilter(const Industry * const *industry, const std::pair<CargoT
static GUIIndustryList::FilterFunction * const _industry_filter_funcs[] = { &CargoFilter };
/** Enum referring to the Hotkeys in the industry directory window */
enum IndustryDirectoryHotkeys : int32_t {
IDHK_FOCUS_FILTER_BOX, ///< Focus the filter box
};
/**
* The list of industries.
*/
@@ -1854,7 +1856,7 @@ public:
case WID_ID_INDUSTRY_LIST: {
Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE);
resize.height = d.height;
fill.height = resize.height = d.height;
d.height *= 5;
d.width += padding.width;
d.height += padding.height;
@@ -1916,7 +1918,7 @@ public:
}
}
void OnDropdownSelect(WidgetID widget, int index) override
void OnDropdownSelect(WidgetID widget, int index, int) override
{
switch (widget) {
case WID_ID_DROPDOWN_CRITERIA: {
@@ -1963,7 +1965,7 @@ public:
}
/** Rebuild the industry list on a regular interval. */
IntervalTimer<TimerWindow> rebuild_interval = {std::chrono::seconds(3), [this](auto) {
const IntervalTimer<TimerWindow> rebuild_interval = {std::chrono::seconds(3), [this](auto) {
this->industries.ForceResort();
this->BuildSortIndustriesList();
}};
@@ -1991,21 +1993,8 @@ public:
}
}
EventState OnHotkey(int hotkey) override
{
switch (hotkey) {
case IDHK_FOCUS_FILTER_BOX:
this->SetFocusedWidget(WID_ID_FILTER);
SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
break;
default:
return ES_NOT_HANDLED;
}
return ES_HANDLED;
}
static inline HotkeyList hotkeys {"industrydirectory", {
Hotkey('F', "focus_filter_box", IDHK_FOCUS_FILTER_BOX),
Hotkey('F', "focus_filter_box", WID_ID_FILTER),
}};
};
@@ -2092,8 +2081,8 @@ struct CargoesField {
static Dimension cargo_space;
static Dimension cargo_stub;
static const int INDUSTRY_LINE_COLOUR;
static const int CARGO_LINE_COLOUR;
static const PixelColour INDUSTRY_LINE_COLOUR;
static const PixelColour CARGO_LINE_COLOUR;
static int small_height, normal_height;
static int cargo_field_width;
@@ -2501,8 +2490,8 @@ int CargoesField::vert_inter_industry_space; ///< Amount of space between two in
int CargoesField::blob_distance; ///< Distance of the industry legend colour from the edge of the industry box.
const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box.
const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo.
const PixelColour CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box.
const PixelColour CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo.
/** A single row of #CargoesField. */
struct CargoesRow {
@@ -2731,7 +2720,7 @@ struct IndustryCargoesWindow : public Window {
{
switch (widget) {
case WID_IC_PANEL:
resize.height = CargoesField::normal_height;
fill.height = resize.height = CargoesField::normal_height;
size.width = CargoesField::industry_width * 3 + CargoesField::cargo_field_width * 2 + WidgetDimensions::scaled.frametext.Horizontal();
size.height = CargoesField::small_height + 2 * resize.height + WidgetDimensions::scaled.frametext.Vertical();
break;
@@ -2798,19 +2787,13 @@ struct IndustryCargoesWindow : public Window {
*/
static bool HousesCanAccept(const std::span<const CargoType> cargoes)
{
HouseZones climate_mask;
switch (_settings_game.game_creation.landscape) {
case LandscapeType::Temperate: climate_mask = HZ_TEMP; break;
case LandscapeType::Arctic: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
case LandscapeType::Tropic: climate_mask = HZ_SUBTROPIC; break;
case LandscapeType::Toyland: climate_mask = HZ_TOYLND; break;
default: NOT_REACHED();
}
HouseZones climate_mask = GetClimateMaskForLandscape();
for (const CargoType cargo_type : cargoes) {
if (!IsValidCargoType(cargo_type)) continue;
for (const auto &hs : HouseSpec::Specs()) {
if (!hs.enabled || !(hs.building_availability & climate_mask)) continue;
if (!hs.enabled || !hs.building_availability.Any(climate_mask)) continue;
for (uint j = 0; j < lengthof(hs.accepts_cargo); j++) {
if (hs.cargo_acceptance[j] > 0 && cargo_type == hs.accepts_cargo[j]) return true;
@@ -3188,7 +3171,7 @@ struct IndustryCargoesWindow : public Window {
case WID_IC_NOTIFY:
this->ToggleWidgetLoweredState(WID_IC_NOTIFY);
this->SetWidgetDirty(WID_IC_NOTIFY);
if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
SndClickBeep();
if (this->IsWidgetLowered(WID_IC_NOTIFY)) {
if (FindWindowByClass(WC_SMALLMAP) == nullptr) citymania::ShowSmallMap();
@@ -3238,7 +3221,7 @@ struct IndustryCargoesWindow : public Window {
}
}
void OnDropdownSelect(WidgetID widget, int index) override
void OnDropdownSelect(WidgetID widget, int index, int) override
{
if (index < 0) return;