summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels Martin Hansen <nielsm@indvikleren.dk>2018-07-26 19:29:54 +0200
committerNiels Martin Hansen <nielsm@indvikleren.dk>2018-11-03 21:43:54 +0100
commite66cec8f86357918c58b20bd3cc67330f277a5e1 (patch)
tree1d34c8882bdc3fa2150ebcd06ea5e9ce247cd68a
parent8859381d301a60169e167431c97cb084b7730ead (diff)
downloadopenttd-e66cec8f86357918c58b20bd3cc67330f277a5e1.tar.xz
Add: NewGRF support for 16-in-16-out industries
-rw-r--r--src/economy.cpp4
-rw-r--r--src/industry.h19
-rw-r--r--src/industry_cmd.cpp77
-rw-r--r--src/industry_gui.cpp64
-rw-r--r--src/industry_type.h4
-rw-r--r--src/industrytype.h9
-rw-r--r--src/lang/english.txt2
-rw-r--r--src/newgrf.cpp159
-rw-r--r--src/newgrf_industries.cpp66
-rw-r--r--src/newgrf_spritegroup.h10
-rw-r--r--src/saveload/afterload.cpp9
-rw-r--r--src/saveload/industry_sl.cpp3
-rw-r--r--src/subsidy.cpp6
-rw-r--r--src/table/newgrf_debug_data.h37
14 files changed, 393 insertions, 76 deletions
diff --git a/src/economy.cpp b/src/economy.cpp
index b42dc3301..ad9895ba9 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -1062,6 +1062,7 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n
uint amount = min(num_pieces, 0xFFFFU - ind->incoming_cargo_waiting[cargo_index]);
ind->incoming_cargo_waiting[cargo_index] += amount;
+ ind->last_cargo_accepted_at[cargo_index] = _date;
num_pieces -= amount;
accepted += amount;
}
@@ -1138,7 +1139,6 @@ static void TriggerIndustryProduction(Industry *i)
uint16 callback = indspec->callback_mask;
i->was_cargo_delivered = true;
- i->last_cargo_accepted_at = _date;
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) {
@@ -1151,7 +1151,7 @@ static void TriggerIndustryProduction(Industry *i)
uint cargo_waiting = i->incoming_cargo_waiting[ci_in];
if (cargo_waiting == 0) continue;
- for (uint ci_out = 0; ci_out < lengthof(i->produced_cargo_waiting), ci_out++) {
+ for (uint ci_out = 0; ci_out < lengthof(i->produced_cargo_waiting); ci_out++) {
i->produced_cargo_waiting[ci_out] = min(i->produced_cargo_waiting[ci_out] + (cargo_waiting * indspec->input_cargo_multiplier[ci_in][ci_out] / 256), 0xFFFF);
}
diff --git a/src/industry.h b/src/industry.h
index 42cf3aff2..af0208b3c 100644
--- a/src/industry.h
+++ b/src/industry.h
@@ -12,6 +12,7 @@
#ifndef INDUSTRY_H
#define INDUSTRY_H
+#include <algorithm>
#include "newgrf_storage.h"
#include "subsidy_type.h"
#include "industry_map.h"
@@ -64,7 +65,7 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
OwnerByte founder; ///< Founder of the industry
Date construction_date; ///< Date of the construction of the industry
uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType)
- Date last_cargo_accepted_at; ///< Last day cargo was accepted by this industry
+ Date last_cargo_accepted_at[INDUSTRY_NUM_INPUTS]; ///< Last day each cargo type was accepted by this industry
byte selected_layout; ///< Which tile layout was used when creating the industry
uint16 random; ///< Random value used for randomisation of all kinds of things
@@ -86,6 +87,22 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
return IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->index;
}
+ inline int GetCargoProducedIndex(CargoID cargo) const
+ {
+ if (cargo == CT_INVALID) return -1;
+ const CargoID *pos = std::find(this->produced_cargo, endof(this->produced_cargo), cargo);
+ if (pos == endof(this->produced_cargo)) return -1;
+ return pos - this->produced_cargo;
+ }
+
+ inline int GetCargoAcceptedIndex(CargoID cargo) const
+ {
+ if (cargo == CT_INVALID) return -1;
+ const CargoID *pos = std::find(this->accepts_cargo, endof(this->accepts_cargo), cargo);
+ if (pos == endof(this->accepts_cargo)) return -1;
+ return pos - this->accepts_cargo;
+ }
+
/**
* Get the industry of the given tile
* @param tile the tile to get the industry from
diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp
index a30fea6d1..d918ef16b 100644
--- a/src/industry_cmd.cpp
+++ b/src/industry_cmd.cpp
@@ -394,35 +394,49 @@ static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, Ca
{
IndustryGfx gfx = GetIndustryGfx(tile);
const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx);
+ const Industry *ind = Industry::GetByTile(tile);
- /* When we have to use a callback, we put our data in the next two variables */
- CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)];
- uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)];
-
- /* And then these will always point to a same sized array with the required data */
- const CargoID *accepts_cargo = itspec->accepts_cargo;
- const uint8 *cargo_acceptance = itspec->acceptance;
+ /* Starting point for acceptance */
+ CargoID accepts_cargo[lengthof(itspec->accepts_cargo)];
+ int8 cargo_acceptance[lengthof(itspec->acceptance)];
+ MemCpyT(accepts_cargo, itspec->accepts_cargo, lengthof(accepts_cargo));
+ MemCpyT(cargo_acceptance, itspec->acceptance, lengthof(cargo_acceptance));
+
+ if (itspec->special_flags & INDTILE_SPECIAL_ACCEPTS_ALL_CARGO) {
+ /* Copy all accepted cargoes from industry itself */
+ for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
+ CargoID *pos = std::find(accepts_cargo, endof(accepts_cargo), ind->accepts_cargo[i]);
+ if (pos == endof(accepts_cargo)) {
+ /* Not found, insert */
+ pos = std::find(accepts_cargo, endof(accepts_cargo), CT_INVALID);
+ if (pos == endof(accepts_cargo)) continue; // nowhere to place, give up on this one
+ *pos = ind->accepts_cargo[i];
+ }
+ cargo_acceptance[pos - accepts_cargo] += 8;
+ }
+ }
if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) {
+ /* Try callback for accepts list, if success override all existing accepts */
uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile);
if (res != CALLBACK_FAILED) {
- accepts_cargo = raw_accepts_cargo;
- for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
+ MemSetT(accepts_cargo, CT_INVALID, lengthof(accepts_cargo));
+ for (uint i = 0; i < 3; i++) accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile);
}
}
if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) {
+ /* Try callback for acceptance list, if success override all existing acceptance */
uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile);
if (res != CALLBACK_FAILED) {
- cargo_acceptance = raw_cargo_acceptance;
- for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4);
+ MemSetT(cargo_acceptance, 0, lengthof(cargo_acceptance));
+ for (uint i = 0; i < 3; i++) cargo_acceptance[i] = GB(res, i * 4, 4);
}
}
- const Industry *ind = Industry::GetByTile(tile);
for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) {
CargoID a = accepts_cargo[i];
- if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes
+ if (a == CT_INVALID || cargo_acceptance[i] <= 0) continue; // work only with valid cargoes
/* Add accepted cargo */
acceptance[a] += cargo_acceptance[i];
@@ -1659,6 +1673,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
MemSetT(i->last_month_pct_transported, 0, lengthof(i->last_month_pct_transported));
MemSetT(i->last_month_transported, 0, lengthof(i->last_month_transported));
MemSetT(i->incoming_cargo_waiting, 0, lengthof(i->incoming_cargo_waiting));
+ MemSetT(i->last_cargo_accepted_at, 0, lengthof(i->last_cargo_accepted_at));
/* don't use smooth economy for industries using production related callbacks */
if (indspec->UsesSmoothEconomy()) {
@@ -1718,28 +1733,56 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
}
if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
+ /* Clear all input cargo types */
for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
- for (uint j = 0; j < lengthof(i->accepts_cargo); j++) {
+ /* Query actual types */
+ uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? lengthof(i->accepts_cargo) : 3;
+ for (uint j = 0; j < maxcargoes; j++) {
uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
break;
}
- i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
+ CargoID cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
+ if (std::find(indspec->accepts_cargo, endof(indspec->accepts_cargo), cargo) == endof(indspec->accepts_cargo)) {
+ /* Cargo not in spec, error in NewGRF */
+ ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
+ break;
+ }
+ if (std::find(i->accepts_cargo, i->accepts_cargo + j, cargo) != i->accepts_cargo + j) {
+ /* Duplicate cargo */
+ ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
+ break;
+ }
+ i->accepts_cargo[j] = cargo;
}
}
if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
+ /* Clear all output cargo types */
for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
- for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
+ /* Query actual types */
+ uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? lengthof(i->produced_cargo) : 2;
+ for (uint j = 0; j < maxcargoes; j++) {
uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
break;
}
- i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
+ CargoID cargo = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile);
+ if (std::find(indspec->produced_cargo, endof(indspec->produced_cargo), cargo) == endof(indspec->produced_cargo)) {
+ /* Cargo not in spec, error in NewGRF */
+ ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
+ break;
+ }
+ if (std::find(i->produced_cargo, i->produced_cargo + j, cargo) != i->produced_cargo + j) {
+ /* Duplicate cargo */
+ ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
+ break;
+ }
+ i->produced_cargo[j] = cargo;
}
}
diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp
index 1229fec33..d54fb41c1 100644
--- a/src/industry_gui.cpp
+++ b/src/industry_gui.cpp
@@ -74,12 +74,7 @@ static void ShowIndustryCargoesWindow(IndustryType id);
/**
* Gets the string to display after the cargo name (using callback 37)
- * @param cargo the cargo for which the suffix is requested
- * - 00 - first accepted cargo type
- * - 01 - second accepted cargo type
- * - 02 - third accepted cargo type
- * - 03 - first produced cargo type
- * - 04 - second produced cargo type
+ * @param cargo the cargo for which the suffix is requested, meaning depends on presence of flag 18 in prop 1A
* @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType
* @param ind the industry (NULL if in fund window)
* @param ind_type the industry type
@@ -134,9 +129,14 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
}
}
+enum CargoSuffixInOut {
+ CARGOSUFFIX_OUT = 0,
+ CARGOSUFFIX_IN = 1,
+};
+
/**
* Gets all strings to display after the cargoes of industries (using callback 37)
- * @param cb_offset The offset for the cargo used in cb37, 0 for accepted cargoes, 3 for produced cargoes
+ * @param use_input get suffixes for output cargoes or input cargoes?
* @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType
* @param ind the industry (NULL if in fund window)
* @param ind_type the industry type
@@ -145,14 +145,40 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,
* @param suffixes is filled with the suffixes
*/
template <typename TC, typename TS>
-static inline void GetAllCargoSuffixes(uint cb_offset, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes)
+static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes)
{
assert_compile(lengthof(cargoes) <= lengthof(suffixes));
- for (uint j = 0; j < lengthof(cargoes); j++) {
- if (cargoes[j] != CT_INVALID) {
- GetCargoSuffix(cb_offset + j, cst, ind, ind_type, indspec, suffixes[j]);
- } else {
+
+ 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) {
+ 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]);
+ 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]);
+ break;
+ default:
+ NOT_REACHED();
}
}
}
@@ -359,7 +385,7 @@ public:
const IndustrySpec *indsp = GetIndustrySpec(this->index[i]);
CargoSuffix cargo_suffix[lengthof(indsp->accepts_cargo)];
- GetAllCargoSuffixes(0, CST_FUND, NULL, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix);
+ GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, NULL, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix);
StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
byte p = 0;
SetDParam(0, STR_JUST_NOTHING);
@@ -373,7 +399,7 @@ public:
d = maxdim(d, GetStringBoundingBox(str));
/* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */
- GetAllCargoSuffixes(3, CST_FUND, NULL, this->index[i], indsp, indsp->produced_cargo, cargo_suffix);
+ GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, NULL, this->index[i], indsp, indsp->produced_cargo, cargo_suffix);
str = STR_INDUSTRY_VIEW_PRODUCES_CARGO;
p = 0;
SetDParam(0, STR_JUST_NOTHING);
@@ -478,7 +504,7 @@ public:
/* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */
CargoSuffix cargo_suffix[lengthof(indsp->accepts_cargo)];
- GetAllCargoSuffixes(0, CST_FUND, NULL, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix);
+ GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_FUND, NULL, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix);
StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO;
byte p = 0;
SetDParam(0, STR_JUST_NOTHING);
@@ -493,7 +519,7 @@ public:
y += FONT_HEIGHT_NORMAL;
/* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */
- GetAllCargoSuffixes(3, CST_FUND, NULL, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix);
+ GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_FUND, NULL, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix);
str = STR_INDUSTRY_VIEW_PRODUCES_CARGO;
p = 0;
SetDParam(0, STR_JUST_NOTHING);
@@ -771,7 +797,7 @@ public:
}
CargoSuffix cargo_suffix[lengthof(i->accepts_cargo)];
- GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix);
+ 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);
uint left_side = left + WD_FRAMERECT_LEFT * 4; // Indent accepted cargoes.
@@ -810,7 +836,7 @@ public:
y += FONT_HEIGHT_NORMAL;
}
- GetAllCargoSuffixes(3, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix);
+ GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix);
first = true;
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (i->produced_cargo[j] == CT_INVALID) continue;
@@ -1262,7 +1288,7 @@ protected:
SetDParam(p++, i->index);
static CargoSuffix cargo_suffix[lengthof(i->produced_cargo)];
- GetAllCargoSuffixes(3, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix);
+ GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix);
/* Industry productions */
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
diff --git a/src/industry_type.h b/src/industry_type.h
index 6234f7b11..9a8a46901 100644
--- a/src/industry_type.h
+++ b/src/industry_type.h
@@ -37,6 +37,10 @@ static const IndustryGfx INVALID_INDUSTRYTILE = NUM_INDUSTRYTILES; ///< one a
static const int INDUSTRY_COMPLETED = 3; ///< final stage of industry construction.
+static const int INDUSTRY_NUM_INPUTS = 16; ///< Number of cargo types an industry can accept
+static const int INDUSTRY_NUM_OUTPUTS = 16; ///< Number of cargo types an industry can produce
+
+
void CheckIndustries();
#endif /* INDUSTRY_TYPE_H */
diff --git a/src/industrytype.h b/src/industrytype.h
index da09a6d9b..cd451fa77 100644
--- a/src/industrytype.h
+++ b/src/industrytype.h
@@ -80,6 +80,7 @@ enum IndustryBehaviour {
INDUSTRYBEH_PRODCALLBACK_RANDOM = 1 << 15, ///< Production callback needs random bits in var 10
INDUSTRYBEH_NOBUILT_MAPCREATION = 1 << 16, ///< Do not force one instance of this type to appear on map generation
INDUSTRYBEH_CANCLOSE_LASTINSTANCE = 1 << 17, ///< Allow closing down the last instance of this type
+ INDUSTRYBEH_CARGOTYPES_UNLIMITED = 1 << 18, ///< Allow produced/accepted cargoes callbacks to supply more than 2 and 3 types
};
DECLARE_ENUM_AS_BIT_SET(IndustryBehaviour)
@@ -87,6 +88,7 @@ DECLARE_ENUM_AS_BIT_SET(IndustryBehaviour)
enum IndustryTileSpecialFlags {
INDTILE_SPECIAL_NONE = 0,
INDTILE_SPECIAL_NEXTFRAME_RANDOMBITS = 1 << 0, ///< Callback 0x26 needs random bits
+ INDTILE_SPECIAL_ACCEPTS_ALL_CARGO = 1 << 1, ///< Tile always accepts all cargoes the associated industry accepts
};
DECLARE_ENUM_AS_BIT_SET(IndustryTileSpecialFlags)
@@ -95,9 +97,6 @@ struct IndustryTileTable {
IndustryGfx gfx;
};
-const int INDUSTRY_NUM_INPUTS = 16; ///< Number of cargo types an industry can accept
-const int INDUSTRY_NUM_OUTPUTS = 16; ///< Number of cargo types an industry can produce
-
/**
* Defines the data structure for constructing industry.
*/
@@ -150,8 +149,8 @@ struct IndustrySpec {
* @note A tile can at most accept 3 types of cargo, even if an industry as a whole can accept more types.
*/
struct IndustryTileSpec {
- CargoID accepts_cargo[3]; ///< Cargo accepted by this tile
- uint8 acceptance[3]; ///< Level of acceptance per cargo type
+ CargoID accepts_cargo[INDUSTRY_NUM_INPUTS]; ///< Cargo accepted by this tile
+ int8 acceptance[INDUSTRY_NUM_INPUTS]; ///< Level of acceptance per cargo type (signed, may be negative!)
Slope slopes_refused; ///< slope pattern on which this tile cannot be built
byte anim_production; ///< Animation frame to start when goods are produced
byte anim_next; ///< Next frame in an animation
diff --git a/src/lang/english.txt b/src/lang/english.txt
index d33afbfaa..cb04a5cbd 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -2970,6 +2970,8 @@ STR_NEWGRF_ERROR_READ_BOUNDS :Read past end o
STR_NEWGRF_ERROR_GRM_FAILED :Requested GRF resources not available (sprite {3:NUM})
STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:RAW_STRING} was disabled by {2:RAW_STRING}
STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Invalid/unknown sprite layout format (sprite {3:NUM})
+STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG :Too many elements in property value list (sprite {3:NUM}, property {4:HEX})
+STR_NEWGRF_ERROR_INDPROD_CALLBACK :Invalid industry production callback (sprite {3:NUM}, "{1:RAW_STRING}")
# NewGRF related 'general' warnings
STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Caution!
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 93b28a1bc..57dcb41ca 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -3083,6 +3083,10 @@ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader *buf)
buf->ReadWord();
break;
+ case 0x13:
+ buf->Skip(buf->ReadByte() * 2);
+ break;
+
default:
ret = CIR_UNKNOWN;
break;
@@ -3172,7 +3176,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr
case 0x0C: {
uint16 acctp = buf->ReadWord();
tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur.grffile);
- tsp->acceptance[prop - 0x0A] = GB(acctp, 8, 8);
+ tsp->acceptance[prop - 0x0A] = Clamp(GB(acctp, 8, 8), 0, 16);
break;
}
@@ -3201,6 +3205,26 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr
tsp->special_flags = (IndustryTileSpecialFlags)buf->ReadByte();
break;
+ case 0x13: { // variable length cargo acceptance
+ byte num_cargoes = buf->ReadByte();
+ if (num_cargoes > lengthof(tsp->acceptance)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
+ error->param_value[1] = prop;
+ return CIR_DISABLED;
+ }
+ for (uint i = 0; i < lengthof(tsp->acceptance); i++) {
+ if (i < num_cargoes) {
+ tsp->accepts_cargo[i] = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
+ /* Tile acceptance can be negative to counteract the INDTILE_SPECIAL_ACCEPTS_ALL_CARGO flag */
+ tsp->acceptance[i] = (int8)buf->ReadByte();
+ } else {
+ tsp->accepts_cargo[i] = CT_INVALID;
+ tsp->acceptance[i] = 0;
+ }
+ }
+ break;
+ }
+
default:
ret = CIR_UNKNOWN;
break;
@@ -3280,11 +3304,17 @@ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader *buf)
for (byte j = 0; j < 3; j++) buf->ReadByte();
break;
- case 0x15: {
- byte number_of_sounds = buf->ReadByte();
- for (uint8 j = 0; j < number_of_sounds; j++) {
- buf->ReadByte();
- }
+ case 0x15:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ buf->Skip(buf->ReadByte());
+ break;
+
+ case 0x28: {
+ int num_inputs = buf->ReadByte();
+ int num_outputs = buf->ReadByte();
+ buf->Skip(num_inputs * num_outputs * 2);
break;
}
@@ -3642,6 +3672,77 @@ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop,
break;
}
+ case 0x25: { // variable length produced cargoes
+ byte num_cargoes = buf->ReadByte();
+ if (num_cargoes > lengthof(indsp->produced_cargo)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
+ error->param_value[1] = prop;
+ return CIR_DISABLED;
+ }
+ for (uint i = 0; i < lengthof(indsp->produced_cargo); i++) {
+ if (i < num_cargoes) {
+ CargoID cargo = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
+ indsp->produced_cargo[i] = cargo;
+ } else {
+ indsp->produced_cargo[i] = CT_INVALID;
+ }
+ }
+ break;
+ }
+
+ case 0x26: { // variable length accepted cargoes
+ byte num_cargoes = buf->ReadByte();
+ if (num_cargoes > lengthof(indsp->accepts_cargo)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
+ error->param_value[1] = prop;
+ return CIR_DISABLED;
+ }
+ for (uint i = 0; i < lengthof(indsp->accepts_cargo); i++) {
+ if (i < num_cargoes) {
+ CargoID cargo = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
+ indsp->accepts_cargo[i] = cargo;
+ } else {
+ indsp->accepts_cargo[i] = CT_INVALID;
+ }
+ }
+ break;
+ }
+
+ case 0x27: { // variable length production rates
+ byte num_cargoes = buf->ReadByte();
+ if (num_cargoes > lengthof(indsp->production_rate)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
+ error->param_value[1] = prop;
+ return CIR_DISABLED;
+ }
+ for (uint i = 0; i < lengthof(indsp->production_rate); i++) {
+ if (i < num_cargoes) {
+ indsp->production_rate[i] = buf->ReadByte();
+ } else {
+ indsp->production_rate[i] = 0;
+ }
+ }
+ break;
+ }
+
+ case 0x28: { // variable size input/output production multiplier table
+ byte num_inputs = buf->ReadByte();
+ byte num_outputs = buf->ReadByte();
+ if (num_inputs > lengthof(indsp->accepts_cargo) || num_outputs > lengthof(indsp->produced_cargo)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LIST_PROPERTY_TOO_LONG);
+ error->param_value[1] = prop;
+ return CIR_DISABLED;
+ }
+ for (uint i = 0; i < lengthof(indsp->accepts_cargo); i++) {
+ for (uint j = 0; j < lengthof(indsp->produced_cargo); j++) {
+ uint16 mult = 0;
+ if (i < num_inputs && j < num_outputs) mult = buf->ReadWord();
+ indsp->input_cargo_multiplier[i][j] = mult;
+ }
+ }
+ break;
+ }
+
default:
ret = CIR_UNKNOWN;
break;
@@ -4839,7 +4940,7 @@ static void NewSpriteGroup(ByteReader *buf)
}
case GSF_INDUSTRIES: {
- if (type > 1) {
+ if (type > 2) {
grfmsg(1, "NewSpriteGroup: Unsupported industry production version %d, skipping", type);
break;
}
@@ -4849,21 +4950,63 @@ static void NewSpriteGroup(ByteReader *buf)
act_group = group;
group->version = type;
if (type == 0) {
+ group->num_input = 3;
for (uint i = 0; i < 3; i++) {
group->subtract_input[i] = (int16)buf->ReadWord(); // signed
}
+ group->num_output = 2;
for (uint i = 0; i < 2; i++) {
group->add_output[i] = buf->ReadWord(); // unsigned
}
group->again = buf->ReadByte();
- } else {
+ } else if (type == 1) {
+ group->num_input = 3;
for (uint i = 0; i < 3; i++) {
group->subtract_input[i] = buf->ReadByte();
}
+ group->num_output = 2;
for (uint i = 0; i < 2; i++) {
group->add_output[i] = buf->ReadByte();
}
group->again = buf->ReadByte();
+ } else if (type == 2) {
+ group->num_input = buf->ReadByte();
+ if (group->num_input > lengthof(group->subtract_input)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
+ error->data = stredup("too many inputs (max 16)");
+ return;
+ }
+ for (uint i = 0; i < group->num_input; i++) {
+ byte rawcargo = buf->ReadByte();
+ CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile);
+ if (std::find(group->cargo_input, group->cargo_input + i, cargo) != group->cargo_input + i) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
+ error->data = stredup("duplicate input cargo");
+ return;
+ }
+ group->cargo_input[i] = cargo;
+ group->subtract_input[i] = buf->ReadByte();
+ }
+ group->num_output = buf->ReadByte();
+ if (group->num_output > lengthof(group->add_output)) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
+ error->data = stredup("too many outputs (max 16)");
+ return;
+ }
+ for (uint i = 0; i < group->num_output; i++) {
+ byte rawcargo = buf->ReadByte();
+ CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile);
+ if (std::find(group->cargo_output, group->cargo_output + i, cargo) != group->cargo_output + i) {
+ GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
+ error->data = stredup("duplicate output cargo");
+ return;
+ }
+ group->cargo_output[i] = cargo;
+ group->add_output[i] = buf->ReadByte();
+ }
+ group->again = buf->ReadByte();
+ } else {
+ NOT_REACHED();
}
break;
}
diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp
index c3ddda79a..de388c023 100644
--- a/src/newgrf_industries.cpp
+++ b/src/newgrf_industries.cpp
@@ -304,6 +304,33 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
return GetCountAndDistanceOfClosestInstance(parameter, layout_filter, town_filter, this->industry);
}
+ case 0x69:
+ case 0x6A:
+ case 0x6B:
+ case 0x6C:
+ case 0x6D: {
+ CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile);
+ int index = this->industry->GetCargoProducedIndex(cargo);
+ if (index < 0) return 0; // invalid cargo
+ if (variable == 0x69) return this->industry->produced_cargo_waiting[index];
+ if (variable == 0x6A) return this->industry->this_month_production[index];
+ if (variable == 0x6B) return this->industry->this_month_transported[index];
+ if (variable == 0x6C) return this->industry->last_month_production[index];
+ if (variable == 0x6D) return this->industry->last_month_transported[index];
+ NOT_REACHED();
+ }
+
+
+ case 0x6E:
+ case 0x6F: {
+ CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile);
+ int index = this->industry->GetCargoAcceptedIndex(cargo);
+ if (index < 0) return 0; // invalid cargo
+ if (variable == 0x6E) return this->industry->last_cargo_accepted_at[index];
+ if (variable == 0x6F) return this->industry->incoming_cargo_waiting[index];
+ NOT_REACHED();
+ }
+
/* Get a variable from the persistent storage */
case 0x7C: return (this->industry->psa != NULL) ? this->industry->psa->GetValue(parameter) : 0;
@@ -364,7 +391,10 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
case 0xB0: return Clamp(this->industry->construction_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Date when built since 1920 (in days)
case 0xB3: return this->industry->construction_type; // Construction type
- case 0xB4: return Clamp(this->industry->last_cargo_accepted_at - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Date last cargo accepted since 1920 (in days)
+ case 0xB4: {
+ Date *latest = std::max_element(this->industry->last_cargo_accepted_at, endof(this->industry->last_cargo_accepted_at));
+ return Clamp((*latest) - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Date last cargo accepted since 1920 (in days)
+ }
}
DEBUG(grf, 1, "Unhandled industry variable 0x%X", variable);
@@ -575,13 +605,28 @@ void IndustryProductionCallback(Industry *ind, int reason)
if (tgroup == NULL || tgroup->type != SGT_INDUSTRY_PRODUCTION) break;
const IndustryProductionSpriteGroup *group = (const IndustryProductionSpriteGroup *)tgroup;
- bool deref = (group->version == 1);
+ bool deref = (group->version >= 1);
- for (uint i = 0; i < 3; i++) {
- ind->incoming_cargo_waiting[i] = Clamp(ind->incoming_cargo_waiting[i] - DerefIndProd(group->subtract_input[i], deref) * multiplier, 0, 0xFFFF);
- }
- for (uint i = 0; i < 2; i++) {
- ind->produced_cargo_waiting[i] = Clamp(ind->produced_cargo_waiting[i] + max(DerefIndProd(group->add_output[i], deref), 0) * multiplier, 0, 0xFFFF);
+ if (group->version < 2) {
+ /* Callback parameters map directly to industry cargo slot indices */
+ for (uint i = 0; i < group->num_input; i++) {
+ ind->incoming_cargo_waiting[i] = Clamp(ind->incoming_cargo_waiting[i] - DerefIndProd(group->subtract_input[i], deref) * multiplier, 0, 0xFFFF);
+ }
+ for (uint i = 0; i < group->num_output; i++) {
+ ind->produced_cargo_waiting[i] = Clamp(ind->produced_cargo_waiting[i] + max(DerefIndProd(group->add_output[i], deref), 0) * multiplier, 0, 0xFFFF);
+ }
+ } else {
+ /* Callback receives list of cargos to apply for, which need to have their cargo slots in industry looked up */
+ for (uint i = 0; i < group->num_input; i++) {
+ int cargo_index = ind->GetCargoAcceptedIndex(group->cargo_input[i]);
+ if (cargo_index < 0) continue;
+ ind->incoming_cargo_waiting[cargo_index] = Clamp(ind->incoming_cargo_waiting[cargo_index] - DerefIndProd(group->subtract_input[i], deref) * multiplier, 0, 0xFFFF);
+ }
+ for (uint i = 0; i < group->num_output; i++) {
+ int cargo_index = ind->GetCargoProducedIndex(group->cargo_output[i]);
+ if (cargo_index < 0) continue;
+ ind->produced_cargo_waiting[cargo_index] = Clamp(ind->produced_cargo_waiting[cargo_index] + max(DerefIndProd(group->add_output[i], deref), 0) * multiplier, 0, 0xFFFF);
+ }
}
int32 again = DerefIndProd(group->again, deref);
@@ -602,12 +647,7 @@ void IndustryProductionCallback(Industry *ind, int reason)
*/
bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type)
{
- assert(
- cargo_type == ind->accepts_cargo[0] || cargo_type == ind->accepts_cargo[1] || cargo_type == ind->accepts_cargo[2] || cargo_type == ind->accepts_cargo[3] ||
- cargo_type == ind->accepts_cargo[4] || cargo_type == ind->accepts_cargo[5] || cargo_type == ind->accepts_cargo[6] || cargo_type == ind->accepts_cargo[7] ||
- cargo_type == ind->accepts_cargo[8] || cargo_type == ind->accepts_cargo[9] || cargo_type == ind->accepts_cargo[10] || cargo_type == ind->accepts_cargo[11] ||
- cargo_type == ind->accepts_cargo[12] || cargo_type == ind->accepts_cargo[13] || cargo_type == ind->accepts_cargo[14] || cargo_type == ind->accepts_cargo[15]
- );
+ assert(std::find(ind->accepts_cargo, endof(ind->accepts_cargo), cargo_type) != endof(ind->accepts_cargo));
const IndustrySpec *indspec = GetIndustrySpec(ind->type);
if (HasBit(indspec->callback_mask, CBM_IND_REFUSE_CARGO)) {
diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h
index 6adf7c2ac..6f038fd13 100644
--- a/src/newgrf_spritegroup.h
+++ b/src/newgrf_spritegroup.h
@@ -15,6 +15,7 @@
#include "town_type.h"
#include "engine_type.h"
#include "house_type.h"
+#include "industry_type.h"
#include "newgrf_callbacks.h"
#include "newgrf_generic.h"
@@ -277,9 +278,14 @@ struct IndustryProductionSpriteGroup : SpriteGroup {
IndustryProductionSpriteGroup() : SpriteGroup(SGT_INDUSTRY_PRODUCTION) {}
uint8 version;
- int16 subtract_input[3]; // signed
- uint16 add_output[2]; // unsigned
+ uint8 num_input; ///< How many subtract_input values are valid
+ int16 subtract_input[INDUSTRY_NUM_INPUTS]; ///< Take this much of the input cargo (can be negative, is indirect in cb version 1+)
+ CargoID cargo_input[INDUSTRY_NUM_INPUTS]; ///< Which input cargoes to take from (only cb version 2)
+ uint8 num_output; ///< How many add_output values are valid
+ uint16 add_output[INDUSTRY_NUM_OUTPUTS]; ///< Add this much output cargo when successful (unsigned, is indirect in cb version 1+)
+ CargoID cargo_output[INDUSTRY_NUM_OUTPUTS]; ///< Which output cargoes to add to (only cb version 2)
uint8 again;
+
};
/**
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index 1529aca2b..077f86bf6 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -3033,6 +3033,15 @@ bool AfterLoadGame()
i->accepts_cargo[ci] = CT_INVALID;
i->incoming_cargo_waiting[ci] = 0;
}
+ /* Make sure last_cargo_accepted_at is copied to elements for every valid input cargo.
+ * The loading routine should put the original singular value into the first array element. */
+ for (size_t ci = 0; ci < lengthof(i->accepts_cargo); ci++) {
+ if (i->accepts_cargo[ci] != CT_INVALID) {
+ i->last_cargo_accepted_at[ci] = i->last_cargo_accepted_at[0];
+ } else {
+ i->last_cargo_accepted_at[ci] = 0;
+ }
+ }
}
}
diff --git a/src/saveload/industry_sl.cpp b/src/saveload/industry_sl.cpp
index 9727e4e51..a9c84e62a 100644
--- a/src/saveload/industry_sl.cpp
+++ b/src/saveload/industry_sl.cpp
@@ -61,7 +61,8 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, founder, SLE_UINT8, 70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_date, SLE_INT32, 70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_type, SLE_UINT8, 70, SL_MAX_VERSION),
- SLE_CONDVAR(Industry, last_cargo_accepted_at, SLE_INT32, 70, SL_MAX_VERSION),
+ SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, 70, 201),
+ SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, 202, SL_MAX_VERSION),
SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, 73, SL_MAX_VERSION),
SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16, 76, 160),
diff --git a/src/subsidy.cpp b/src/subsidy.cpp
index fa327efa9..d1fda0f0a 100644
--- a/src/subsidy.cpp
+++ b/src/subsidy.cpp
@@ -384,12 +384,12 @@ bool FindSubsidyIndustryCargoRoute()
/* Randomize cargo type */
int num_cargos = 0;
- for (size_t ci = 0; ci < lengthof(src_ind->produced_cargo); ci++) {
- if (src_ind->produced_cargo[ci] != CT_INVALID) num_cargos++;
+ uint cargo_index;
+ for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) {
+ if (src_ind->produced_cargo[cargo_index] != CT_INVALID) num_cargos++;
}
if (num_cargos == 0) return false; // industry produces nothing
int cargo_num = RandomRange(num_cargos) + 1;
- int cargo_index;
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) {
if (src_ind->produced_cargo[cargo_index] != CT_INVALID) cargo_num--;
if (cargo_num == 0) break;
diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h
index a6aa71616..19b411fed 100644
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -272,11 +272,38 @@ static const NIFeature _nif_industrytile = {
/*** NewGRF industries ***/
static const NIProperty _nip_industries[] = {
- NIP(0x10, Industry, produced_cargo[0], NIT_CARGO, "produced cargo 0"),
- NIP(0x10, Industry, produced_cargo[1], NIT_CARGO, "produced cargo 1"),
- NIP(0x11, Industry, accepts_cargo[0], NIT_CARGO, "accepted cargo 0"),
- NIP(0x11, Industry, accepts_cargo[1], NIT_CARGO, "accepted cargo 1"),
- NIP(0x11, Industry, accepts_cargo[2], NIT_CARGO, "accepted cargo 2"),
+ NIP(0x25, Industry, produced_cargo[ 0], NIT_CARGO, "produced cargo 0"),
+ NIP(0x25, Industry, produced_cargo[ 1], NIT_CARGO, "produced cargo 1"),
+ NIP(0x25, Industry, produced_cargo[ 2], NIT_CARGO, "produced cargo 2"),
+ NIP(0x25, Industry, produced_cargo[ 3], NIT_CARGO, "produced cargo 3"),
+ NIP(0x25, Industry, produced_cargo[ 4], NIT_CARGO, "produced cargo 4"),
+ NIP(0x25, Industry, produced_cargo[ 5], NIT_CARGO, "produced cargo 5"),
+ NIP(0x25, Industry, produced_cargo[ 6], NIT_CARGO, "produced cargo 6"),
+ NIP(0x25, Industry, produced_cargo[ 7], NIT_CARGO, "produced cargo 7"),
+ NIP(0x25, Industry, produced_cargo[ 8], NIT_CARGO, "produced cargo 8"),
+ NIP(0x25, Industry, produced_cargo[ 9], NIT_CARGO, "produced cargo 9"),
+ NIP(0x25, Industry, produced_cargo[10], NIT_CARGO, "produced cargo 10"),
+ NIP(0x25, Industry, produced_cargo[11], NIT_CARGO, "produced cargo 11"),
+ NIP(0x25, Industry, produced_cargo[12], NIT_CARGO, "produced cargo 12"),
+ NIP(0x25, Industry, produced_cargo[13], NIT_CARGO, "produced cargo 13"),
+ NIP(0x25, Industry, produced_cargo[14], NIT_CARGO, "produced cargo 14"),
+ NIP(0x25, Industry, produced_cargo[15], NIT_CARGO, "produced cargo 15"),
+ NIP(0x26, Industry, accepts_cargo[ 0], NIT_CARGO, "accepted cargo 0"),
+ NIP(0x26, Industry, accepts_cargo[ 1], NIT_CARGO, "accepted cargo 1"),
+ NIP(0x26, Industry, accepts_cargo[ 2], NIT_CARGO, "accepted cargo 2"),
+ NIP(0x26, Industry, accepts_cargo[ 3], NIT_CARGO, "accepted cargo 3"),
+ NIP(0x26, Industry, accepts_cargo[ 4], NIT_CARGO, "accepted cargo 4"),
+ NIP(0x26, Industry, accepts_cargo[ 5], NIT_CARGO, "accepted cargo 5"),
+ NIP(0x26, Industry, accepts_cargo[ 6], NIT_CARGO, "accepted cargo 6"),
+ NIP(0x26, Industry, accepts_cargo[ 7], NIT_CARGO, "accepted cargo 7"),
+ NIP(0x26, Industry, accepts_cargo[ 8], NIT_CARGO, "accepted cargo 8"),
+ NIP(0x26, Industry, accepts_cargo[ 9], NIT_CARGO, "accepted cargo 9"),
+ NIP(0x26, Industry, accepts_cargo[10], NIT_CARGO, "accepted cargo 10"),
+ NIP(0x26, Industry, accepts_cargo[11], NIT_CARGO, "accepted cargo 11"),
+ NIP(0x26, Industry, accepts_cargo[12], NIT_CARGO, "accepted cargo 12"),
+ NIP(0x26, Industry, accepts_cargo[13], NIT_CARGO, "accepted cargo 13"),
+ NIP(0x26, Industry, accepts_cargo[14], NIT_CARGO, "accepted cargo 14"),
+ NIP(0x26, Industry, accepts_cargo[15], NIT_CARGO, "accepted cargo 15"),
NIP_END()
};