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;
785 switch (cargo_suffix[j].display) {
790 str = stockpiling ? STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT : STR_INDUSTRY_VIEW_ACCEPT_CARGO;
797 str = STR_INDUSTRY_VIEW_ACCEPT_CARGO;
826 if (this->editable ==
EA_RATE) {
849 if (callback_res > 0x400) {
853 if (message != STR_NULL && message != STR_UNDEFINED) {
894 if (pt.y >= this->production_offset_y) {
909 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(widget);
938 default: NOT_REACHED();
941 UpdateIndustryProduction(i);
960 default: NOT_REACHED();
1006 uint value = atoi(str);
1018 UpdateIndustryProduction(i);
1029 if (!gui_scope)
return;
1031 if (IsProductionAlterable(i)) {
1050 static void UpdateIndustryProduction(
Industry *i)
1074 NWidget(
NWID_VIEWPORT, INVALID_COLOUR,
WID_IV_VIEWPORT),
SetMinimalSize(254, 86),
SetFill(1, 0),
SetPadding(1, 1, 1, 1),
SetResize(1, 1),
1088 WDP_AUTO,
"view_industry", 260, 120,
1091 _nested_industry_view_widgets,
lengthof(_nested_industry_view_widgets)
1094 void ShowIndustryViewWindow(
int industry)
1134 static const Industry *last_industry;
1137 static const StringID sorter_names[];
1140 GUIIndustryList industries;
1147 this->industries.
Clear();
1150 FOR_ALL_INDUSTRIES(i) {
1151 *this->industries.
Append() = i;
1159 if (!this->industries.
Sort())
return;
1160 IndustryDirectoryWindow::last_industry = NULL;
1191 if (p1 > p2)
Swap(p1, p2);
1193 return (p1 << 8) + p2;
1199 static char buf_cache[96];
1200 static char buf[96];
1203 GetString(buf, STR_INDUSTRY_NAME,
lastof(buf));
1205 if (*b != last_industry) {
1208 GetString(buf_cache, STR_INDUSTRY_NAME,
lastof(buf_cache));
1221 int r = it_a - it_b;
1228 uint prod_a = 0, prod_b = 0;
1229 for (uint i = 0; i <
lengthof((*a)->produced_cargo); i++) {
1230 if ((*a)->produced_cargo[i] !=
CT_INVALID) prod_a += (*a)->last_month_production[i];
1231 if ((*b)->produced_cargo[i] !=
CT_INVALID) prod_b += (*b)->last_month_production[i];
1233 int r = prod_a - prod_b;
1277 case 1:
return STR_INDUSTRY_DIRECTORY_ITEM_NOPROD;
1278 case 5:
return STR_INDUSTRY_DIRECTORY_ITEM;
1279 default:
return STR_INDUSTRY_DIRECTORY_ITEM_TWO;
1289 this->industries.
SetListing(this->last_sorting);
1290 this->industries.
SetSortFuncs(IndustryDirectoryWindow::sorter_funcs);
1299 this->last_sorting = this->industries.
GetListing();
1317 if (this->industries.
Length() == 0) {
1321 for (uint i = this->vscroll->
GetPosition(); i < this->industries.
Length(); i++) {
1338 d.height += padding.height;
1339 *size =
maxdim(*size, d);
1345 for (uint i = 0; IndustryDirectoryWindow::sorter_names[i] !=
INVALID_STRING_ID; i++) {
1348 d.width += padding.width;
1349 d.height += padding.height;
1350 *size =
maxdim(*size, d);
1356 for (uint i = 0; i < this->industries.
Length(); i++) {
1359 resize->height = d.height;
1363 *size =
maxdim(*size, d);
1384 if (p < this->industries.
Length()) {
1398 if (this->industries.
SortType() != index) {
1437 Listing IndustryDirectoryWindow::last_sorting = {
false, 0};
1438 const Industry *IndustryDirectoryWindow::last_industry = NULL;
1442 &IndustryNameSorter,
1443 &IndustryTypeSorter,
1444 &IndustryProductionSorter,
1445 &IndustryTransportedCargoSorter
1449 const StringID IndustryDirectoryWindow::sorter_names[] = {
1452 STR_SORT_BY_PRODUCTION,
1453 STR_SORT_BY_TRANSPORTED,
1460 WDP_AUTO,
"list_industries", 428, 190,
1463 _nested_industry_directory_widgets,
lengthof(_nested_industry_directory_widgets)
1466 void ShowIndustryDirectory()
1485 SetDataTip(STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP, STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP),
1488 SetDataTip(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY, STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP),
1490 SetDataTip(STR_INDUSTRY_CARGOES_SELECT_CARGO, STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP),
1502 WDP_AUTO,
"industry_cargoes", 300, 210,
1505 _nested_industry_cargoes_widgets,
lengthof(_nested_industry_cargoes_widgets)
1575 this->u.industry.ind_type =
ind_type;
1593 for (
int i = 0; i < this->u.cargo.num_cargoes; i++) {
1594 if (cargo == this->u.cargo.vertical_cargoes[i]) {
1599 if (column < 0)
return -1;
1602 assert(this->u.cargo.supp_cargoes[column] ==
INVALID_CARGO);
1603 this->u.cargo.supp_cargoes[column] = column;
1605 assert(this->u.cargo.cust_cargoes[column] ==
INVALID_CARGO);
1606 this->u.cargo.cust_cargoes[column] = column;
1620 if (this->u.cargo.supp_cargoes[i] !=
INVALID_CARGO)
return true;
1621 if (this->u.cargo.cust_cargoes[i] !=
INVALID_CARGO)
return true;
1640 for (i = 0; i < MAX_CARGOES && i < length; i++) {
1642 this->u.cargo.vertical_cargoes[num] = cargoes[i];
1646 this->u.cargo.num_cargoes = (count < 0) ? num : count;
1648 this->u.cargo.top_end =
top_end;
1664 for (i = 0; i < MAX_CARGOES && i < length; i++) this->u.cargo_label.cargoes[i] = cargoes[i];
1666 this->u.cargo_label.left_align = left_align;
1676 this->u.header = textid;
1688 switch (this->u.cargo.num_cargoes) {
1693 default: NOT_REACHED();
1702 void Draw(
int xpos,
int ypos)
const
1704 switch (this->
type) {
1728 int blob_left, blob_right;
1743 const CargoID *other_right, *other_left;
1745 other_right = this->u.industry.other_accepted;
1746 other_left = this->u.industry.other_produced;
1748 other_right = this->u.industry.other_produced;
1749 other_left = this->u.industry.other_accepted;
1774 int colpos = cargo_base;
1775 for (
int i = 0; i < this->u.cargo.num_cargoes; i++) {
1787 const CargoID *hor_left, *hor_right;
1789 hor_left = this->u.cargo.cust_cargoes;
1790 hor_right = this->u.cargo.supp_cargoes;
1792 hor_left = this->u.cargo.supp_cargoes;
1793 hor_right = this->u.cargo.cust_cargoes;
1798 int col = hor_left[i];
1801 for (; col > 0; col--) {
1809 int col = hor_right[i];
1812 for (; col < this->u.cargo.num_cargoes - 1; col++) {
1855 for (col = 0; col < this->u.cargo.num_cargoes; col++) {
1856 if (pt.x < cpos)
break;
1873 if (this->u.cargo.supp_cargoes[row] !=
INVALID_CARGO)
return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]];
1880 if (col == this->u.cargo.num_cargoes) {
1881 if (this->u.cargo.cust_cargoes[row] !=
INVALID_CARGO)
return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]];
1882 if (right != NULL) {
1893 return (this->u.cargo.supp_cargoes[row] !=
INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] :
INVALID_CARGO;
1896 return (this->u.cargo.cust_cargoes[row] !=
INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] :
INVALID_CARGO;
1917 return this->u.cargo_label.cargoes[row];
1979 int other_count = 0;
1982 for (uint i = 0; i <
lengthof(indsp->produced_cargo); i++) {
1983 int col = cargo_fld->
ConnectCargo(indsp->produced_cargo[i],
true);
1984 if (col < 0) others[other_count++] = indsp->produced_cargo[i];
1988 for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) {
1993 for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
1995 if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->
ConnectCargo(cid,
true);
2014 for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
2015 int col = cargo_fld->
ConnectCargo(cargo_fld->u.
cargo.vertical_cargoes[i], !accepting);
2016 if (col >= 0) cargoes[col] = cargo_fld->u.
cargo.vertical_cargoes[i];
2036 int other_count = 0;
2041 if (col < 0) others[other_count++] = indsp->
accepts_cargo[i];
2045 for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) {
2050 for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
2123 CargoesField::small_height = d.height;
2130 if (!indsp->
enabled)
continue;
2133 d.width =
max(d.width, this->ind_textsize.width);
2142 if (!csp->
IsValid())
continue;
2150 uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + MAX_CARGOES *
FONT_HEIGHT_NORMAL + (MAX_CARGOES - 1) * CargoesField::VERT_CARGO_SPACE;
2153 CargoesField::industry_width = d.width;
2154 CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE;
2165 size->width =
max(size->width, this->ind_textsize.width + padding.width);
2169 size->width =
max(size->width, this->cargo_textsize.width + padding.width);
2199 while (length1 > 0) {
2201 for (uint i = 0; i < length2; i++)
if (*cargoes1 == cargoes2[i])
return true;
2217 for (uint i = 0; i < length; i++) {
2219 if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL)
return true;
2234 case LT_TEMPERATE: climate_mask =
HZ_TEMP;
break;
2237 case LT_TOYLAND: climate_mask =
HZ_TOYLND;
break;
2238 default: NOT_REACHED();
2240 for (uint i = 0; i < length; i++) {
2266 if (!indsp->
enabled)
continue;
2284 if (!indsp->
enabled)
continue;
2299 while (top < bottom && !this->
fields[top].columns[column].HasConnection()) {
2303 this->
fields[
top].columns[column].u.cargo.top_end =
true;
2305 while (bottom > top && !this->
fields[bottom].columns[column].HasConnection()) {
2309 this->
fields[bottom].columns[column].u.cargo.bottom_end =
true;
2321 this->
fields[row].columns[col].MakeIndustry(it);
2323 this->
fields[row].ConnectIndustryProduced(col);
2325 this->
fields[row].ConnectIndustryAccepted(col);
2347 this->GetWidget<NWidgetCore>(
WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION;
2366 int num_indrows =
max(3,
max(num_supp, num_cust));
2367 for (
int i = 0; i < num_indrows; i++) {
2376 int central_row = 1 + num_indrows / 2;
2377 this->
fields[central_row].columns[2].MakeIndustry(it);
2378 this->
fields[central_row].ConnectIndustryProduced(2);
2379 this->
fields[central_row].ConnectIndustryAccepted(2);
2382 this->
fields[central_row - 1].MakeCargoLabel(2,
true);
2383 this->
fields[central_row + 1].MakeCargoLabel(2,
false);
2390 if (!indsp->
enabled)
continue;
2393 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it);
2398 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, it);
2403 if (houses_supply) {
2404 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES);
2407 if (houses_accept) {
2408 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, NUM_INDUSTRYTYPES);
2426 this->GetWidget<NWidgetCore>(
WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_CARGO_CAPTION;
2442 int num_indrows =
max(num_supp, num_cust);
2443 for (
int i = 0; i < num_indrows; i++) {
2452 this->
fields[num_indrows].MakeCargoLabel(0,
false);
2459 if (!indsp->
enabled)
continue;
2462 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it);
2467 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, it);
2472 if (houses_supply) {
2473 this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES);
2476 if (houses_accept) {
2477 this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, NUM_INDUSTRYTYPES);
2497 if (!gui_scope)
return;
2515 int width = r.right - r.left + 1;
2519 _cur_dpi = &tmp_dpi;
2528 int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height;
2529 if (vpos + row_height >= 0) {
2530 int xpos = left_pos;
2539 while (col >= 0 && col <= last_column) {
2540 this->
fields[i].columns[col].Draw(xpos, vpos);
2541 xpos += (col & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width;
2546 if (vpos >= height)
break;
2566 if (pt.y < vpos)
return false;
2568 int row = (pt.y - vpos) / CargoesField::normal_height;
2569 if (row + 1 >= (
int)this->
fields.
Length())
return false;
2570 vpos = pt.y - vpos - row * CargoesField::normal_height;
2574 if (pt.x < xpos)
return false;
2576 for (column = 0; column <= 5; column++) {
2577 int width = (column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width;
2578 if (pt.x < xpos + width)
break;
2582 if (column > num_columns)
return false;
2589 fieldxy->x = num_columns - column;
2590 xy->x = ((column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width) - xpos;
2592 fieldxy->x = column;
2606 switch (fld->
type) {
2612 CargoesField *lft = (fieldxy.x > 0) ? this->
fields[fieldxy.y].columns + fieldxy.x - 1 : NULL;
2613 CargoesField *rgt = (fieldxy.x < 4) ? this->
fields[fieldxy.y].columns + fieldxy.x + 1 : NULL;
2648 if (lst->
Length() == 0) {
2662 if (!indsp->
enabled)
continue;
2665 if (lst->
Length() == 0) {
2678 if (index < 0)
return;
2700 switch (fld->
type) {
2702 CargoesField *lft = (fieldxy.x > 0) ? this->
fields[fieldxy.y].columns + fieldxy.x - 1 : NULL;
2703 CargoesField *rgt = (fieldxy.x < 4) ? this->
fields[fieldxy.y].columns + fieldxy.x + 1 : NULL;
2715 GuiShowTooltips(
this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, TCC_HOVER);
2725 params[0] = csp->
name;
2726 GuiShowTooltips(
this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, TCC_HOVER);
2753 if (
id >= NUM_INDUSTRYTYPES)
return;