|
@@ -149,48 +149,48 @@ enum CargoSuffixInOut {
|
|
|
* @param indspec the industry spec
|
|
|
* @param cargoes array with cargotypes. for CT_INVALID no suffix will be determined
|
|
|
* @param suffixes is filled with the suffixes
|
|
|
*/
|
|
|
template <typename TC, typename TS>
|
|
|
static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes)
|
|
|
{
|
|
|
static_assert(lengthof(cargoes) <= lengthof(suffixes));
|
|
|
|
|
|
if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) {
|
|
|
/* Reworked behaviour with new many-in-many-out scheme */
|
|
|
for (uint j = 0; j < lengthof(suffixes); j++) {
|
|
|
if (cargoes[j] != CT_INVALID) {
|
|
|
if (IsValidCargoID(cargoes[j])) {
|
|
|
byte local_id = indspec->grf_prop.grffile->cargo_map[cargoes[j]]; // should we check the value for valid?
|
|
|
uint cargotype = local_id << 16 | use_input;
|
|
|
GetCargoSuffix(cargotype, cst, ind, ind_type, indspec, suffixes[j]);
|
|
|
} else {
|
|
|
suffixes[j].text[0] = '\0';
|
|
|
suffixes[j].display = CSD_CARGO;
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
/* Compatible behaviour with old 3-in-2-out scheme */
|
|
|
for (uint j = 0; j < lengthof(suffixes); j++) {
|
|
|
suffixes[j].text[0] = '\0';
|
|
|
suffixes[j].display = CSD_CARGO;
|
|
|
}
|
|
|
switch (use_input) {
|
|
|
case CARGOSUFFIX_OUT:
|
|
|
if (cargoes[0] != CT_INVALID) GetCargoSuffix(3, cst, ind, ind_type, indspec, suffixes[0]);
|
|
|
if (cargoes[1] != CT_INVALID) GetCargoSuffix(4, cst, ind, ind_type, indspec, suffixes[1]);
|
|
|
if (IsValidCargoID(cargoes[0])) GetCargoSuffix(3, cst, ind, ind_type, indspec, suffixes[0]);
|
|
|
if (IsValidCargoID(cargoes[1])) GetCargoSuffix(4, cst, ind, ind_type, indspec, suffixes[1]);
|
|
|
break;
|
|
|
case CARGOSUFFIX_IN:
|
|
|
if (cargoes[0] != CT_INVALID) GetCargoSuffix(0, cst, ind, ind_type, indspec, suffixes[0]);
|
|
|
if (cargoes[1] != CT_INVALID) GetCargoSuffix(1, cst, ind, ind_type, indspec, suffixes[1]);
|
|
|
if (cargoes[2] != CT_INVALID) GetCargoSuffix(2, cst, ind, ind_type, indspec, suffixes[2]);
|
|
|
if (IsValidCargoID(cargoes[0])) GetCargoSuffix(0, cst, ind, ind_type, indspec, suffixes[0]);
|
|
|
if (IsValidCargoID(cargoes[1])) GetCargoSuffix(1, cst, ind, ind_type, indspec, suffixes[1]);
|
|
|
if (IsValidCargoID(cargoes[2])) GetCargoSuffix(2, cst, ind, ind_type, indspec, suffixes[2]);
|
|
|
break;
|
|
|
default:
|
|
|
NOT_REACHED();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
std::array<IndustryType, NUM_INDUSTRYTYPES> _sorted_industry_types; ///< Industry types sorted by name.
|
|
|
|
|
|
/** Sort industry types by their name. */
|
|
|
static bool IndustryTypeNameSorter(const IndustryType &a, const IndustryType &b)
|
|
|
{
|
|
@@ -337,25 +337,25 @@ class BuildIndustryWindow : public Windo
|
|
|
* @param cargo_suffix Array of suffixes to attach to each cargo
|
|
|
* @param cargolistlen Length of arrays
|
|
|
* @param prefixstr String to use for the first item
|
|
|
* @return A formatted raw string
|
|
|
*/
|
|
|
std::string MakeCargoListString(const CargoID *cargolist, const CargoSuffix *cargo_suffix, int cargolistlen, StringID prefixstr) const
|
|
|
{
|
|
|
std::string cargostring;
|
|
|
int numcargo = 0;
|
|
|
int firstcargo = -1;
|
|
|
|
|
|
for (int j = 0; j < cargolistlen; j++) {
|
|
|
if (cargolist[j] == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(cargolist[j])) continue;
|
|
|
numcargo++;
|
|
|
if (firstcargo < 0) {
|
|
|
firstcargo = j;
|
|
|
continue;
|
|
|
}
|
|
|
SetDParam(0, CargoSpec::Get(cargolist[j])->name);
|
|
|
SetDParamStr(1, cargo_suffix[j].text);
|
|
|
cargostring += GetString(STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION);
|
|
|
}
|
|
|
|
|
|
if (numcargo > 0) {
|
|
|
SetDParam(0, CargoSpec::Get(cargolist[firstcargo])->name);
|
|
@@ -836,25 +836,25 @@ public:
|
|
|
bool has_accept = false;
|
|
|
|
|
|
if (i->prod_level == PRODLEVEL_CLOSURE) {
|
|
|
DrawString(ir, STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE);
|
|
|
ir.top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide;
|
|
|
}
|
|
|
|
|
|
CargoSuffix cargo_suffix[lengthof(i->accepts_cargo)];
|
|
|
GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix);
|
|
|
bool stockpiling = HasBit(ind->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_mask, CBM_IND_PRODUCTION_256_TICKS);
|
|
|
|
|
|
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
|
|
|
if (i->accepts_cargo[j] == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(i->accepts_cargo[j])) continue;
|
|
|
has_accept = true;
|
|
|
if (first) {
|
|
|
DrawString(ir, STR_INDUSTRY_VIEW_REQUIRES);
|
|
|
ir.top += FONT_HEIGHT_NORMAL;
|
|
|
first = false;
|
|
|
}
|
|
|
SetDParam(0, CargoSpec::Get(i->accepts_cargo[j])->name);
|
|
|
SetDParam(1, i->accepts_cargo[j]);
|
|
|
SetDParam(2, i->incoming_cargo_waiting[j]);
|
|
|
SetDParamStr(3, "");
|
|
|
StringID str = STR_NULL;
|
|
|
switch (cargo_suffix[j].display) {
|
|
@@ -876,25 +876,25 @@ public:
|
|
|
NOT_REACHED();
|
|
|
}
|
|
|
DrawString(ir.Indent(WidgetDimensions::scaled.hsep_indent, rtl), str);
|
|
|
ir.top += FONT_HEIGHT_NORMAL;
|
|
|
}
|
|
|
|
|
|
GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix);
|
|
|
int line_height = this->editable == EA_RATE ? this->cheat_line_height : FONT_HEIGHT_NORMAL;
|
|
|
int text_y_offset = (line_height - FONT_HEIGHT_NORMAL) / 2;
|
|
|
int button_y_offset = (line_height - SETTING_BUTTON_HEIGHT) / 2;
|
|
|
first = true;
|
|
|
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
|
|
|
if (i->produced_cargo[j] == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(i->produced_cargo[j])) continue;
|
|
|
if (first) {
|
|
|
if (has_accept) ir.top += WidgetDimensions::scaled.vsep_wide;
|
|
|
DrawString(ir, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE);
|
|
|
ir.top += FONT_HEIGHT_NORMAL;
|
|
|
if (this->editable == EA_RATE) this->production_offset_y = ir.top;
|
|
|
first = false;
|
|
|
}
|
|
|
|
|
|
SetDParam(0, i->produced_cargo[j]);
|
|
|
SetDParam(1, i->last_month_production[j]);
|
|
|
SetDParamStr(2, cargo_suffix[j].text);
|
|
|
SetDParam(3, ToPercent8(i->last_month_pct_transported[j]));
|
|
@@ -972,25 +972,25 @@ public:
|
|
|
|
|
|
switch (this->editable) {
|
|
|
case EA_NONE: break;
|
|
|
|
|
|
case EA_MULTIPLIER:
|
|
|
if (IsInsideBS(pt.y, this->production_offset_y, this->cheat_line_height)) line = IL_MULTIPLIER;
|
|
|
break;
|
|
|
|
|
|
case EA_RATE:
|
|
|
if (pt.y >= this->production_offset_y) {
|
|
|
int row = (pt.y - this->production_offset_y) / this->cheat_line_height;
|
|
|
for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
|
|
|
if (i->produced_cargo[j] == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(i->produced_cargo[j])) continue;
|
|
|
row--;
|
|
|
if (row < 0) {
|
|
|
line = (InfoLine)(IL_RATE1 + j);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
if (line == IL_NONE) return;
|
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
@@ -1131,25 +1131,25 @@ public:
|
|
|
void ShowNewGRFInspectWindow() const override
|
|
|
{
|
|
|
::ShowNewGRFInspectWindow(GSF_INDUSTRIES, this->window_number);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
static void UpdateIndustryProduction(Industry *i)
|
|
|
{
|
|
|
const IndustrySpec *indspec = GetIndustrySpec(i->type);
|
|
|
if (indspec->UsesOriginalEconomy()) i->RecomputeProductionMultipliers();
|
|
|
|
|
|
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
|
|
|
if (i->produced_cargo[j] != CT_INVALID) {
|
|
|
if (IsValidCargoID(i->produced_cargo[j])) {
|
|
|
i->last_month_production[j] = 8 * i->production_rate[j];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** Widget definition of the view industry gui */
|
|
|
static const NWidgetPart _nested_industry_view_widgets[] = {
|
|
|
NWidget(NWID_HORIZONTAL),
|
|
|
NWidget(WWT_CLOSEBOX, COLOUR_CREAM),
|
|
|
NWidget(WWT_CAPTION, COLOUR_CREAM, WID_IV_CAPTION), SetDataTip(STR_INDUSTRY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
|
|
NWidget(WWT_PUSHIMGBTN, COLOUR_CREAM, WID_IV_GOTO), SetMinimalSize(12, 14), SetDataTip(SPR_GOTO_LOCATION, STR_INDUSTRY_VIEW_LOCATION_TOOLTIP),
|
|
|
NWidget(WWT_DEBUGBOX, COLOUR_CREAM),
|
|
@@ -1235,44 +1235,44 @@ static bool CDECL CargoFilter(const Indu
|
|
|
auto accepted_cargo = cargoes.first;
|
|
|
auto produced_cargo = cargoes.second;
|
|
|
|
|
|
bool accepted_cargo_matches;
|
|
|
|
|
|
switch (accepted_cargo) {
|
|
|
case CF_ANY:
|
|
|
accepted_cargo_matches = true;
|
|
|
break;
|
|
|
|
|
|
case CF_NONE:
|
|
|
accepted_cargo_matches = std::all_of(std::begin((*industry)->accepts_cargo), std::end((*industry)->accepts_cargo), [](CargoID cargo) {
|
|
|
return cargo == CT_INVALID;
|
|
|
return !IsValidCargoID(cargo);
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
const auto &ac = (*industry)->accepts_cargo;
|
|
|
accepted_cargo_matches = std::find(std::begin(ac), std::end(ac), accepted_cargo) != std::end(ac);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
bool produced_cargo_matches;
|
|
|
|
|
|
switch (produced_cargo) {
|
|
|
case CF_ANY:
|
|
|
produced_cargo_matches = true;
|
|
|
break;
|
|
|
|
|
|
case CF_NONE:
|
|
|
produced_cargo_matches = std::all_of(std::begin((*industry)->produced_cargo), std::end((*industry)->produced_cargo), [](CargoID cargo) {
|
|
|
return cargo == CT_INVALID;
|
|
|
return !IsValidCargoID(cargo);
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
const auto &pc = (*industry)->produced_cargo;
|
|
|
produced_cargo_matches = std::find(std::begin(pc), std::end(pc), produced_cargo) != std::end(pc);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
return accepted_cargo_matches && produced_cargo_matches;
|
|
|
}
|
|
|
|
|
@@ -1416,25 +1416,25 @@ protected:
|
|
|
|
|
|
/**
|
|
|
* Returns percents of cargo transported if industry produces this cargo, else -1
|
|
|
*
|
|
|
* @param i industry to check
|
|
|
* @param id cargo slot
|
|
|
* @return percents of cargo transported, or -1 if industry doesn't use this cargo slot
|
|
|
*/
|
|
|
static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id)
|
|
|
{
|
|
|
assert(id < lengthof(i->produced_cargo));
|
|
|
|
|
|
if (i->produced_cargo[id] == CT_INVALID) return -1;
|
|
|
if (!IsValidCargoID(i->produced_cargo[id])) return -1;
|
|
|
return ToPercent8(i->last_month_pct_transported[id]);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns value representing industry's transported cargo
|
|
|
* percentage for industry sorting
|
|
|
*
|
|
|
* @param i industry to check
|
|
|
* @return value used for sorting
|
|
|
*/
|
|
|
static int GetCargoTransportedSortValue(const Industry *i)
|
|
|
{
|
|
@@ -1480,26 +1480,26 @@ protected:
|
|
|
return (r == 0) ? IndustryNameSorter(a, b) : r < 0;
|
|
|
}
|
|
|
|
|
|
/** Sort industries by production and name */
|
|
|
static bool IndustryProductionSorter(const Industry * const &a, const Industry * const &b)
|
|
|
{
|
|
|
CargoID filter = IndustryDirectoryWindow::produced_cargo_filter;
|
|
|
if (filter == CF_NONE) return IndustryTypeSorter(a, b);
|
|
|
|
|
|
uint prod_a = 0, prod_b = 0;
|
|
|
for (uint i = 0; i < lengthof(a->produced_cargo); i++) {
|
|
|
if (filter == CF_ANY) {
|
|
|
if (a->produced_cargo[i] != CT_INVALID) prod_a += a->last_month_production[i];
|
|
|
if (b->produced_cargo[i] != CT_INVALID) prod_b += b->last_month_production[i];
|
|
|
if (IsValidCargoID(a->produced_cargo[i])) prod_a += a->last_month_production[i];
|
|
|
if (IsValidCargoID(b->produced_cargo[i])) prod_b += b->last_month_production[i];
|
|
|
} else {
|
|
|
if (a->produced_cargo[i] == filter) prod_a += a->last_month_production[i];
|
|
|
if (b->produced_cargo[i] == filter) prod_b += b->last_month_production[i];
|
|
|
}
|
|
|
}
|
|
|
int r = prod_a - prod_b;
|
|
|
|
|
|
return (r == 0) ? IndustryTypeSorter(a, b) : r < 0;
|
|
|
}
|
|
|
|
|
|
/** Sort industries by transported cargo and name */
|
|
|
static bool IndustryTransportedCargoSorter(const Industry * const &a, const Industry * const &b)
|
|
@@ -1525,25 +1525,25 @@ protected:
|
|
|
GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix);
|
|
|
|
|
|
/* Get industry productions (CargoID, production, suffix, transported) */
|
|
|
struct CargoInfo {
|
|
|
CargoID cargo_id;
|
|
|
uint16 production;
|
|
|
const char *suffix;
|
|
|
uint transported;
|
|
|
};
|
|
|
std::vector<CargoInfo> cargos;
|
|
|
|
|
|
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
|
|
|
if (i->produced_cargo[j] == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(i->produced_cargo[j])) continue;
|
|
|
cargos.push_back({ i->produced_cargo[j], i->last_month_production[j], cargo_suffix[j].text.c_str(), ToPercent8(i->last_month_pct_transported[j]) });
|
|
|
}
|
|
|
|
|
|
switch (static_cast<IndustryDirectoryWindow::SorterType>(this->industries.SortType())) {
|
|
|
case IndustryDirectoryWindow::SorterType::ByName:
|
|
|
case IndustryDirectoryWindow::SorterType::ByType:
|
|
|
case IndustryDirectoryWindow::SorterType::ByProduction:
|
|
|
/* Sort by descending production, then descending transported */
|
|
|
std::sort(cargos.begin(), cargos.end(), [](const CargoInfo &a, const CargoInfo &b) {
|
|
|
if (a.production != b.production) return a.production > b.production;
|
|
|
return a.transported > b.transported;
|
|
|
});
|
|
@@ -1960,77 +1960,77 @@ struct CargoesField {
|
|
|
MemSetT(this->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Connect a cargo from an industry to the #CFT_CARGO column.
|
|
|
* @param cargo Cargo to connect.
|
|
|
* @param producer Cargo is produced (if \c false, cargo is assumed to be accepted).
|
|
|
* @return Horizontal connection index, or \c -1 if not accepted at all.
|
|
|
*/
|
|
|
int ConnectCargo(CargoID cargo, bool producer)
|
|
|
{
|
|
|
assert(this->type == CFT_CARGO);
|
|
|
if (cargo == INVALID_CARGO) return -1;
|
|
|
if (!IsValidCargoID(cargo)) return -1;
|
|
|
|
|
|
/* Find the vertical cargo column carrying the cargo. */
|
|
|
int column = -1;
|
|
|
for (int i = 0; i < this->u.cargo.num_cargoes; i++) {
|
|
|
if (cargo == this->u.cargo.vertical_cargoes[i]) {
|
|
|
column = i;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (column < 0) return -1;
|
|
|
|
|
|
if (producer) {
|
|
|
assert(this->u.cargo.supp_cargoes[column] == INVALID_CARGO);
|
|
|
assert(!IsValidCargoID(this->u.cargo.supp_cargoes[column]));
|
|
|
this->u.cargo.supp_cargoes[column] = column;
|
|
|
} else {
|
|
|
assert(this->u.cargo.cust_cargoes[column] == INVALID_CARGO);
|
|
|
assert(!IsValidCargoID(this->u.cargo.cust_cargoes[column]));
|
|
|
this->u.cargo.cust_cargoes[column] = column;
|
|
|
}
|
|
|
return column;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Does this #CFT_CARGO field have a horizontal connection?
|
|
|
* @return \c true if a horizontal connection exists, \c false otherwise.
|
|
|
*/
|
|
|
bool HasConnection()
|
|
|
{
|
|
|
assert(this->type == CFT_CARGO);
|
|
|
|
|
|
for (uint i = 0; i < MAX_CARGOES; i++) {
|
|
|
if (this->u.cargo.supp_cargoes[i] != INVALID_CARGO) return true;
|
|
|
if (this->u.cargo.cust_cargoes[i] != INVALID_CARGO) return true;
|
|
|
if (IsValidCargoID(this->u.cargo.supp_cargoes[i])) return true;
|
|
|
if (IsValidCargoID(this->u.cargo.cust_cargoes[i])) return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Make a piece of cargo column.
|
|
|
* @param cargoes Array of #CargoID (may contain #INVALID_CARGO).
|
|
|
* @param length Number of cargoes in \a cargoes.
|
|
|
* @param count Number of cargoes to display (should be at least the number of valid cargoes, or \c -1 to let the method compute it).
|
|
|
* @param top_end This is the first cargo field of this column.
|
|
|
* @param bottom_end This is the last cargo field of this column.
|
|
|
* @note #supp_cargoes and #cust_cargoes should be filled in later.
|
|
|
*/
|
|
|
void MakeCargo(const CargoID *cargoes, uint length, int count = -1, bool top_end = false, bool bottom_end = false)
|
|
|
{
|
|
|
this->type = CFT_CARGO;
|
|
|
uint i;
|
|
|
uint num = 0;
|
|
|
for (i = 0; i < MAX_CARGOES && i < length; i++) {
|
|
|
if (cargoes[i] != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(cargoes[i])) {
|
|
|
this->u.cargo.vertical_cargoes[num] = cargoes[i];
|
|
|
num++;
|
|
|
}
|
|
|
}
|
|
|
this->u.cargo.num_cargoes = (count < 0) ? num : count;
|
|
|
for (; num < MAX_CARGOES; num++) this->u.cargo.vertical_cargoes[num] = INVALID_CARGO;
|
|
|
this->u.cargo.top_end = top_end;
|
|
|
this->u.cargo.bottom_end = bottom_end;
|
|
|
MemSetT(this->u.cargo.supp_cargoes, INVALID_CARGO, MAX_CARGOES);
|
|
|
MemSetT(this->u.cargo.cust_cargoes, INVALID_CARGO, MAX_CARGOES);
|
|
|
}
|
|
|
|
|
@@ -2119,31 +2119,31 @@ struct CargoesField {
|
|
|
|
|
|
/* Draw the other_produced/other_accepted cargoes. */
|
|
|
const CargoID *other_right, *other_left;
|
|
|
if (_current_text_dir == TD_RTL) {
|
|
|
other_right = this->u.industry.other_accepted;
|
|
|
other_left = this->u.industry.other_produced;
|
|
|
} else {
|
|
|
other_right = this->u.industry.other_produced;
|
|
|
other_left = this->u.industry.other_accepted;
|
|
|
}
|
|
|
ypos1 += CargoesField::cargo_border.height + (FONT_HEIGHT_NORMAL - CargoesField::cargo_line.height) / 2;
|
|
|
for (uint i = 0; i < CargoesField::max_cargoes; i++) {
|
|
|
if (other_right[i] != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(other_right[i])) {
|
|
|
const CargoSpec *csp = CargoSpec::Get(other_right[i]);
|
|
|
int xp = xpos + industry_width + CargoesField::cargo_stub.width;
|
|
|
DrawHorConnection(xpos + industry_width, xp - 1, ypos1, csp);
|
|
|
GfxDrawLine(xp, ypos1, xp, ypos1 + CargoesField::cargo_line.height - 1, CARGO_LINE_COLOUR);
|
|
|
}
|
|
|
if (other_left[i] != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(other_left[i])) {
|
|
|
const CargoSpec *csp = CargoSpec::Get(other_left[i]);
|
|
|
int xp = xpos - CargoesField::cargo_stub.width;
|
|
|
DrawHorConnection(xp + 1, xpos - 1, ypos1, csp);
|
|
|
GfxDrawLine(xp, ypos1, xp, ypos1 + CargoesField::cargo_line.height - 1, CARGO_LINE_COLOUR);
|
|
|
}
|
|
|
ypos1 += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case CFT_CARGO: {
|
|
|
int cargo_base = this->GetCargoBase(xpos);
|
|
@@ -2163,55 +2163,55 @@ struct CargoesField {
|
|
|
}
|
|
|
|
|
|
const CargoID *hor_left, *hor_right;
|
|
|
if (_current_text_dir == TD_RTL) {
|
|
|
hor_left = this->u.cargo.cust_cargoes;
|
|
|
hor_right = this->u.cargo.supp_cargoes;
|
|
|
} else {
|
|
|
hor_left = this->u.cargo.supp_cargoes;
|
|
|
hor_right = this->u.cargo.cust_cargoes;
|
|
|
}
|
|
|
ypos += CargoesField::cargo_border.height + vert_inter_industry_space / 2 + (FONT_HEIGHT_NORMAL - CargoesField::cargo_line.height) / 2;
|
|
|
for (uint i = 0; i < MAX_CARGOES; i++) {
|
|
|
if (hor_left[i] != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(hor_left[i])) {
|
|
|
int col = hor_left[i];
|
|
|
int dx = 0;
|
|
|
const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]);
|
|
|
for (; col > 0; col--) {
|
|
|
int lf = cargo_base + col * CargoesField::cargo_line.width + (col - 1) * CargoesField::cargo_space.width;
|
|
|
DrawHorConnection(lf, lf + CargoesField::cargo_space.width - dx, ypos, csp);
|
|
|
dx = 1;
|
|
|
}
|
|
|
DrawHorConnection(xpos, cargo_base - dx, ypos, csp);
|
|
|
}
|
|
|
if (hor_right[i] != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(hor_right[i])) {
|
|
|
int col = hor_right[i];
|
|
|
int dx = 0;
|
|
|
const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]);
|
|
|
for (; col < this->u.cargo.num_cargoes - 1; col++) {
|
|
|
int lf = cargo_base + (col + 1) * CargoesField::cargo_line.width + col * CargoesField::cargo_space.width;
|
|
|
DrawHorConnection(lf + dx - 1, lf + CargoesField::cargo_space.width - 1, ypos, csp);
|
|
|
dx = 1;
|
|
|
}
|
|
|
DrawHorConnection(cargo_base + col * CargoesField::cargo_space.width + (col + 1) * CargoesField::cargo_line.width - 1 + dx, xpos + CargoesField::cargo_field_width - 1, ypos, csp);
|
|
|
}
|
|
|
ypos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case CFT_CARGO_LABEL:
|
|
|
ypos += CargoesField::cargo_border.height + vert_inter_industry_space / 2;
|
|
|
for (uint i = 0; i < MAX_CARGOES; i++) {
|
|
|
if (this->u.cargo_label.cargoes[i] != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(this->u.cargo_label.cargoes[i])) {
|
|
|
const CargoSpec *csp = CargoSpec::Get(this->u.cargo_label.cargoes[i]);
|
|
|
DrawString(xpos + WidgetDimensions::scaled.framerect.left, xpos + industry_width - 1 - WidgetDimensions::scaled.framerect.right, ypos, csp->name, TC_WHITE,
|
|
|
(this->u.cargo_label.left_align) ? SA_LEFT : SA_RIGHT);
|
|
|
}
|
|
|
ypos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
NOT_REACHED();
|
|
|
}
|
|
|
}
|
|
@@ -2239,48 +2239,48 @@ struct CargoesField {
|
|
|
|
|
|
int vpos = vert_inter_industry_space / 2 + CargoesField::cargo_border.width;
|
|
|
uint row;
|
|
|
for (row = 0; row < MAX_CARGOES; row++) {
|
|
|
if (pt.y < vpos) return INVALID_CARGO;
|
|
|
if (pt.y < vpos + FONT_HEIGHT_NORMAL) break;
|
|
|
vpos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.width;
|
|
|
}
|
|
|
if (row == MAX_CARGOES) return INVALID_CARGO;
|
|
|
|
|
|
/* row = 0 -> at first horizontal row, row = 1 -> second horizontal row, 2 = 3rd horizontal row. */
|
|
|
if (col == 0) {
|
|
|
if (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]];
|
|
|
if (IsValidCargoID(this->u.cargo.supp_cargoes[row])) return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]];
|
|
|
if (left != nullptr) {
|
|
|
if (left->type == CFT_INDUSTRY) return left->u.industry.other_produced[row];
|
|
|
if (left->type == CFT_CARGO_LABEL && !left->u.cargo_label.left_align) return left->u.cargo_label.cargoes[row];
|
|
|
}
|
|
|
return INVALID_CARGO;
|
|
|
}
|
|
|
if (col == this->u.cargo.num_cargoes) {
|
|
|
if (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]];
|
|
|
if (IsValidCargoID(this->u.cargo.cust_cargoes[row])) return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]];
|
|
|
if (right != nullptr) {
|
|
|
if (right->type == CFT_INDUSTRY) return right->u.industry.other_accepted[row];
|
|
|
if (right->type == CFT_CARGO_LABEL && right->u.cargo_label.left_align) return right->u.cargo_label.cargoes[row];
|
|
|
}
|
|
|
return INVALID_CARGO;
|
|
|
}
|
|
|
if (row >= col) {
|
|
|
/* Clicked somewhere in-between vertical cargo connection.
|
|
|
* Since the horizontal connection is made in the same order as the vertical list, the above condition
|
|
|
* ensures we are left-below the main diagonal, thus at the supplying side.
|
|
|
*/
|
|
|
return (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] : INVALID_CARGO;
|
|
|
return (IsValidCargoID(this->u.cargo.supp_cargoes[row])) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] : INVALID_CARGO;
|
|
|
} else {
|
|
|
/* Clicked at a customer connection. */
|
|
|
return (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] : INVALID_CARGO;
|
|
|
return (IsValidCargoID(this->u.cargo.cust_cargoes[row])) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] : INVALID_CARGO;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Decide what cargo the user clicked in the cargo label field.
|
|
|
* @param pt Click position in the cargo label field.
|
|
|
* @return Cargo clicked at, or #INVALID_CARGO if none.
|
|
|
*/
|
|
|
CargoID CargoLabelClickedAt(Point pt) const
|
|
|
{
|
|
|
assert(this->type == CFT_CARGO_LABEL);
|
|
|
|
|
@@ -2352,25 +2352,25 @@ struct CargoesRow {
|
|
|
CargoID others[MAX_CARGOES]; // Produced cargoes not carried in the cargo column.
|
|
|
int other_count = 0;
|
|
|
|
|
|
const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type);
|
|
|
assert(CargoesField::max_cargoes <= lengthof(indsp->produced_cargo));
|
|
|
for (uint i = 0; i < CargoesField::max_cargoes; i++) {
|
|
|
int col = cargo_fld->ConnectCargo(indsp->produced_cargo[i], true);
|
|
|
if (col < 0) others[other_count++] = indsp->produced_cargo[i];
|
|
|
}
|
|
|
|
|
|
/* Allocate other cargoes in the empty holes of the horizontal cargo connections. */
|
|
|
for (uint i = 0; i < CargoesField::max_cargoes && other_count > 0; i++) {
|
|
|
if (cargo_fld->u.cargo.supp_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_produced[i] = others[--other_count];
|
|
|
if (!IsValidCargoID(cargo_fld->u.cargo.supp_cargoes[i])) ind_fld->u.industry.other_produced[i] = others[--other_count];
|
|
|
}
|
|
|
} else {
|
|
|
/* Houses only display what is demanded. */
|
|
|
for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) {
|
|
|
CargoID cid = cargo_fld->u.cargo.vertical_cargoes[i];
|
|
|
if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->ConnectCargo(cid, true);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Construct a #CFT_CARGO_LABEL field.
|
|
@@ -2410,25 +2410,25 @@ struct CargoesRow {
|
|
|
CargoID others[MAX_CARGOES]; // Accepted cargoes not carried in the cargo column.
|
|
|
int other_count = 0;
|
|
|
|
|
|
const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type);
|
|
|
assert(CargoesField::max_cargoes <= lengthof(indsp->accepts_cargo));
|
|
|
for (uint i = 0; i < CargoesField::max_cargoes; i++) {
|
|
|
int col = cargo_fld->ConnectCargo(indsp->accepts_cargo[i], false);
|
|
|
if (col < 0) others[other_count++] = indsp->accepts_cargo[i];
|
|
|
}
|
|
|
|
|
|
/* Allocate other cargoes in the empty holes of the horizontal cargo connections. */
|
|
|
for (uint i = 0; i < CargoesField::max_cargoes && other_count > 0; i++) {
|
|
|
if (cargo_fld->u.cargo.cust_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_accepted[i] = others[--other_count];
|
|
|
if (!IsValidCargoID(cargo_fld->u.cargo.cust_cargoes[i])) ind_fld->u.industry.other_accepted[i] = others[--other_count];
|
|
|
}
|
|
|
} else {
|
|
|
/* Houses only display what is demanded. */
|
|
|
for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) {
|
|
|
for (uint h = 0; h < NUM_HOUSES; h++) {
|
|
|
HouseSpec *hs = HouseSpec::Get(h);
|
|
|
if (!hs->enabled) continue;
|
|
|
|
|
|
for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) {
|
|
|
if (hs->cargo_acceptance[j] > 0 && cargo_fld->u.cargo.vertical_cargoes[i] == hs->accepts_cargo[j]) {
|
|
|
cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], false);
|
|
|
goto next_cargo;
|
|
@@ -2593,66 +2593,66 @@ struct IndustryCargoesWindow : public Wi
|
|
|
|
|
|
/**
|
|
|
* Do the two sets of cargoes have a valid cargo in common?
|
|
|
* @param cargoes1 Base address of the first cargo array.
|
|
|
* @param length1 Number of cargoes in the first cargo array.
|
|
|
* @param cargoes2 Base address of the second cargo array.
|
|
|
* @param length2 Number of cargoes in the second cargo array.
|
|
|
* @return Arrays have at least one valid cargo in common.
|
|
|
*/
|
|
|
static bool HasCommonValidCargo(const CargoID *cargoes1, uint length1, const CargoID *cargoes2, uint length2)
|
|
|
{
|
|
|
while (length1 > 0) {
|
|
|
if (*cargoes1 != INVALID_CARGO) {
|
|
|
if (IsValidCargoID(*cargoes1)) {
|
|
|
for (uint i = 0; i < length2; i++) if (*cargoes1 == cargoes2[i]) return true;
|
|
|
}
|
|
|
cargoes1++;
|
|
|
length1--;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Can houses be used to supply one of the cargoes?
|
|
|
* @param cargoes Base address of the cargo array.
|
|
|
* @param length Number of cargoes in the array.
|
|
|
* @return Houses can supply at least one of the cargoes.
|
|
|
*/
|
|
|
static bool HousesCanSupply(const CargoID *cargoes, uint length)
|
|
|
{
|
|
|
for (uint i = 0; i < length; i++) {
|
|
|
if (cargoes[i] == INVALID_CARGO) continue;
|
|
|
if (!IsValidCargoID(cargoes[i])) continue;
|
|
|
if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Can houses be used as customers of the produced cargoes?
|
|
|
* @param cargoes Base address of the cargo array.
|
|
|
* @param length Number of cargoes in the array.
|
|
|
* @return Houses can accept at least one of the cargoes.
|
|
|
*/
|
|
|
static bool HousesCanAccept(const CargoID *cargoes, uint length)
|
|
|
{
|
|
|
HouseZones climate_mask;
|
|
|
switch (_settings_game.game_creation.landscape) {
|
|
|
case LT_TEMPERATE: climate_mask = HZ_TEMP; break;
|
|
|
case LT_ARCTIC: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
|
|
|
case LT_TROPIC: climate_mask = HZ_SUBTROPIC; break;
|
|
|
case LT_TOYLAND: climate_mask = HZ_TOYLND; break;
|
|
|
default: NOT_REACHED();
|
|
|
}
|
|
|
for (uint i = 0; i < length; i++) {
|
|
|
if (cargoes[i] == INVALID_CARGO) continue;
|
|
|
if (!IsValidCargoID(cargoes[i])) continue;
|
|
|
|
|
|
for (uint h = 0; h < NUM_HOUSES; h++) {
|
|
|
HouseSpec *hs = HouseSpec::Get(h);
|
|
|
if (!hs->enabled || !(hs->building_availability & climate_mask)) continue;
|
|
|
|
|
|
for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) {
|
|
|
if (hs->cargo_acceptance[j] > 0 && cargoes[i] == hs->accepts_cargo[j]) return true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
@@ -3003,31 +3003,31 @@ struct IndustryCargoesWindow : public Wi
|
|
|
if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return;
|
|
|
|
|
|
const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x;
|
|
|
switch (fld->type) {
|
|
|
case CFT_INDUSTRY:
|
|
|
if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES) this->ComputeIndustryDisplay(fld->u.industry.ind_type);
|
|
|
break;
|
|
|
|
|
|
case CFT_CARGO: {
|
|
|
CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : nullptr;
|
|
|
CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : nullptr;
|
|
|
CargoID cid = fld->CargoClickedAt(lft, rgt, xy);
|
|
|
if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid);
|
|
|
if (IsValidCargoID(cid)) this->ComputeCargoDisplay(cid);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case CFT_CARGO_LABEL: {
|
|
|
CargoID cid = fld->CargoLabelClickedAt(xy);
|
|
|
if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid);
|
|
|
if (IsValidCargoID(cid)) this->ComputeCargoDisplay(cid);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case WID_IC_NOTIFY:
|
|
|
this->ToggleWidgetLoweredState(WID_IC_NOTIFY);
|
|
|
this->SetWidgetDirty(WID_IC_NOTIFY);
|
|
@@ -3104,25 +3104,25 @@ struct IndustryCargoesWindow : public Wi
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case CFT_INDUSTRY:
|
|
|
if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES && (this->ind_cargo >= NUM_INDUSTRYTYPES || fieldxy.x != 2)) {
|
|
|
GuiShowTooltips(this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, nullptr, close_cond);
|
|
|
}
|
|
|
return true;
|
|
|
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
if (cid != INVALID_CARGO && (this->ind_cargo < NUM_INDUSTRYTYPES || cid != this->ind_cargo - NUM_INDUSTRYTYPES)) {
|
|
|
if (IsValidCargoID(cid) && (this->ind_cargo < NUM_INDUSTRYTYPES || cid != this->ind_cargo - NUM_INDUSTRYTYPES)) {
|
|
|
const CargoSpec *csp = CargoSpec::Get(cid);
|
|
|
uint64 params[5];
|
|
|
params[0] = csp->name;
|
|
|
GuiShowTooltips(this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, close_cond);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
void OnResize() override
|
|
|
{
|