43 #include "table/strings.h"
49 bool _ignore_restrictions;
91 suffix.
text[0] =
'\0';
100 if (
GB(callback, 0, 8) == 0xFF)
return;
101 if (callback < 0x400) {
112 if (callback == 0x400)
return;
113 if (callback == 0x401) {
117 if (callback < 0x400) {
124 if (callback >= 0x800 && callback < 0xC00) {
147 template <
typename TC,
typename TS>
151 for (uint j = 0; j <
lengthof(cargoes); j++) {
153 GetCargoSuffix(cb_offset + j, cst, ind, ind_type, indspec, suffixes[j]);
155 suffixes[j].text[0] =
'\0';
165 static char industry_name[2][64];
168 GetString(industry_name[0], indsp1->
name,
lastof(industry_name[0]));
171 GetString(industry_name[1], indsp2->
name,
lastof(industry_name[1]));
173 int r =
strnatcmp(industry_name[0], industry_name[1]);
176 return (r != 0) ? r : (*a - *b);
204 uint8 indtype =
GB(p1, 0, 8);
214 static const NWidgetPart _nested_build_industry_widgets[] = {
223 NWidget(
WWT_MATRIX, COLOUR_DARK_GREEN,
WID_DPI_MATRIX_WIDGET),
SetMatrixDataTip(1, 0, STR_FUND_INDUSTRY_SELECTION_TOOLTIP),
SetFill(1, 0),
SetResize(1, 1),
SetScrollbar(
WID_DPI_SCROLLBAR),
230 SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
238 WDP_AUTO,
"build_industry", 170, 212,
241 _nested_build_industry_widgets,
lengthof(_nested_build_industry_widgets)
267 if (_game_mode == GM_EDITOR) {
341 for (byte i = 0; i < this->
count; i++) {
347 d.height = 5 * resize->height;
356 for (byte i = 0; i < this->
count; i++) {
363 StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
377 str = STR_INDUSTRY_VIEW_PRODUCES_CARGO;
381 for (byte j = 0; j <
lengthof(indsp->produced_cargo); j++) {
382 if (indsp->produced_cargo[j] ==
CT_INVALID)
continue;
400 d.width += padding.width;
401 d.height += padding.height;
414 if (_game_mode == GM_EDITOR) {
416 SetDParam(0, STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY);
429 uint text_left, text_right, icon_left, icon_right;
432 icon_left = icon_right - 10;
437 icon_right = icon_left + 10;
447 DrawString(text_left, text_right, y, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE);
453 DrawString(text_left, text_right, y, indsp->
name, selected ? TC_WHITE : TC_ORANGE);
467 DrawStringMultiLine(left, right, y, bottom, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP);
473 if (_game_mode != GM_EDITOR) {
475 DrawString(left, right, y, STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST);
482 StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
497 str = STR_INDUSTRY_VIEW_PRODUCES_CARGO;
501 for (byte j = 0; j <
lengthof(indsp->produced_cargo); j++) {
502 if (indsp->produced_cargo[j] ==
CT_INVALID)
continue;
515 if (callback_res > 0x400) {
519 if (str != STR_UNDEFINED) {
537 if (y < this->
count) {
597 uint32 seed = InteractiveRandom();
599 if (_game_mode == GM_EDITOR) {
609 _ignore_restrictions =
true;
611 DoCommandP(tile, (InteractiveRandomRange(indsp->
num_table) << 8) | this->selected_type, seed,
615 _ignore_restrictions =
false;
666 if (!gui_scope)
return;
675 void ShowBuildIndustryWindow()
682 static void UpdateIndustryProduction(
Industry *i);
684 static inline bool IsProductionAlterable(
const Industry *i)
688 (is->production_rate[0] != 0 || is->production_rate[1] != 0 || is->
IsRawIndustry()) &&
760 bool has_accept =
false;
780 switch (cargo_suffix[j].display) {
833 if (this->editable ==
EA_RATE) {
856 if (callback_res > 0x400) {
860 if (message != STR_NULL && message != STR_UNDEFINED) {
901 if (pt.y >= this->production_offset_y) {
916 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(widget);
945 default: NOT_REACHED();
948 UpdateIndustryProduction(i);
967 default: NOT_REACHED();
1013 uint value = atoi(str);
1025 UpdateIndustryProduction(i);
1036 if (!gui_scope)
return;
1038 if (IsProductionAlterable(i)) {
1057 static void UpdateIndustryProduction(
Industry *i)
1081 NWidget(
NWID_VIEWPORT, INVALID_COLOUR,
WID_IV_VIEWPORT),
SetMinimalSize(254, 86),
SetFill(1, 0),
SetPadding(1, 1, 1, 1),
SetResize(1, 1),
1095 WDP_AUTO,
"view_industry", 260, 120,
1098 _nested_industry_view_widgets,
lengthof(_nested_industry_view_widgets)
1101 void ShowIndustryViewWindow(
int industry)
1141 static const Industry *last_industry;
1144 static const StringID sorter_names[];
1147 GUIIndustryList industries;
1154 this->industries.
Clear();
1157 FOR_ALL_INDUSTRIES(i) {
1158 *this->industries.
Append() = i;
1166 if (!this->industries.
Sort())
return;
1167 IndustryDirectoryWindow::last_industry = NULL;
1198 if (p1 > p2)
Swap(p1, p2);
1200 return (p1 << 8) + p2;
1206 static char buf_cache[96];
1207 static char buf[96];
1210 GetString(buf, STR_INDUSTRY_NAME,
lastof(buf));
1212 if (*b != last_industry) {
1215 GetString(buf_cache, STR_INDUSTRY_NAME,
lastof(buf_cache));
1228 int r = it_a - it_b;
1235 uint prod_a = 0, prod_b = 0;
1236 for (uint i = 0; i <
lengthof((*a)->produced_cargo); i++) {
1237 if ((*a)->produced_cargo[i] !=
CT_INVALID) prod_a += (*a)->last_month_production[i];
1238 if ((*b)->produced_cargo[i] !=
CT_INVALID) prod_b += (*b)->last_month_production[i];
1240 int r = prod_a - prod_b;
1284 case 1:
return STR_INDUSTRY_DIRECTORY_ITEM_NOPROD;
1285 case 5:
return STR_INDUSTRY_DIRECTORY_ITEM;
1286 default:
return STR_INDUSTRY_DIRECTORY_ITEM_TWO;
1296 this->industries.
SetListing(this->last_sorting);
1297 this->industries.
SetSortFuncs(IndustryDirectoryWindow::sorter_funcs);
1306 this->last_sorting = this->industries.
GetListing();
1324 if (this->industries.
Length() == 0) {
1328 for (uint i = this->vscroll->
GetPosition(); i < this->industries.
Length(); i++) {
1345 d.height += padding.height;
1346 *size =
maxdim(*size, d);
1352 for (uint i = 0; IndustryDirectoryWindow::sorter_names[i] !=
INVALID_STRING_ID; i++) {
1355 d.width += padding.width;
1356 d.height += padding.height;
1357 *size =
maxdim(*size, d);
1363 for (uint i = 0; i < this->industries.
Length(); i++) {
1366 resize->height = d.height;
1370 *size =
maxdim(*size, d);
1391 if (p < this->industries.
Length()) {
1405 if (this->industries.
SortType() != index) {
1444 Listing IndustryDirectoryWindow::last_sorting = {
false, 0};
1445 const Industry *IndustryDirectoryWindow::last_industry = NULL;
1449 &IndustryNameSorter,
1450 &IndustryTypeSorter,
1451 &IndustryProductionSorter,
1452 &IndustryTransportedCargoSorter
1456 const StringID IndustryDirectoryWindow::sorter_names[] = {
1459 STR_SORT_BY_PRODUCTION,
1460 STR_SORT_BY_TRANSPORTED,
1467 WDP_AUTO,
"list_industries", 428, 190,
1470 _nested_industry_directory_widgets,
lengthof(_nested_industry_directory_widgets)
1473 void ShowIndustryDirectory()
1492 SetDataTip(STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP, STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP),
1495 SetDataTip(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY, STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP),
1497 SetDataTip(STR_INDUSTRY_CARGOES_SELECT_CARGO, STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP),
1509 WDP_AUTO,
"industry_cargoes", 300, 210,
1512 _nested_industry_cargoes_widgets,
lengthof(_nested_industry_cargoes_widgets)
1582 this->u.industry.ind_type =
ind_type;
1600 for (
int i = 0; i < this->u.cargo.num_cargoes; i++) {
1601 if (cargo == this->u.cargo.vertical_cargoes[i]) {
1606 if (column < 0)
return -1;
1609 assert(this->u.cargo.supp_cargoes[column] ==
INVALID_CARGO);
1610 this->u.cargo.supp_cargoes[column] = column;
1612 assert(this->u.cargo.cust_cargoes[column] ==
INVALID_CARGO);
1613 this->u.cargo.cust_cargoes[column] = column;
1627 if (this->u.cargo.supp_cargoes[i] !=
INVALID_CARGO)
return true;
1628 if (this->u.cargo.cust_cargoes[i] !=
INVALID_CARGO)
return true;
1647 for (i = 0; i < MAX_CARGOES && i < length; i++) {
1649 this->u.cargo.vertical_cargoes[num] = cargoes[i];
1653 this->u.cargo.num_cargoes = (count < 0) ? num : count;
1655 this->u.cargo.top_end =
top_end;
1671 for (i = 0; i < MAX_CARGOES && i < length; i++) this->u.cargo_label.cargoes[i] = cargoes[i];
1673 this->u.cargo_label.left_align = left_align;
1683 this->u.header = textid;
1695 switch (this->u.cargo.num_cargoes) {
1700 default: NOT_REACHED();
1709 void Draw(
int xpos,
int ypos)
const
1711 switch (this->
type) {
1735 int blob_left, blob_right;
1750 const CargoID *other_right, *other_left;
1752 other_right = this->u.industry.other_accepted;
1753 other_left = this->u.industry.other_produced;
1755 other_right = this->u.industry.other_produced;
1756 other_left = this->u.industry.other_accepted;
1781 int colpos = cargo_base;
1782 for (
int i = 0; i < this->u.cargo.num_cargoes; i++) {
1794 const CargoID *hor_left, *hor_right;
1796 hor_left = this->u.cargo.cust_cargoes;
1797 hor_right = this->u.cargo.supp_cargoes;
1799 hor_left = this->u.cargo.supp_cargoes;
1800 hor_right = this->u.cargo.cust_cargoes;
1805 int col = hor_left[i];
1808 for (; col > 0; col--) {
1816 int col = hor_right[i];
1819 for (; col < this->u.cargo.num_cargoes - 1; col++) {
1862 for (col = 0; col < this->u.cargo.num_cargoes; col++) {
1863 if (pt.x < cpos)
break;
1880 if (this->u.cargo.supp_cargoes[row] !=
INVALID_CARGO)
return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]];
1887 if (col == this->u.cargo.num_cargoes) {
1888 if (this->u.cargo.cust_cargoes[row] !=
INVALID_CARGO)
return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]];
1889 if (right != NULL) {
1900 return (this->u.cargo.supp_cargoes[row] !=
INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] :
INVALID_CARGO;
1903 return (this->u.cargo.cust_cargoes[row] !=
INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] :
INVALID_CARGO;
1924 return this->u.cargo_label.cargoes[row];
1986 int other_count = 0;
1989 for (uint i = 0; i <
lengthof(indsp->produced_cargo); i++) {
1990 int col = cargo_fld->
ConnectCargo(indsp->produced_cargo[i],
true);
1991 if (col < 0) others[other_count++] = indsp->produced_cargo[i];
1995 for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) {
2000 for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
2002 if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->
ConnectCargo(cid,
true);
2021 for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
2022 int col = cargo_fld->
ConnectCargo(cargo_fld->u.
cargo.vertical_cargoes[i], !accepting);
2023 if (col >= 0) cargoes[col] = cargo_fld->u.
cargo.vertical_cargoes[i];
2043 int other_count = 0;
2048 if (col < 0) others[other_count++] = indsp->
accepts_cargo[i];
2052 for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) {
2057 for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
2130 CargoesField::small_height = d.height;
2137 if (!indsp->
enabled)
continue;
2140 d.width =
max(d.width, this->ind_textsize.width);
2149 if (!csp->
IsValid())
continue;
2157 uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + MAX_CARGOES *
FONT_HEIGHT_NORMAL + (MAX_CARGOES - 1) * CargoesField::VERT_CARGO_SPACE;
2160 CargoesField::industry_width = d.width;
2161 CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE;
2172 size->width =
max(size->width, this->ind_textsize.width + padding.width);
2176 size->width =
max(size->width, this->cargo_textsize.width + padding.width);
2206 while (length1 > 0) {
2208 for (uint i = 0; i < length2; i++)
if (*cargoes1 == cargoes2[i])
return true;
2224 for (uint i = 0; i < length; i++) {
2226 if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL)
return true;
2241 case LT_TEMPERATE: climate_mask =
HZ_TEMP;
break;
2244 case LT_TOYLAND: climate_mask =
HZ_TOYLND;
break;
2245 default: NOT_REACHED();
2247 for (uint i = 0; i < length; i++) {
2273 if (!indsp->
enabled)
continue;
2291 if (!indsp->
enabled)
continue;
2306 while (top < bottom && !this->
fields[top].columns[column].HasConnection()) {
2310 this->
fields[
top].columns[column].u.cargo.top_end =
true;
2312 while (bottom > top && !this->
fields[bottom].columns[column].HasConnection()) {
2316 this->
fields[bottom].columns[column].u.cargo.bottom_end =
true;
2328 this->
fields[row].columns[col].MakeIndustry(it);
2330 this->
fields[row].ConnectIndustryProduced(col);
2332 this->
fields[row].ConnectIndustryAccepted(col);
2354 this->GetWidget<NWidgetCore>(
WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION;
2373 int num_indrows =
max(3,
max(num_supp, num_cust));
2374 for (
int i = 0; i < num_indrows; i++) {
2383 int central_row = 1 + num_indrows / 2;
2384 this->
fields[central_row].columns[2].MakeIndustry(it);
2385 this->
fields[central_row].ConnectIndustryProduced(2);
2386 this->
fields[central_row].ConnectIndustryAccepted(2);
2389 this->
fields[central_row - 1].MakeCargoLabel(2,
true);
2390 this->
fields[central_row + 1].MakeCargoLabel(2,
false);
2397 if (!indsp->
enabled)
continue;
2400 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it);
2405 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, it);
2410 if (houses_supply) {
2411 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES);
2414 if (houses_accept) {
2415 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, NUM_INDUSTRYTYPES);
2433 this->GetWidget<NWidgetCore>(
WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_CARGO_CAPTION;
2449 int num_indrows =
max(num_supp, num_cust);
2450 for (
int i = 0; i < num_indrows; i++) {
2459 this->
fields[num_indrows].MakeCargoLabel(0,
false);
2466 if (!indsp->
enabled)
continue;
2469 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it);
2474 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, it);
2479 if (houses_supply) {
2480 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES);
2483 if (houses_accept) {
2484 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, NUM_INDUSTRYTYPES);
2504 if (!gui_scope)
return;
2522 int width = r.right - r.left + 1;
2526 _cur_dpi = &tmp_dpi;
2535 int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height;
2536 if (vpos + row_height >= 0) {
2537 int xpos = left_pos;
2546 while (col >= 0 && col <= last_column) {
2547 this->
fields[i].columns[col].Draw(xpos, vpos);
2548 xpos += (col & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width;
2553 if (vpos >= height)
break;
2573 if (pt.y < vpos)
return false;
2575 int row = (pt.y - vpos) / CargoesField::normal_height;
2576 if (row + 1 >= (
int)this->
fields.
Length())
return false;
2577 vpos = pt.y - vpos - row * CargoesField::normal_height;
2581 if (pt.x < xpos)
return false;
2583 for (column = 0; column <= 5; column++) {
2584 int width = (column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width;
2585 if (pt.x < xpos + width)
break;
2589 if (column > num_columns)
return false;
2596 fieldxy->x = num_columns - column;
2597 xy->x = ((column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width) - xpos;
2599 fieldxy->x = column;
2613 switch (fld->
type) {
2619 CargoesField *lft = (fieldxy.x > 0) ? this->
fields[fieldxy.y].columns + fieldxy.x - 1 : NULL;
2620 CargoesField *rgt = (fieldxy.x < 4) ? this->
fields[fieldxy.y].columns + fieldxy.x + 1 : NULL;
2655 if (lst->
Length() == 0) {
2669 if (!indsp->
enabled)
continue;
2672 if (lst->
Length() == 0) {
2685 if (index < 0)
return;
2707 switch (fld->
type) {
2709 CargoesField *lft = (fieldxy.x > 0) ? this->
fields[fieldxy.y].columns + fieldxy.x - 1 : NULL;
2710 CargoesField *rgt = (fieldxy.x < 4) ? this->
fields[fieldxy.y].columns + fieldxy.x + 1 : NULL;
2722 GuiShowTooltips(
this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, TCC_HOVER);
2732 params[0] = csp->
name;
2733 GuiShowTooltips(
this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, TCC_HOVER);
2760 if (
id >= NUM_INDUSTRYTYPES)
return;