| @@ -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
frosch123
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
frosch123
The comments here are misleading. |
||
| /* 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)) { | ||
| @@ -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++; | ||
nielsmh
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++) { | ||
nielsmh
This algorithm feels overly complicated. Does it seem right? |
||
| 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
nielsmh
This is ugly, can it be formatted in a nicer way? |
||
| 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), | ||
nielsmhOct 7, 2018
Author
Contributor
Re-indent remaining comments in block here to match the accepts_cargo comment indent level?