43 #include "table/strings.h" 
   49 bool _ignore_restrictions;
 
   82     if (callback > 0x400) {
 
   84     } 
else if (indspec->
grf_prop.
grffile->grf_version >= 8 || 
GB(callback, 0, 8) != 0xFF) {
 
  102 template <
typename TC, 
typename TS>
 
  106   for (uint j = 0; j < 
lengthof(cargoes); j++) {
 
  110       suffixes[j][0] = 
'\0';
 
  120   static char industry_name[2][64];
 
  123   GetString(industry_name[0], indsp1->
name, 
lastof(industry_name[0]));
 
  126   GetString(industry_name[1], indsp2->
name, 
lastof(industry_name[1]));
 
  128   int r = 
strnatcmp(industry_name[0], industry_name[1]); 
 
  131   return (r != 0) ? r : (*a - *b);
 
  159   uint8 indtype = 
GB(p1, 0, 8);
 
  169 static const NWidgetPart _nested_build_industry_widgets[] = {
 
  178     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),
 
  185         SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP),
 
  193   WDP_AUTO, 
"build_industry", 170, 212,
 
  196   _nested_build_industry_widgets, 
lengthof(_nested_build_industry_widgets)
 
  222     if (_game_mode == GM_EDITOR) { 
 
  296         for (byte i = 0; i < this->
count; i++) {
 
  302         d.height = 5 * resize->height;
 
  311         for (byte i = 0; i < this->
count; i++) {
 
  316           char cargo_suffix[3][512];
 
  318           StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
 
  332           str = STR_INDUSTRY_VIEW_PRODUCES_CARGO;
 
  336           for (byte j = 0; j < 
lengthof(indsp->produced_cargo); j++) {
 
  337             if (indsp->produced_cargo[j] == 
CT_INVALID) 
continue;
 
  355         d.width += padding.width;
 
  356         d.height += padding.height;
 
  369         if (_game_mode == GM_EDITOR) {
 
  371           SetDParam(0, STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY);
 
  384         uint text_left, text_right, icon_left, icon_right;
 
  387           icon_left  = icon_right - 10;
 
  392           icon_right = icon_left  + 10;
 
  402             DrawString(text_left, text_right, y, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE);
 
  408           DrawString(text_left, text_right, y, indsp->
name, selected ? TC_WHITE : TC_ORANGE);
 
  422           DrawStringMultiLine(left, right, y,  bottom, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP);
 
  428         if (_game_mode != GM_EDITOR) {
 
  430           DrawString(left, right, y, STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST);
 
  435         char cargo_suffix[3][512];
 
  437         StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
 
  452         str = STR_INDUSTRY_VIEW_PRODUCES_CARGO;
 
  456         for (byte j = 0; j < 
lengthof(indsp->produced_cargo); j++) {
 
  457           if (indsp->produced_cargo[j] == 
CT_INVALID) 
continue;
 
  470             if (callback_res > 0x400) {
 
  474               if (str != STR_UNDEFINED) {
 
  492         if (y < this->
count) { 
 
  552     uint32 seed = InteractiveRandom();
 
  554     if (_game_mode == GM_EDITOR) {
 
  564       _ignore_restrictions = 
true;
 
  566       DoCommandP(tile, (InteractiveRandomRange(indsp->
num_table) << 8) | this->selected_type, seed,
 
  570       _ignore_restrictions = 
false;
 
  621     if (!gui_scope) 
return;
 
  630 void ShowBuildIndustryWindow()
 
  637 static void UpdateIndustryProduction(
Industry *i);
 
  639 static inline bool IsProductionAlterable(
const Industry *i)
 
  643       (is->production_rate[0] != 0 || is->production_rate[1] != 0 || is->
IsRawIndustry()) &&
 
  715     bool has_accept = 
false;
 
  716     char cargo_suffix[3][512];
 
  741       StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
 
  775       if (this->editable == 
EA_RATE) {
 
  798         if (callback_res > 0x400) {
 
  802           if (message != STR_NULL && message != STR_UNDEFINED) {
 
  843             if (pt.y >= this->production_offset_y) {
 
  858         NWidgetBase *nwi = this->GetWidget<NWidgetBase>(widget);
 
  887             default: NOT_REACHED();
 
  890           UpdateIndustryProduction(i);
 
  909             default: NOT_REACHED();
 
  955     uint value = atoi(str);
 
  967     UpdateIndustryProduction(i);
 
  978     if (!gui_scope) 
return;
 
  980     if (IsProductionAlterable(i)) {
 
  999 static void UpdateIndustryProduction(
Industry *i)
 
 1023       NWidget(
NWID_VIEWPORT, INVALID_COLOUR, 
WID_IV_VIEWPORT), 
SetMinimalSize(254, 86), 
SetFill(1, 0), 
SetPadding(1, 1, 1, 1), 
SetResize(1, 1),
 
 1037   WDP_AUTO, 
"view_industry", 260, 120,
 
 1040   _nested_industry_view_widgets, 
lengthof(_nested_industry_view_widgets)
 
 1043 void ShowIndustryViewWindow(
int industry)
 
 1083   static const Industry *last_industry;
 
 1086   static const StringID sorter_names[];
 
 1089   GUIIndustryList industries;
 
 1096       this->industries.
Clear();
 
 1099       FOR_ALL_INDUSTRIES(i) {
 
 1100         *this->industries.
Append() = i;
 
 1108     if (!this->industries.
Sort()) 
return;
 
 1109     IndustryDirectoryWindow::last_industry = NULL; 
 
 1140     if (p1 > p2) 
Swap(p1, p2); 
 
 1142     return (p1 << 8) + p2;
 
 1148     static char buf_cache[96];
 
 1149     static char buf[96];
 
 1152     GetString(buf, STR_INDUSTRY_NAME, 
lastof(buf));
 
 1154     if (*b != last_industry) {
 
 1157       GetString(buf_cache, STR_INDUSTRY_NAME, 
lastof(buf_cache));
 
 1170     int r = it_a - it_b;
 
 1177     uint prod_a = 0, prod_b = 0;
 
 1178     for (uint i = 0; i < 
lengthof((*a)->produced_cargo); i++) {
 
 1179       if ((*a)->produced_cargo[i] != 
CT_INVALID) prod_a += (*a)->last_month_production[i];
 
 1180       if ((*b)->produced_cargo[i] != 
CT_INVALID) prod_b += (*b)->last_month_production[i];
 
 1182     int r = prod_a - prod_b;
 
 1226       case 1:  
return STR_INDUSTRY_DIRECTORY_ITEM_NOPROD;
 
 1227       case 5:  
return STR_INDUSTRY_DIRECTORY_ITEM;
 
 1228       default: 
return STR_INDUSTRY_DIRECTORY_ITEM_TWO;
 
 1238     this->industries.
SetListing(this->last_sorting);
 
 1239     this->industries.
SetSortFuncs(IndustryDirectoryWindow::sorter_funcs);
 
 1248     this->last_sorting = this->industries.
GetListing();
 
 1266         if (this->industries.
Length() == 0) {
 
 1270         for (uint i = this->vscroll->
GetPosition(); i < this->industries.
Length(); i++) {
 
 1287         d.height += padding.height;
 
 1288         *size = 
maxdim(*size, d);
 
 1294         for (uint i = 0; IndustryDirectoryWindow::sorter_names[i] != 
INVALID_STRING_ID; i++) {
 
 1297         d.width += padding.width;
 
 1298         d.height += padding.height;
 
 1299         *size = 
maxdim(*size, d);
 
 1305         for (uint i = 0; i < this->industries.
Length(); i++) {
 
 1308         resize->height = d.height;
 
 1312         *size = 
maxdim(*size, d);
 
 1333         if (p < this->industries.
Length()) {
 
 1347     if (this->industries.
SortType() != index) {
 
 1386 Listing IndustryDirectoryWindow::last_sorting = {
false, 0};
 
 1387 const Industry *IndustryDirectoryWindow::last_industry = NULL;
 
 1391   &IndustryNameSorter,
 
 1392   &IndustryTypeSorter,
 
 1393   &IndustryProductionSorter,
 
 1394   &IndustryTransportedCargoSorter
 
 1398 const StringID IndustryDirectoryWindow::sorter_names[] = {
 
 1401   STR_SORT_BY_PRODUCTION,
 
 1402   STR_SORT_BY_TRANSPORTED,
 
 1409   WDP_AUTO, 
"list_industries", 428, 190,
 
 1412   _nested_industry_directory_widgets, 
lengthof(_nested_industry_directory_widgets)
 
 1415 void ShowIndustryDirectory()
 
 1434           SetDataTip(STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP, STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP),
 
 1437             SetDataTip(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY, STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP),
 
 1439             SetDataTip(STR_INDUSTRY_CARGOES_SELECT_CARGO, STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP),
 
 1451   WDP_AUTO, 
"industry_cargoes", 300, 210,
 
 1454   _nested_industry_cargoes_widgets, 
lengthof(_nested_industry_cargoes_widgets)
 
 1524     this->u.industry.ind_type = 
ind_type;
 
 1542     for (
int i = 0; i < this->u.cargo.num_cargoes; i++) {
 
 1543       if (cargo == this->u.cargo.vertical_cargoes[i]) {
 
 1548     if (column < 0) 
return -1;
 
 1551       assert(this->u.cargo.supp_cargoes[column] == 
INVALID_CARGO);
 
 1552       this->u.cargo.supp_cargoes[column]  = column;
 
 1554       assert(this->u.cargo.cust_cargoes[column] == 
INVALID_CARGO);
 
 1555       this->u.cargo.cust_cargoes[column] = column;
 
 1569       if (this->u.cargo.supp_cargoes[i] != 
INVALID_CARGO) 
return true;
 
 1570       if (this->u.cargo.cust_cargoes[i] != 
INVALID_CARGO) 
return true;
 
 1589     for (i = 0; i < MAX_CARGOES && i < length; i++) {
 
 1591         this->u.cargo.vertical_cargoes[num] = cargoes[i];
 
 1595     this->u.cargo.num_cargoes = (count < 0) ? num : count;
 
 1597     this->u.cargo.top_end = 
top_end;
 
 1613     for (i = 0; i < MAX_CARGOES && i < length; i++) this->u.cargo_label.cargoes[i] = cargoes[i];
 
 1615     this->u.cargo_label.left_align = left_align;
 
 1625     this->u.header = textid;
 
 1637     switch (this->u.cargo.num_cargoes) {
 
 1642       default: NOT_REACHED();
 
 1651   void Draw(
int xpos, 
int ypos)
 const 
 1653     switch (this->
type) {
 
 1677           int blob_left, blob_right;
 
 1692         const CargoID *other_right, *other_left;
 
 1694           other_right = this->u.industry.other_accepted;
 
 1695           other_left  = this->u.industry.other_produced;
 
 1697           other_right = this->u.industry.other_produced;
 
 1698           other_left  = this->u.industry.other_accepted;
 
 1723         int colpos = cargo_base;
 
 1724         for (
int i = 0; i < this->u.cargo.num_cargoes; i++) {
 
 1736         const CargoID *hor_left, *hor_right;
 
 1738           hor_left  = this->u.cargo.cust_cargoes;
 
 1739           hor_right = this->u.cargo.supp_cargoes;
 
 1741           hor_left  = this->u.cargo.supp_cargoes;
 
 1742           hor_right = this->u.cargo.cust_cargoes;
 
 1747             int col = hor_left[i];
 
 1750             for (; col > 0; col--) {
 
 1758             int col = hor_right[i];
 
 1761             for (; col < this->u.cargo.num_cargoes - 1; col++) {
 
 1804     for (col = 0; col < this->u.cargo.num_cargoes; col++) {
 
 1805       if (pt.x < cpos) 
break;
 
 1822       if (this->u.cargo.supp_cargoes[row] != 
INVALID_CARGO) 
return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]];
 
 1829     if (col == this->u.cargo.num_cargoes) {
 
 1830       if (this->u.cargo.cust_cargoes[row] != 
INVALID_CARGO) 
return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]];
 
 1831       if (right != NULL) {
 
 1842       return (this->u.cargo.supp_cargoes[row] != 
INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] : 
INVALID_CARGO;
 
 1845       return (this->u.cargo.cust_cargoes[row] != 
INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] : 
INVALID_CARGO;
 
 1866     return this->u.cargo_label.cargoes[row];
 
 1928       int other_count = 0;
 
 1931       for (uint i = 0; i < 
lengthof(indsp->produced_cargo); i++) {
 
 1932         int col = cargo_fld->
ConnectCargo(indsp->produced_cargo[i], 
true);
 
 1933         if (col < 0) others[other_count++] = indsp->produced_cargo[i];
 
 1937       for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) {
 
 1942       for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
 
 1944         if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->
ConnectCargo(cid, 
true);
 
 1963     for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
 
 1964       int col = cargo_fld->
ConnectCargo(cargo_fld->u.
cargo.vertical_cargoes[i], !accepting);
 
 1965       if (col >= 0) cargoes[col] = cargo_fld->u.
cargo.vertical_cargoes[i];
 
 1985       int other_count = 0;
 
 1990         if (col < 0) others[other_count++] = indsp->
accepts_cargo[i];
 
 1994       for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) {
 
 1999       for (uint i = 0; i < cargo_fld->u.
cargo.num_cargoes; i++) {
 
 2072     CargoesField::small_height = d.height;
 
 2079       if (!indsp->
enabled) 
continue;
 
 2082     d.width = 
max(d.width, this->ind_textsize.width);
 
 2091       if (!csp->
IsValid()) 
continue;
 
 2099     uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + MAX_CARGOES * 
FONT_HEIGHT_NORMAL + (MAX_CARGOES - 1) *  CargoesField::VERT_CARGO_SPACE;
 
 2102     CargoesField::industry_width = d.width;
 
 2103     CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE;
 
 2114         size->width = 
max(size->width, this->ind_textsize.width + padding.width);
 
 2118         size->width = 
max(size->width, this->cargo_textsize.width + padding.width);
 
 2148     while (length1 > 0) {
 
 2150         for (uint i = 0; i < length2; i++) 
if (*cargoes1 == cargoes2[i]) 
return true;
 
 2166     for (uint i = 0; i < length; i++) {
 
 2168       if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) 
return true;
 
 2183       case LT_TEMPERATE: climate_mask = 
HZ_TEMP; 
break;
 
 2186       case LT_TOYLAND:   climate_mask = 
HZ_TOYLND; 
break;
 
 2187       default: NOT_REACHED();
 
 2189     for (uint i = 0; i < length; i++) {
 
 2215       if (!indsp->
enabled) 
continue;
 
 2233       if (!indsp->
enabled) 
continue;
 
 2248     while (top < bottom && !this->
fields[top].columns[column].HasConnection()) {
 
 2252     this->
fields[
top].columns[column].u.cargo.top_end = 
true;
 
 2254     while (bottom > top && !this->
fields[bottom].columns[column].HasConnection()) {
 
 2258     this->
fields[bottom].columns[column].u.cargo.bottom_end = 
true;
 
 2270     this->
fields[row].columns[col].MakeIndustry(it);
 
 2272       this->
fields[row].ConnectIndustryProduced(col);
 
 2274       this->
fields[row].ConnectIndustryAccepted(col);
 
 2296     this->GetWidget<NWidgetCore>(
WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION;
 
 2315     int num_indrows = 
max(3, 
max(num_supp, num_cust)); 
 
 2316     for (
int i = 0; i < num_indrows; i++) {
 
 2325     int central_row = 1 + num_indrows / 2;
 
 2326     this->
fields[central_row].columns[2].MakeIndustry(it);
 
 2327     this->
fields[central_row].ConnectIndustryProduced(2);
 
 2328     this->
fields[central_row].ConnectIndustryAccepted(2);
 
 2331     this->
fields[central_row - 1].MakeCargoLabel(2, 
true);
 
 2332     this->
fields[central_row + 1].MakeCargoLabel(2, 
false);
 
 2339       if (!indsp->
enabled) 
continue;
 
 2342         this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it);
 
 2347         this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, it);
 
 2352     if (houses_supply) {
 
 2353       this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES);
 
 2356     if (houses_accept) {
 
 2357       this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, NUM_INDUSTRYTYPES);
 
 2375     this->GetWidget<NWidgetCore>(
WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_CARGO_CAPTION;
 
 2391     int num_indrows = 
max(num_supp, num_cust);
 
 2392     for (
int i = 0; i < num_indrows; i++) {
 
 2401     this->
fields[num_indrows].MakeCargoLabel(0, 
false); 
 
 2408       if (!indsp->
enabled) 
continue;
 
 2411         this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it);
 
 2416         this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, it);
 
 2421     if (houses_supply) {
 
 2422       this->
PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES);
 
 2425     if (houses_accept) {
 
 2426       this->
PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, NUM_INDUSTRYTYPES);
 
 2446     if (!gui_scope) 
return;
 
 2464     int width = r.right - r.left + 1;
 
 2468     _cur_dpi = &tmp_dpi;
 
 2477       int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height;
 
 2478       if (vpos + row_height >= 0) {
 
 2479         int xpos = left_pos;
 
 2488         while (col >= 0 && col <= last_column) {
 
 2489           this->
fields[i].columns[col].Draw(xpos, vpos);
 
 2490           xpos += (col & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width;
 
 2495       if (vpos >= height) 
break;
 
 2515     if (pt.y < vpos) 
return false;
 
 2517     int row = (pt.y - vpos) / CargoesField::normal_height; 
 
 2518     if (row + 1 >= (
int)this->
fields.
Length()) 
return false;
 
 2519     vpos = pt.y - vpos - row * CargoesField::normal_height; 
 
 2523     if (pt.x < xpos) 
return false;
 
 2525     for (column = 0; column <= 5; column++) {
 
 2526       int width = (column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width;
 
 2527       if (pt.x < xpos + width) 
break;
 
 2531     if (column > num_columns) 
return false;
 
 2538       fieldxy->x = num_columns - column;
 
 2539       xy->x = ((column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width) - xpos;
 
 2541       fieldxy->x = column;
 
 2555         switch (fld->
type) {
 
 2561             CargoesField *lft = (fieldxy.x > 0) ? this->
fields[fieldxy.y].columns + fieldxy.x - 1 : NULL;
 
 2562             CargoesField *rgt = (fieldxy.x < 4) ? this->
fields[fieldxy.y].columns + fieldxy.x + 1 : NULL;
 
 2597         if (lst->
Length() == 0) {
 
 2611           if (!indsp->
enabled) 
continue;
 
 2614         if (lst->
Length() == 0) {
 
 2627     if (index < 0) 
return;
 
 2649     switch (fld->
type) {
 
 2651         CargoesField *lft = (fieldxy.x > 0) ? this->
fields[fieldxy.y].columns + fieldxy.x - 1 : NULL;
 
 2652         CargoesField *rgt = (fieldxy.x < 4) ? this->
fields[fieldxy.y].columns + fieldxy.x + 1 : NULL;
 
 2664           GuiShowTooltips(
this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, TCC_HOVER);
 
 2674       params[0] = csp->
name;
 
 2675       GuiShowTooltips(
this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, TCC_HOVER);
 
 2702     if (
id >= NUM_INDUSTRYTYPES) 
return;