Skip to content

Commit

Permalink
Feature: NewGRF support for 16-in-16-out industries per frosch' sugge…
Browse files Browse the repository at this point in the history
…stion, except var 6E
  • Loading branch information
nielsmh committed Jul 26, 2018
1 parent d334cc6 commit 66abd5c
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 34 deletions.
17 changes: 17 additions & 0 deletions src/industry.h
Expand Up @@ -12,6 +12,7 @@
#ifndef INDUSTRY_H
#define INDUSTRY_H

#include <algorithm>
#include "newgrf_storage.h"
#include "subsidy_type.h"
#include "industry_map.h"
Expand Down Expand Up @@ -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
Expand Down
22 changes: 20 additions & 2 deletions src/industry_cmd.cpp
Expand Up @@ -1725,28 +1725,46 @@ 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 = 3;
if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) maxcargoes = lengthof(i->accepts_cargo);
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);
if (std::find(indspec->accepts_cargo, endof(indspec->accepts_cargo), i->accepts_cargo[j]) == 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 (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 = 2;
if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) maxcargoes = lengthof(i->produced_cargo);
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);
if (std::find(indspec->produced_cargo, endof(indspec->produced_cargo), i->produced_cargo[j]) == endof(indspec->produced_cargo)) {
/* Cargo not in spec, error in NewGRF */
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
break;
}
}
}

Expand Down
47 changes: 34 additions & 13 deletions src/industry_gui.cpp
Expand Up @@ -136,7 +136,7 @@ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind,

/**
* 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 True if working on input cargoes, false if working on output 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
Expand All @@ -145,14 +145,35 @@ 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(bool 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 ? 0 : 1);
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;
}
if (use_input) {
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[0]);
if (cargoes[2] != CT_INVALID) GetCargoSuffix(2, cst, ind, ind_type, indspec, suffixes[0]);
} else {
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[0]);
}
}
}
Expand Down Expand Up @@ -359,7 +380,7 @@ class BuildIndustryWindow : public Window {
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(true, 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);
Expand All @@ -373,7 +394,7 @@ class BuildIndustryWindow : public Window {
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(false, 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);
Expand Down Expand Up @@ -478,7 +499,7 @@ class BuildIndustryWindow : public Window {

/* 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(true, 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);
Expand All @@ -493,7 +514,7 @@ class BuildIndustryWindow : public Window {
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(false, 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);
Expand Down Expand Up @@ -772,7 +793,7 @@ class IndustryViewWindow : public Window
}

CargoSuffix cargo_suffix[lengthof(i->accepts_cargo)];
GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix);
GetAllCargoSuffixes(true, 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.
Expand Down Expand Up @@ -811,7 +832,7 @@ class IndustryViewWindow : public Window
y += FONT_HEIGHT_NORMAL;
}

GetAllCargoSuffixes(3, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix);
GetAllCargoSuffixes(false, 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;
Expand Down Expand Up @@ -1263,7 +1284,7 @@ class IndustryDirectoryWindow : public Window {
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(false, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix);

/* Industry productions */
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
Expand Down
4 changes: 4 additions & 0 deletions src/industry_type.h
Expand Up @@ -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 */
4 changes: 1 addition & 3 deletions src/industrytype.h
Expand Up @@ -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)

Expand All @@ -95,9 +96,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.
*/
Expand Down
66 changes: 64 additions & 2 deletions src/newgrf.cpp
Expand Up @@ -4843,7 +4843,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;
}
Expand All @@ -4853,21 +4853,48 @@ 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)) {
grfmsg(1, "NewSpriteGroup: Industry production wants more inputs than possible, given=%d, max=%d, skipping", group->num_input, lengthof(group->subtract_input));
break;
}
for (uint i = 0; i < group->num_input; i++) {
/* XXX: maybe check for same cargo id used multiple times and warn/error? */
group->cargo_input[i] = buf->ReadByte();
group->subtract_input[i] = buf->ReadByte();
}
group->num_output = buf->ReadByte();
if (group->num_output > lengthof(group->add_output)) {
grfmsg(1, "NewSpriteGroup: Industry production wants more outputs than possible, given=%d, max=%d, skipping", group->num_output, lengthof(group->add_output));
break;
}
for (uint i = 0; i < group->num_output; i++) {
group->cargo_output[i] = buf->ReadByte();
group->add_output[i] = buf->ReadByte();
}
group->again = buf->ReadByte();
} else {
NOT_REACHED();
}
break;
}
Expand Down Expand Up @@ -8667,6 +8694,41 @@ static void FinaliseIndustriesArray()

_industry_mngr.SetEntitySpec(indsp);
_loaded_newgrf_features.has_newindustries = true;

IndustryType type = _industry_mngr.GetID(indsp->grf_prop.local_id, indsp->grf_prop.grffile->grfid);

/* Query actual input cargo types via CB */
if (HasBit(indsp->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
for (uint j = 0; j < lengthof(indsp->accepts_cargo); j++) indsp->accepts_cargo[j] = CT_INVALID;
uint maxcargoes = 3;
if (indsp->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) maxcargoes = lengthof(indsp->accepts_cargo);
for (uint j = 0; j < maxcargoes; j++) {
uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, NULL, type, INVALID_TILE);
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
if (indsp->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
break;
}
indsp->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indsp->grf_prop.grffile);
}
}

/* Query actual output cargo types via CB */
if (HasBit(indsp->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
for (uint j = 0; j < lengthof(indsp->produced_cargo); j++) indsp->produced_cargo[j] = CT_INVALID;
uint maxcargoes = 2;
if (indsp->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) maxcargoes = lengthof(indsp->produced_cargo);
for (uint j = 0; j < maxcargoes; j++) {
uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, NULL, type, INVALID_TILE);
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
if (indsp->grf_prop.grffile->grf_version >= 8 && res >= 0x100) {
ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
break;
}
indsp->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indsp->grf_prop.grffile);
}
}

}
}
}
Expand Down
50 changes: 38 additions & 12 deletions src/newgrf_industries.cpp
Expand Up @@ -304,6 +304,22 @@ 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) break; // 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();
}

/* Get a variable from the persistent storage */
case 0x7C: return (this->industry->psa != NULL) ? this->industry->psa->GetValue(parameter) : 0;

Expand Down Expand Up @@ -575,13 +591,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) {
/* Old style 3-in-2-out cargo handling */
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);
}
} else {
/* Lists of cargo ids */
for (uint i = 0; i < group->num_input; i++) {
int cargo_index = ind->GetCargoAcceptedIndex(GetCargoTranslation(group->cargo_input[i], spec->grf_prop.grffile));
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(GetCargoTranslation(group->cargo_output[i], spec->grf_prop.grffile));
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);
Expand All @@ -602,12 +633,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)) {
Expand Down

0 comments on commit 66abd5c

Please sign in to comment.