Large diffs are not rendered by default.

@@ -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 */
@@ -80,13 +80,15 @@ 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)

/** Flags for miscellaneous industry tile specialities */
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)

@@ -99,41 +101,41 @@ struct IndustryTileTable {
* Defines the data structure for constructing industry.
*/
struct IndustrySpec {
const IndustryTileTable * const *table;///< List of the tiles composing the industry
byte num_table; ///< Number of elements in the table
uint8 cost_multiplier; ///< Base construction cost multiplier.
uint32 removal_cost_multiplier; ///< Base removal cost multiplier.
uint32 prospecting_chance; ///< Chance prospecting succeeds
IndustryType conflicting[3]; ///< Industries this industry cannot be close to
byte check_proc; ///< Index to a procedure to check for conflicting circumstances
CargoID produced_cargo[2];
byte production_rate[2];
const IndustryTileTable * const *table; ///< List of the tiles composing the industry
byte num_table; ///< Number of elements in the table
uint8 cost_multiplier; ///< Base construction cost multiplier.
uint32 removal_cost_multiplier; ///< Base removal cost multiplier.
uint32 prospecting_chance; ///< Chance prospecting succeeds
IndustryType conflicting[3]; ///< Industries this industry cannot be close to
byte check_proc; ///< Index to a procedure to check for conflicting circumstances
CargoID produced_cargo[INDUSTRY_NUM_OUTPUTS];
byte production_rate[INDUSTRY_NUM_OUTPUTS];
/**
* minimum amount of cargo transported to the stations.
* If the waiting cargo is less than this number, no cargo is moved to it.
*/
byte minimal_cargo;
CargoID accepts_cargo[3]; ///< 3 accepted cargoes.
uint16 input_cargo_multiplier[3][2]; ///< Input cargo multipliers (multiply amount of incoming cargo for the produced cargoes)
IndustryLifeType life_type; ///< This is also known as Industry production flag, in newgrf specs
byte climate_availability; ///< Bitmask, giving landscape enums as bit position
IndustryBehaviour behaviour; ///< How this industry will behave, and how others entities can use it
byte map_colour; ///< colour used for the small map
StringID name; ///< Displayed name of the industry
StringID new_industry_text; ///< Message appearing when the industry is built
StringID closure_text; ///< Message appearing when the industry closes
StringID production_up_text; ///< Message appearing when the industry's production is increasing
StringID production_down_text; ///< Message appearing when the industry's production is decreasing
StringID station_name; ///< Default name for nearby station
byte appear_ingame[NUM_LANDSCAPE]; ///< Probability of appearance in game
byte appear_creation[NUM_LANDSCAPE]; ///< Probability of appearance during map creation
uint8 number_of_sounds; ///< Number of sounds available in the sounds array
const uint8 *random_sounds; ///< array of random sounds.
CargoID accepts_cargo[INDUSTRY_NUM_INPUTS]; ///< 16 accepted cargoes.
uint16 input_cargo_multiplier[INDUSTRY_NUM_INPUTS][INDUSTRY_NUM_OUTPUTS]; ///< Input cargo multipliers (multiply amount of incoming cargo for the produced cargoes)
This conversation was marked as resolved by nielsmh

This comment has been minimized.

@nielsmh

nielsmh Oct 7, 2018
Author Contributor

Re-indent remaining comments in block here to match the accepts_cargo comment indent level?

IndustryLifeType life_type; ///< This is also known as Industry production flag, in newgrf specs
byte climate_availability; ///< Bitmask, giving landscape enums as bit position
IndustryBehaviour behaviour; ///< How this industry will behave, and how others entities can use it
byte map_colour; ///< colour used for the small map
StringID name; ///< Displayed name of the industry
StringID new_industry_text; ///< Message appearing when the industry is built
StringID closure_text; ///< Message appearing when the industry closes
StringID production_up_text; ///< Message appearing when the industry's production is increasing
StringID production_down_text; ///< Message appearing when the industry's production is decreasing
StringID station_name; ///< Default name for nearby station
byte appear_ingame[NUM_LANDSCAPE]; ///< Probability of appearance in game
byte appear_creation[NUM_LANDSCAPE]; ///< Probability of appearance during map creation
uint8 number_of_sounds; ///< Number of sounds available in the sounds array
const uint8 *random_sounds; ///< array of random sounds.
/* Newgrf data */
uint16 callback_mask; ///< Bitmask of industry callbacks that have to be called
uint8 cleanup_flag; ///< flags indicating which data should be freed upon cleaning up
bool enabled; ///< entity still available (by default true).newgrf can disable it, though
GRFFileProps grf_prop; ///< properties related to the grf file
uint16 callback_mask; ///< Bitmask of industry callbacks that have to be called
uint8 cleanup_flag; ///< flags indicating which data should be freed upon cleaning up
bool enabled; ///< entity still available (by default true).newgrf can disable it, though
GRFFileProps grf_prop; ///< properties related to the grf file

bool IsRawIndustry() const;
bool IsProcessingIndustry() const;
@@ -144,10 +146,11 @@ struct IndustrySpec {

/**
* Defines the data structure of each individual tile of an industry.
* @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
@@ -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!
@@ -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();
This conversation was marked as resolved by nielsmh

This comment has been minimized.

@frosch123

frosch123 Nov 3, 2018
Member

DisableGrf(..) if num_cargoes > lengthof(tsp->acceptance)

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;
}
@@ -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) {
This conversation was marked as resolved by nielsmh

This comment has been minimized.

@frosch123

frosch123 Jul 27, 2018
Member

The comments here are misleading.
This "if" is about whether group->cargo_input/output is valid and shall be used.
Even though the number of cargos are known for version < 2, I would still use num_input/output there, since they are set in newgrf.cpp.

This conversation was marked as resolved by nielsmh

This comment has been minimized.

@nielsmh

nielsmh Oct 7, 2018
Author Contributor

Thinking about this again, maybe there should still be a choice between direct/indirect cargo types specification here. I think @andythenorth talked about the indirection being a bother and not useful?

One idea would be to let the lowest bit specify whether indirection is used, and the next whether long cargo lists are used, such that:

  • v0 = direct cargo spec, short lists
  • v1 = indirect cargo spec, short lists
  • v2 = direct cargo spec, long lists
  • v3 = indirect cargo spec, long lists.

This comment has been minimized.

@nielsmh

nielsmh Oct 27, 2018
Author Contributor

Talked to Andy about this, no change to the spec/code is needed here.

/* 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,7 +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]);
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)) {
@@ -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;

};

/**
@@ -3015,6 +3015,36 @@ bool AfterLoadGame()
}
}

if (IsSavegameVersionBefore(202)) {
/* Make sure added industry cargo slots are cleared */
Industry *i;
FOR_ALL_INDUSTRIES(i) {
for (size_t ci = 2; ci < lengthof(i->produced_cargo); ci++) {
i->produced_cargo[ci] = CT_INVALID;
i->produced_cargo_waiting[ci] = 0;
i->production_rate[ci] = 0;
i->last_month_production[ci] = 0;
i->last_month_transported[ci] = 0;
i->last_month_pct_transported[ci] = 0;
i->this_month_production[ci] = 0;
i->this_month_transported[ci] = 0;
}
for (size_t ci = 3; ci < lengthof(i->accepts_cargo); ci++) {
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;
}
}
}
}

/* Station acceptance is some kind of cache */
if (IsSavegameVersionBefore(127)) {
Station *st;
@@ -26,18 +26,28 @@ static const SaveLoad _industry_desc[] = {
SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16),
SLE_REF(Industry, town, REF_TOWN),
SLE_CONDNULL( 2, 0, 60), ///< used to be industry's produced_cargo
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, 78, SL_MAX_VERSION),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, 70, SL_MAX_VERSION),
SLE_ARR(Industry, produced_cargo_waiting, SLE_UINT16, 2),
SLE_ARR(Industry, production_rate, SLE_UINT8, 2),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, 78, 201),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, 70, 201),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, 0, 201),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, 0, 201),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, 202, SL_MAX_VERSION),
SLE_CONDNULL( 3, 0, 60), ///< used to be industry's accepts_cargo
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, 78, SL_MAX_VERSION),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, 78, 201),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, 202, SL_MAX_VERSION),
SLE_VAR(Industry, prod_level, SLE_UINT8),
SLE_ARR(Industry, this_month_production, SLE_UINT16, 2),
SLE_ARR(Industry, this_month_transported, SLE_UINT16, 2),
SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8, 2),
SLE_ARR(Industry, last_month_production, SLE_UINT16, 2),
SLE_ARR(Industry, last_month_transported, SLE_UINT16, 2),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 2, 0, 201),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 2, 0, 201),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, 0, 201),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 2, 0, 201),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 16, 202, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 2, 0, 201),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 16, 202, SL_MAX_VERSION),

SLE_VAR(Industry, counter, SLE_UINT16),

@@ -51,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),
@@ -269,8 +269,9 @@
* 199
* 200 #6805 Extend railtypes to 64, adding uint16 to map array.
* 201 #6885 Extend NewGRF persistant storages.
* 202 #6867 Increase industry cargo slots to 16 in, 16 out
*/
extern const uint16 SAVEGAME_VERSION = 201; ///< Current savegame version of OpenTTD.
extern const uint16 SAVEGAME_VERSION = 202; ///< Current savegame version of OpenTTD.

SavegameType _savegame_type; ///< type of savegame we are loading
FileToSaveLoad _file_to_saveload; ///< File to save or load in the openttd loop.
@@ -383,15 +383,21 @@ bool FindSubsidyIndustryCargoRoute()
CargoID cid;

/* Randomize cargo type */
if (src_ind->produced_cargo[1] != CT_INVALID && HasBit(Random(), 0)) {
cid = src_ind->produced_cargo[1];
trans = src_ind->last_month_pct_transported[1];
total = src_ind->last_month_production[1];
} else {
cid = src_ind->produced_cargo[0];
trans = src_ind->last_month_pct_transported[0];
total = src_ind->last_month_production[0];
int num_cargos = 0;
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++;

This comment has been minimized.

@nielsmh

nielsmh Oct 7, 2018
Author Contributor

Why such a weird algorithm to select a random cargo type. Could as well add valid types to a std::vector and select an element from that.

}
if (num_cargos == 0) return false; // industry produces nothing
int cargo_num = RandomRange(num_cargos) + 1;
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) {

This comment has been minimized.

@nielsmh

nielsmh Jul 25, 2018
Author Contributor

This algorithm feels overly complicated. Does it seem right?

This comment has been minimized.

@frosch123

frosch123 Jul 25, 2018
Member

"ci" and "cargo_index" for the same thing is a bit weird.
But otherwise I see nothing wrong.

This comment has been minimized.

@frosch123

frosch123 Jul 27, 2018
Member

warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

if (src_ind->produced_cargo[cargo_index] != CT_INVALID) cargo_num--;
if (cargo_num == 0) break;
}
assert(cargo_num == 0); // indicates loop didn't break as intended
cid = src_ind->produced_cargo[cargo_index];
trans = src_ind->last_month_pct_transported[cargo_index];
total = src_ind->last_month_production[cargo_index];

/* Quit if no production in this industry
* or if the pct transported is already large enough
@@ -435,14 +441,11 @@ bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src)
case ST_INDUSTRY: {
/* Select a random industry. */
const Industry *dst_ind = Industry::GetRandom();
if (dst_ind == NULL) return false;

/* The industry must accept the cargo */
if (dst_ind == NULL ||
(cid != dst_ind->accepts_cargo[0] &&
cid != dst_ind->accepts_cargo[1] &&
cid != dst_ind->accepts_cargo[2])) {
return false;
}
bool valid = std::find(dst_ind->accepts_cargo, endof(dst_ind->accepts_cargo), cid) != endof(dst_ind->accepts_cargo);
if (!valid) return false;

dst = dst_ind->index;
break;
@@ -1195,8 +1195,12 @@ enum IndustryTypes {

#define MI(tbl, sndc, snd, d, pc, ai1, ai2, ai3, ai4, ag1, ag2, ag3, ag4, col, \
c1, c2, c3, proc, p1, r1, p2, r2, m, a1, im1, a2, im2, a3, im3, pr, clim, bev, in, intx, s1, s2, s3) \
{tbl, lengthof(tbl), d, 0, pc, {c1, c2, c3}, proc, {p1, p2}, {r1, r2}, m, \
{a1, a2, a3}, {{im1, 0}, {im2, 0}, {im3, 0}}, pr, clim, bev, col, in, intx, s1, s2, s3, STR_UNDEFINED, {ai1, ai2, ai3, ai4}, {ag1, ag2, ag3, ag4}, \
{tbl, lengthof(tbl), d, 0, pc, {c1, c2, c3}, proc, \
{p1, p2, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID}, \
{r1, r2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, m, \
{a1, a2, a3, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID}, \
{{im1, 0}, {im2, 0}, {im3, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, \
pr, clim, bev, col, in, intx, s1, s2, s3, STR_UNDEFINED, {ai1, ai2, ai3, ai4}, {ag1, ag2, ag3, ag4}, \
This conversation was marked as resolved by nielsmh

This comment has been minimized.

@nielsmh

nielsmh Oct 7, 2018
Author Contributor

This is ugly, can it be formatted in a nicer way?

This comment has been minimized.

@LordAro

LordAro Oct 7, 2018
Member

The old table wasn't great either, tbh. It's only the define, it doesn't matter too much

sndc, snd, 0, 0, true, GRFFileProps(INVALID_INDUSTRYTYPE)}
/* Format:
tile table count and sounds table
@@ -1594,7 +1598,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = {
* @param a2 next frame of animation
* @param a3 chooses between animation or construction state
*/
#define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, {0, ANIM_STATUS_NO_ANIMATION, 2, 0}, INDTILE_SPECIAL_NONE, true, GRFFileProps(INVALID_INDUSTRYTILE)}
#define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID, CT_INVALID}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, {0, ANIM_STATUS_NO_ANIMATION, 2, 0}, INDTILE_SPECIAL_NONE, true, GRFFileProps(INVALID_INDUSTRYTILE)}
static const IndustryTileSpec _origin_industry_tile_specs[NEW_INDUSTRYTILEOFFSET] = {
/* Coal Mine */
MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false),
@@ -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()
};