OpenTTD Source 20241224-master-gf74b0cf984
newgrf_industries.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "debug.h"
12#include "industry.h"
13#include "newgrf_industries.h"
14#include "newgrf_town.h"
15#include "newgrf_cargo.h"
16#include "window_func.h"
17#include "town.h"
18#include "company_base.h"
19#include "error.h"
20#include "strings_func.h"
21#include "core/random_func.hpp"
23
24#include "table/strings.h"
25
26#include "safeguards.h"
27
28/* Since the industry IDs defined by the GRF file don't necessarily correlate
29 * to those used by the game, the IDs used for overriding old industries must be
30 * translated when the idustry spec is set. */
33
40IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32_t grf_id)
41{
42 if (grf_type == IT_INVALID) return IT_INVALID;
43 if (!HasBit(grf_type, 7)) return GB(grf_type, 0, 7);
44
45 return _industry_mngr.GetID(GB(grf_type, 0, 7), grf_id);
46}
47
56uint32_t GetIndustryIDAtOffset(TileIndex tile, const Industry *i, uint32_t cur_grfid)
57{
58 if (!i->TileBelongsToIndustry(tile)) {
59 /* No industry and/or the tile does not have the same industry as the one we match it with */
60 return 0xFFFF;
61 }
62
63 IndustryGfx gfx = GetCleanIndustryGfx(tile);
64 const IndustryTileSpec *indtsp = GetIndustryTileSpec(gfx);
65
66 if (gfx < NEW_INDUSTRYTILEOFFSET) { // Does it belongs to an old type?
67 /* It is an old tile. We have to see if it's been overridden */
68 if (indtsp->grf_prop.override == INVALID_INDUSTRYTILE) { // has it been overridden?
69 return 0xFF << 8 | gfx; // no. Tag FF + the gfx id of that tile
70 }
71 /* Overridden */
72 const IndustryTileSpec *tile_ovr = GetIndustryTileSpec(indtsp->grf_prop.override);
73
74 if (tile_ovr->grf_prop.grfid == cur_grfid) {
75 return tile_ovr->grf_prop.local_id; // same grf file
76 } else {
77 return 0xFFFE; // not the same grf file
78 }
79 }
80 /* Not an 'old type' tile */
81 if (indtsp->grf_prop.spritegroup[0] != nullptr) { // tile has a spritegroup ?
82 if (indtsp->grf_prop.grfid == cur_grfid) { // same industry, same grf ?
83 return indtsp->grf_prop.local_id;
84 } else {
85 return 0xFFFE; // Defined in another grf file
86 }
87 }
88 /* The tile has no spritegroup */
89 return 0xFF << 8 | indtsp->grf_prop.subst_id; // so just give it the substitute
90}
91
92static uint32_t GetClosestIndustry(TileIndex tile, IndustryType type, const Industry *current)
93{
94 uint32_t best_dist = UINT32_MAX;
95
96 for (const IndustryID &industry : Industry::industries[type]) {
97 if (industry == current->index) continue;
98
99 best_dist = std::min(best_dist, DistanceManhattan(tile, Industry::Get(industry)->location.tile));
100 }
101
102 return best_dist;
103}
104
115static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_setID, uint8_t layout_filter, bool town_filter, const Industry *current)
116{
117 uint32_t GrfID = GetRegister(0x100);
118 IndustryType ind_index;
119 uint32_t closest_dist = UINT32_MAX;
120 uint8_t count = 0;
121
122 /* Determine what will be the industry type to look for */
123 switch (GrfID) {
124 case 0: // this is a default industry type
125 ind_index = param_setID;
126 break;
127
128 case 0xFFFFFFFF: // current grf
129 GrfID = GetIndustrySpec(current->type)->grf_prop.grfid;
130 [[fallthrough]];
131
132 default: // use the grfid specified in register 100h
133 SetBit(param_setID, 7); // bit 7 means it is not an old type
134 ind_index = MapNewGRFIndustryType(param_setID, GrfID);
135 break;
136 }
137
138 /* If the industry type is invalid, there is none and the closest is far away. */
139 if (ind_index >= NUM_INDUSTRYTYPES) return 0 | 0xFFFF;
140
141 if (layout_filter == 0 && !town_filter) {
142 /* If the filter is 0, it could be because none was specified as well as being really a 0.
143 * In either case, just do the regular var67 */
144 closest_dist = GetClosestIndustry(current->location.tile, ind_index, current);
145 count = ClampTo<uint8_t>(Industry::GetIndustryTypeCount(ind_index));
146 } else {
147 /* Count only those who match the same industry type and layout filter
148 * Unfortunately, we have to do it manually */
149 for (const IndustryID &industry : Industry::industries[ind_index]) {
150 if (industry == current->index) continue;
151
152 const Industry *i = Industry::Get(industry);
153 if ((layout_filter == 0 || i->selected_layout == layout_filter) && (!town_filter || i->town == current->town)) {
154 closest_dist = std::min(closest_dist, DistanceManhattan(current->location.tile, i->location.tile));
155 count++;
156 }
157 }
158 }
159
160 return count << 16 | GB(closest_dist, 0, 16);
161}
162
163/* virtual */ uint32_t IndustriesScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
164{
165 if (this->ro.callback == CBID_INDUSTRY_LOCATION) {
166 /* Variables available during construction check. */
167
168 switch (variable) {
169 case 0x80: return this->tile.base();
170 case 0x81: return GB(this->tile.base(), 8, 8);
171
172 /* Pointer to the town the industry is associated with */
173 case 0x82: return this->industry->town->index;
174 case 0x83:
175 case 0x84:
176 case 0x85: Debug(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported
177
178 /* Number of the layout */
179 case 0x86: return this->industry->selected_layout;
180
181 /* Ground type */
182 case 0x87: return GetTerrainType(this->tile);
183
184 /* Town zone */
185 case 0x88: return GetTownRadiusGroup(this->industry->town, this->tile);
186
187 /* Manhattan distance of the closest town */
188 case 0x89: return ClampTo<uint8_t>(DistanceManhattan(this->industry->town->xy, this->tile));
189
190 /* Lowest height of the tile */
191 case 0x8A: return ClampTo<uint8_t>(GetTileZ(this->tile) * (this->ro.grffile->grf_version >= 8 ? 1 : TILE_HEIGHT));
192
193 /* Distance to the nearest water/land tile */
194 case 0x8B: return GetClosestWaterDistance(this->tile, (GetIndustrySpec(this->industry->type)->behaviour & INDUSTRYBEH_BUILT_ONWATER) == 0);
195
196 /* Square of Euclidian distance from town */
197 case 0x8D: return ClampTo<uint16_t>(DistanceSquare(this->industry->town->xy, this->tile));
198
199 /* 32 random bits */
200 case 0x8F: return this->random_bits;
201 }
202 }
203
204 const IndustrySpec *indspec = GetIndustrySpec(this->type);
205
206 if (this->industry == nullptr) {
207 Debug(grf, 1, "Unhandled variable 0x{:X} (no available industry) in callback 0x{:x}", variable, this->ro.callback);
208
209 available = false;
210 return UINT_MAX;
211 }
212
213 switch (variable) {
214 case 0x40:
215 case 0x41:
216 case 0x42: { // waiting cargo, but only if those two callback flags are set
217 uint16_t callback = indspec->callback_mask;
219 if ((indspec->behaviour & INDUSTRYBEH_PROD_MULTI_HNDLING) != 0) {
220 if (this->industry->prod_level == 0) return 0;
221 return ClampTo<uint16_t>(this->industry->GetAccepted(variable - 0x40).waiting / this->industry->prod_level);
222 } else {
223 return ClampTo<uint16_t>(this->industry->GetAccepted(variable - 0x40).waiting);
224 }
225 } else {
226 return 0;
227 }
228 }
229
230 /* Manhattan distance of closes dry/water tile */
231 case 0x43:
232 if (this->tile == INVALID_TILE) break;
233 return GetClosestWaterDistance(this->tile, (indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) == 0);
234
235 /* Layout number */
236 case 0x44: return this->industry->selected_layout;
237
238 /* Company info */
239 case 0x45: {
240 uint8_t colours = 0;
241 bool is_ai = false;
242
243 const Company *c = Company::GetIfValid(this->industry->founder);
244 if (c != nullptr) {
245 const Livery *l = &c->livery[LS_DEFAULT];
246
247 is_ai = c->is_ai;
248 colours = l->colour1 + l->colour2 * 16;
249 }
250
251 return this->industry->founder | (is_ai ? 0x10000 : 0) | (colours << 24);
252 }
253
254 case 0x46: return this->industry->construction_date.base(); // Date when built - long format - (in days)
255
256 /* Override flags from GS */
257 case 0x47: return this->industry->ctlflags;
258
259 /* Get industry ID at offset param */
260 case 0x60: return GetIndustryIDAtOffset(GetNearbyTile(parameter, this->industry->location.tile, false), this->industry, this->ro.grffile->grfid);
261
262 /* Get random tile bits at offset param */
263 case 0x61: {
264 if (this->tile == INVALID_TILE) break;
265 TileIndex tile = GetNearbyTile(parameter, this->tile, false);
266 return this->industry->TileBelongsToIndustry(tile) ? GetIndustryRandomBits(tile) : 0;
267 }
268
269 /* Land info of nearby tiles */
270 case 0x62:
271 if (this->tile == INVALID_TILE) break;
272 return GetNearbyIndustryTileInformation(parameter, this->tile, INVALID_INDUSTRY, false, this->ro.grffile->grf_version >= 8);
273
274 /* Animation stage of nearby tiles */
275 case 0x63: {
276 if (this->tile == INVALID_TILE) break;
277 TileIndex tile = GetNearbyTile(parameter, this->tile, false);
278 if (this->industry->TileBelongsToIndustry(tile)) {
279 return GetAnimationFrame(tile);
280 }
281 return 0xFFFFFFFF;
282 }
283
284 /* Distance of nearest industry of given type */
285 case 0x64: {
286 if (this->tile == INVALID_TILE) break;
287 IndustryType type = MapNewGRFIndustryType(parameter, indspec->grf_prop.grfid);
288 if (type >= NUM_INDUSTRYTYPES) return UINT32_MAX;
289 return GetClosestIndustry(this->tile, type, this->industry);
290 }
291 /* Get town zone and Manhattan distance of closest town */
292 case 0x65: {
293 if (this->tile == INVALID_TILE) break;
294 TileIndex tile = GetNearbyTile(parameter, this->tile, true);
295 return GetTownRadiusGroup(this->industry->town, tile) << 16 | ClampTo<uint16_t>(DistanceManhattan(tile, this->industry->town->xy));
296 }
297 /* Get square of Euclidian distance of closest town */
298 case 0x66: {
299 if (this->tile == INVALID_TILE) break;
300 TileIndex tile = GetNearbyTile(parameter, this->tile, true);
301 return DistanceSquare(tile, this->industry->town->xy);
302 }
303
304 /* Count of industry, distance of closest instance
305 * 68 is the same as 67, but with a filtering on selected layout */
306 case 0x67:
307 case 0x68: {
308 uint8_t layout_filter = 0;
309 bool town_filter = false;
310 if (variable == 0x68) {
311 uint32_t reg = GetRegister(0x101);
312 layout_filter = GB(reg, 0, 8);
313 town_filter = HasBit(reg, 8);
314 }
315 return GetCountAndDistanceOfClosestInstance(parameter, layout_filter, town_filter, this->industry);
316 }
317
318 case 0x69:
319 case 0x6A:
320 case 0x6B:
321 case 0x6C:
322 case 0x6D:
323 case 0x70:
324 case 0x71: {
325 CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile);
326 if (!IsValidCargoID(cargo)) return 0;
327 auto it = this->industry->GetCargoProduced(cargo);
328 if (it == std::end(this->industry->produced)) return 0; // invalid cargo
329 switch (variable) {
330 case 0x69: return it->waiting;
331 case 0x6A: return it->history[THIS_MONTH].production;
332 case 0x6B: return it->history[THIS_MONTH].transported;
333 case 0x6C: return it->history[LAST_MONTH].production;
334 case 0x6D: return it->history[LAST_MONTH].transported;
335 case 0x70: return it->rate;
336 case 0x71: return it->history[LAST_MONTH].PctTransported();
337 default: NOT_REACHED();
338 }
339 }
340
341
342 case 0x6E:
343 case 0x6F: {
344 CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile);
345 if (!IsValidCargoID(cargo)) return 0;
346 auto it = this->industry->GetCargoAccepted(cargo);
347 if (it == std::end(this->industry->accepted)) return 0; // invalid cargo
348 if (variable == 0x6E) return it->last_accepted.base();
349 if (variable == 0x6F) return it->waiting;
350 NOT_REACHED();
351 }
352
353 /* Get a variable from the persistent storage */
354 case 0x7C: return (this->industry->psa != nullptr) ? this->industry->psa->GetValue(parameter) : 0;
355
356 /* Industry structure access*/
357 case 0x80: return this->industry->location.tile.base();
358 case 0x81: return GB(this->industry->location.tile.base(), 8, 8);
359 /* Pointer to the town the industry is associated with */
360 case 0x82: return this->industry->town->index;
361 case 0x83:
362 case 0x84:
363 case 0x85: Debug(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported
364 case 0x86: return this->industry->location.w;
365 case 0x87: return this->industry->location.h;// xy dimensions
366
367 case 0x88:
368 case 0x89: return this->industry->GetProduced(variable - 0x88).cargo;
369 case 0x8A: return this->industry->GetProduced(0).waiting;
370 case 0x8B: return GB(this->industry->GetProduced(0).waiting, 8, 8);
371 case 0x8C: return this->industry->GetProduced(1).waiting;
372 case 0x8D: return GB(this->industry->GetProduced(1).waiting, 8, 8);
373 case 0x8E:
374 case 0x8F: return this->industry->GetProduced(variable - 0x8E).rate;
375 case 0x90:
376 case 0x91:
377 case 0x92: return this->industry->GetAccepted(variable - 0x90).cargo;
378 case 0x93: return this->industry->prod_level;
379 /* amount of cargo produced so far THIS month. */
380 case 0x94: return this->industry->GetProduced(0).history[THIS_MONTH].production;
381 case 0x95: return GB(this->industry->GetProduced(0).history[THIS_MONTH].production, 8, 8);
382 case 0x96: return this->industry->GetProduced(1).history[THIS_MONTH].production;
383 case 0x97: return GB(this->industry->GetProduced(1).history[THIS_MONTH].production, 8, 8);
384 /* amount of cargo transported so far THIS month. */
385 case 0x98: return this->industry->GetProduced(0).history[THIS_MONTH].transported;
386 case 0x99: return GB(this->industry->GetProduced(0).history[THIS_MONTH].transported, 8, 8);
387 case 0x9A: return this->industry->GetProduced(1).history[THIS_MONTH].transported;
388 case 0x9B: return GB(this->industry->GetProduced(1).history[THIS_MONTH].transported, 8, 8);
389 /* fraction of cargo transported LAST month. */
390 case 0x9C:
391 case 0x9D: return this->industry->GetProduced(variable - 0x9C).history[LAST_MONTH].PctTransported();
392 /* amount of cargo produced LAST month. */
393 case 0x9E: return this->industry->GetProduced(0).history[LAST_MONTH].production;
394 case 0x9F: return GB(this->industry->GetProduced(0).history[LAST_MONTH].production, 8, 8);
395 case 0xA0: return this->industry->GetProduced(1).history[LAST_MONTH].production;
396 case 0xA1: return GB(this->industry->GetProduced(1).history[LAST_MONTH].production, 8, 8);
397 /* amount of cargo transported last month. */
398 case 0xA2: return this->industry->GetProduced(0).history[LAST_MONTH].transported;
399 case 0xA3: return GB(this->industry->GetProduced(0).history[LAST_MONTH].transported, 8, 8);
400 case 0xA4: return this->industry->GetProduced(1).history[LAST_MONTH].transported;
401 case 0xA5: return GB(this->industry->GetProduced(1).history[LAST_MONTH].transported, 8, 8);
402
403 case 0xA6: return indspec->grf_prop.local_id;
404 case 0xA7: return this->industry->founder;
405 case 0xA8: return this->industry->random_colour;
406 case 0xA9: return ClampTo<uint8_t>(this->industry->last_prod_year - EconomyTime::ORIGINAL_BASE_YEAR);
407 case 0xAA: return this->industry->counter;
408 case 0xAB: return GB(this->industry->counter, 8, 8);
409 case 0xAC: return this->industry->was_cargo_delivered;
410
411 case 0xB0: return ClampTo<uint16_t>(this->industry->construction_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date when built since 1920 (in days)
412 case 0xB3: return this->industry->construction_type; // Construction type
413 case 0xB4: {
414 if (this->industry->accepted.empty()) return 0;
415 auto it = std::max_element(std::begin(this->industry->accepted), std::end(this->industry->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; });
416 return ClampTo<uint16_t>(it->last_accepted - EconomyTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
417 }
418 }
419
420 Debug(grf, 1, "Unhandled industry variable 0x{:X}", variable);
421
422 available = false;
423 return UINT_MAX;
424}
425
426/* virtual */ uint32_t IndustriesScopeResolver::GetRandomBits() const
427{
428 return this->industry != nullptr ? this->industry->random : 0;
429}
430
431/* virtual */ uint32_t IndustriesScopeResolver::GetTriggers() const
432{
433 return 0;
434}
435
436/* virtual */ void IndustriesScopeResolver::StorePSA(uint pos, int32_t value)
437{
438 if (this->industry->index == INVALID_INDUSTRY) return;
439
440 if (this->industry->psa == nullptr) {
441 /* There is no need to create a storage if the value is zero. */
442 if (value == 0) return;
443
444 /* Create storage on first modification. */
445 const IndustrySpec *indsp = GetIndustrySpec(this->industry->type);
447 this->industry->psa = new PersistentStorage(indsp->grf_prop.grfid, GSF_INDUSTRIES, this->industry->location.tile);
448 }
449
450 this->industry->psa->StoreValue(pos, value);
451}
452
458static const GRFFile *GetGrffile(IndustryType type)
459{
460 const IndustrySpec *indspec = GetIndustrySpec(type);
461 return (indspec != nullptr) ? indspec->grf_prop.grffile : nullptr;
462}
463
474IndustriesResolverObject::IndustriesResolverObject(TileIndex tile, Industry *indus, IndustryType type, uint32_t random_bits,
475 CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
476 : ResolverObject(GetGrffile(type), callback, callback_param1, callback_param2),
477 industries_scope(*this, tile, indus, type, random_bits)
478{
480}
481
487{
488 if (!this->town_scope.has_value()) {
489 Town *t = nullptr;
490 bool readonly = true;
491 if (this->industries_scope.industry != nullptr) {
492 t = this->industries_scope.industry->town;
493 readonly = this->industries_scope.industry->index == INVALID_INDUSTRY;
494 } else if (this->industries_scope.tile != INVALID_TILE) {
495 t = ClosestTownFromTile(this->industries_scope.tile, UINT_MAX);
496 }
497 if (t == nullptr) return nullptr;
498 this->town_scope.emplace(*this, t, readonly);
499 }
500 return &*this->town_scope;
501}
502
504{
505 return GSF_INDUSTRIES;
506}
507
512
523uint16_t GetIndustryCallback(CallbackID callback, uint32_t param1, uint32_t param2, Industry *industry, IndustryType type, TileIndex tile)
524{
525 IndustriesResolverObject object(tile, industry, type, 0, callback, param1, param2);
526 return object.ResolveCallback();
527}
528
540CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, size_t layout, uint32_t seed, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type)
541{
542 const IndustrySpec *indspec = GetIndustrySpec(type);
543
544 Industry ind;
545 ind.index = INVALID_INDUSTRY;
546 ind.location.tile = tile;
547 ind.location.w = 0; // important to mark the industry invalid
548 ind.type = type;
549 ind.selected_layout = (uint8_t)layout;
550 ind.town = ClosestTownFromTile(tile, UINT_MAX);
551 ind.random = initial_random_bits;
552 ind.founder = founder;
553 ind.psa = nullptr;
554
555 IndustriesResolverObject object(tile, &ind, type, seed, CBID_INDUSTRY_LOCATION, 0, creation_type);
556 uint16_t result = object.ResolveCallback();
557
558 /* Unlike the "normal" cases, not having a valid result means we allow
559 * the building of the industry, as that's how it's done in TTDP. */
560 if (result == CALLBACK_FAILED) return CommandCost();
561
562 return GetErrorMessageFromLocationCallbackResult(result, indspec->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE);
563}
564
571uint32_t GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32_t default_prob)
572{
573 const IndustrySpec *indspec = GetIndustrySpec(type);
574
576 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_PROBABILITY, 0, creation_type, nullptr, type, INVALID_TILE);
577 if (res != CALLBACK_FAILED) {
578 if (indspec->grf_prop.grffile->grf_version < 8) {
579 /* Disallow if result != 0 */
580 if (res != 0) default_prob = 0;
581 } else {
582 /* Use returned probability. 0x100 to use default */
583 if (res < 0x100) {
584 default_prob = res;
585 } else if (res > 0x100) {
587 }
588 }
589 }
590 }
591 return default_prob;
592}
593
594static int32_t DerefIndProd(int field, bool use_register)
595{
596 return use_register ? (int32_t)GetRegister(field) : field;
597}
598
605{
606 const IndustrySpec *spec = GetIndustrySpec(ind->type);
607 IndustriesResolverObject object(ind->location.tile, ind, ind->type);
608 if ((spec->behaviour & INDUSTRYBEH_PRODCALLBACK_RANDOM) != 0) object.callback_param1 = Random();
609 int multiplier = 1;
610 if ((spec->behaviour & INDUSTRYBEH_PROD_MULTI_HNDLING) != 0) multiplier = ind->prod_level;
611 object.callback_param2 = reason;
612
613 for (uint loop = 0;; loop++) {
614 /* limit the number of calls to break infinite loops.
615 * 'loop' is provided as 16 bits to the newgrf, so abort when those are exceeded. */
616 if (loop >= 0x10000) {
617 /* display error message */
618 SetDParamStr(0, spec->grf_prop.grffile->filename);
619 SetDParam(1, spec->name);
620 ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK, WL_WARNING);
621
622 /* abort the function early, this error isn't critical and will allow the game to continue to run */
623 break;
624 }
625
626 SB(object.callback_param2, 8, 16, loop);
627 const SpriteGroup *tgroup = object.Resolve();
628 if (tgroup == nullptr || tgroup->type != SGT_INDUSTRY_PRODUCTION) break;
630
631 if (group->version == 0xFF) {
632 /* Result was marked invalid on load, display error message */
633 SetDParamStr(0, spec->grf_prop.grffile->filename);
634 SetDParam(1, spec->name);
635 SetDParam(2, ind->location.tile);
636 ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK, WL_WARNING);
637
638 /* abort the function early, this error isn't critical and will allow the game to continue to run */
639 break;
640 }
641
642 bool deref = (group->version >= 1);
643
644 if (group->version < 2) {
645 /* Callback parameters map directly to industry cargo slot indices */
646 for (uint i = 0; i < group->num_input && i < ind->accepted.size(); i++) {
647 if (!IsValidCargoID(ind->accepted[i].cargo)) continue;
648 ind->accepted[i].waiting = ClampTo<uint16_t>(ind->accepted[i].waiting - DerefIndProd(group->subtract_input[i], deref) * multiplier);
649 }
650 for (uint i = 0; i < group->num_output && i < ind->produced.size(); i++) {
651 if (!IsValidCargoID(ind->produced[i].cargo)) continue;
652 ind->produced[i].waiting = ClampTo<uint16_t>(ind->produced[i].waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier);
653 }
654 } else {
655 /* Callback receives list of cargos to apply for, which need to have their cargo slots in industry looked up */
656 for (uint i = 0; i < group->num_input; i++) {
657 auto it = ind->GetCargoAccepted(group->cargo_input[i]);
658 if (it == std::end(ind->accepted)) continue;
659 it->waiting = ClampTo<uint16_t>(it->waiting - DerefIndProd(group->subtract_input[i], deref) * multiplier);
660 }
661 for (uint i = 0; i < group->num_output; i++) {
662 auto it = ind->GetCargoProduced(group->cargo_output[i]);
663 if (it == std::end(ind->produced)) continue;
664 it->waiting = ClampTo<uint16_t>(it->waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier);
665 }
666 }
667
668 int32_t again = DerefIndProd(group->again, deref);
669 if (again == 0) break;
670
671 SB(object.callback_param2, 24, 8, again);
672 }
673
675}
676
685{
686 assert(ind->IsCargoAccepted(cargo_type));
687
688 const IndustrySpec *indspec = GetIndustrySpec(ind->type);
691 0, indspec->grf_prop.grffile->cargo_map[cargo_type],
692 ind, ind->type, ind->location.tile);
694 }
695 return false;
696}
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SB(T &x, const uint8_t s, const uint8_t n, const U d)
Set n bits in x starting at bit s to d.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:107
Common return value for all commands.
uint16_t GetID(uint16_t grf_local_id, uint32_t grfid) const override
Return the ID (if ever available) of a previously inserted entity.
static constexpr TimerGame< struct Economy >::Year ORIGINAL_BASE_YEAR
The minimum starting year/base year of the original TTD.
static constexpr TimerGame< struct Calendar >::Date DAYS_TILL_ORIGINAL_BASE_YEAR
The date of the first day of the original base year.
Definition of stuff that is very close to a company, like the company struct itself.
Owner
Enum for all companies/owners.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
@ WL_WARNING
Other information.
Definition error.h:25
Base of all industries.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
const IndustryTileSpec * GetIndustryTileSpec(IndustryGfx gfx)
Accessor for array _industry_tile_specs.
IndustryGfx GetCleanIndustryGfx(Tile t)
Get the industry graphics ID for the given industry tile as stored in the without translation.
uint8_t GetIndustryRandomBits(Tile tile)
Get the random bits for this tile.
static const IndustryGfx NEW_INDUSTRYTILEOFFSET
original number of tiles
static const IndustryType NEW_INDUSTRYOFFSET
original number of industry types
static const IndustryType NUM_INDUSTRYTYPES
total number of industry types, new and old; limited to 240 because we need some special ids like INV...
static const IndustryType INVALID_INDUSTRYTYPE
one above amount is considered invalid
static const IndustryGfx INVALID_INDUSTRYTILE
one above amount is considered invalid
static const IndustryGfx NUM_INDUSTRYTILES
total number of industry tiles, new and old
@ INDUSTRYBEH_PROD_MULTI_HNDLING
Automatic production multiplier handling.
@ INDUSTRYBEH_PRODCALLBACK_RANDOM
Production callback needs random bits in var 10.
@ INDUSTRYBEH_BUILT_ONWATER
is built on water (oil rig)
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:163
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:146
uint GetClosestWaterDistance(TileIndex tile, bool water)
Finds the distance for the closest tile with water/land given a tile.
Definition map.cpp:329
GrfSpecFeature
Definition newgrf.h:67
@ CBM_IND_PROBABILITY
industry availability/probability callback
@ CBM_IND_REFUSE_CARGO
option out of accepting cargo
@ CBM_IND_PRODUCTION_CARGO_ARRIVAL
call production callback when cargo arrives at the industry
@ CBM_IND_PRODUCTION_256_TICKS
call production callback every 256 ticks
CallbackID
List of implemented NewGRF callbacks.
@ CBID_INDUSTRY_PROBABILITY
Called to determine if the given industry type is available.
@ CBID_INDUSTRY_REFUSE_CARGO
Called to determine if the industry can still accept or refuse more cargo arrival.
@ CBID_INDUSTRY_LOCATION
Called to determine if the given industry can be built on specific area.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoID.
Cargo support for NewGRFs.
CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, const GRFFile *grffile, StringID default_error)
Get the error message from a shape/location/slope check callback result.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
bool ConvertBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
uint32_t GetTerrainType(TileIndex tile, TileContext context)
Function used by houses (and soon industries) to get information on type of "terrain" the tile it is ...
TileIndex GetNearbyTile(uint8_t parameter, TileIndex tile, bool signed_offsets, Axis axis)
Get the tile at the given offset.
uint32_t GetIndustryIDAtOffset(TileIndex tile, const Industry *i, uint32_t cur_grfid)
Make an analysis of a tile and check for its belonging to the same industry, and/or the same grf file...
IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32_t grf_id)
Map the GRF local type to an industry type.
static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_setID, uint8_t layout_filter, bool town_filter, const Industry *current)
Implementation of both var 67 and 68 since the mechanism is almost the same, it is easier to regroup ...
CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, size_t layout, uint32_t seed, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type)
Check that the industry callback allows creation of the industry.
bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type)
Check whether an industry temporarily refuses to accept a certain cargo.
void IndustryProductionCallback(Industry *ind, int reason)
Get the industry production callback and apply it to the industry.
uint32_t GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32_t default_prob)
Check with callback CBID_INDUSTRY_PROBABILITY whether the industry can be built.
uint16_t GetIndustryCallback(CallbackID callback, uint32_t param1, uint32_t param2, Industry *industry, IndustryType type, TileIndex tile)
Perform an industry callback.
static const GRFFile * GetGrffile(IndustryType type)
Get the grf file associated with the given industry type.
Functions for NewGRF industries.
uint32_t GetIndustryIDAtOffset(TileIndex new_tile, const Industry *i, uint32_t cur_grfid)
Make an analysis of a tile and check for its belonging to the same industry, and/or the same grf file...
IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32_t grf_id)
Map the GRF local type to an industry type.
IndustryAvailabilityCallType
From where has callback CBID_INDUSTRY_PROBABILITY been called.
uint32_t GetNearbyIndustryTileInformation(uint8_t parameter, TileIndex tile, IndustryID index, bool signed_offsets, bool grf_version8)
Based on newhouses equivalent, but adapted for newindustries.
uint32_t GetRegister(uint i)
Gets the value of a so-called newgrf "register".
Functions to handle the town part of NewGRF towns.
Pseudo random number generator.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition strings.cpp:371
Functions related to OTTD's strings.
bool is_ai
If true, the company is (also) controlled by the computer (a NoAI program).
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
const struct GRFFile * grffile
grf file that introduced this entity
std::array< const struct SpriteGroup *, Tcnt > spritegroup
pointers to the different sprites of the entity
uint16_t override
id of the entity been replaced by
Dynamic data of a loaded NewGRF.
Definition newgrf.h:108
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoID -> local ID)
Definition newgrf.h:130
Resolver for industries.
IndustriesResolverObject(TileIndex tile, Industry *indus, IndustryType type, uint32_t random_bits=0, CallbackID callback=CBID_NO_CALLBACK, uint32_t callback_param1=0, uint32_t callback_param2=0)
Constructor of the industries resolver.
std::optional< TownScopeResolver > town_scope
Scope resolver for the associated town (if needed and available, else std::nullopt).
TownScopeResolver * GetTown()
Get or create the town scope object associated with the industry.
GrfSpecFeature GetFeature() const override
Get the feature number being resolved for.
uint32_t GetDebugID() const override
Get an identifier for the item being resolved.
IndustriesScopeResolver industries_scope
Scope resolver for the industry.
uint32_t GetTriggers() const override
Get the triggers.
IndustryType type
Type of the industry.
uint32_t random_bits
Random bits of the new industry.
uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const override
Get a variable value.
uint32_t GetRandomBits() const override
Get a few random bits.
void StorePSA(uint pos, int32_t value) override
Store a value into the persistent storage area (PSA).
TileIndex tile
Tile owned by the industry.
Industry * industry
Industry being resolved.
uint16_t add_output[INDUSTRY_NUM_OUTPUTS]
Add this much output cargo when successful (unsigned, is indirect in cb version 1+)
CargoID cargo_input[INDUSTRY_NUM_INPUTS]
Which input cargoes to take from (only cb version 2)
uint8_t num_input
How many subtract_input values are valid.
int16_t subtract_input[INDUSTRY_NUM_INPUTS]
Take this much of the input cargo (can be negative, is indirect in cb version 1+)
uint8_t version
Production callback version used, or 0xFF if marked invalid.
uint8_t num_output
How many add_output values are valid.
CargoID cargo_output[INDUSTRY_NUM_OUTPUTS]
Which output cargoes to add to (only cb version 2)
Defines the data structure for constructing industry.
uint16_t callback_mask
Bitmask of industry callbacks that have to be called.
StringID name
Displayed name of the industry.
IndustryBehaviour behaviour
How this industry will behave, and how others entities can use it.
GRFFileProps grf_prop
properties related to the grf file
Defines the data structure of each individual tile of an industry.
GRFFileProps grf_prop
properties related to the grf file
uint16_t waiting
Amount of cargo waiting to processed.
Definition industry.h:87
CargoID cargo
Cargo type.
Definition industry.h:86
CargoID cargo
Cargo type.
Definition industry.h:79
uint16_t waiting
Amount of cargo produced.
Definition industry.h:80
std::array< ProducedHistory, 25 > history
History of cargo produced and transported for this month and 24 previous months.
Definition industry.h:82
uint8_t rate
Production rate.
Definition industry.h:81
Defines the internal data of a functional industry.
Definition industry.h:66
IndustryType type
type of industry.
Definition industry.h:102
TimerGameCalendar::Date construction_date
Date of the construction of the industry.
Definition industry.h:114
IndustryControlFlags ctlflags
flags overriding standard behaviours
Definition industry.h:107
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
Definition industry.h:210
PersistentStorage * psa
Persistent storage for NewGRF industries.
Definition industry.h:123
uint8_t prod_level
general production level
Definition industry.h:99
Colours random_colour
randomized colour of the industry, for display purpose
Definition industry.h:104
AcceptedCargoes::iterator GetCargoAccepted(CargoID cargo)
Get accepted cargo slot for a specific cargo type.
Definition industry.h:189
uint8_t construction_type
Way the industry was constructed (.
Definition industry.h:115
const ProducedCargo & GetProduced(size_t slot) const
Safely get a produced cargo slot, or an empty data if the slot does not exist.
Definition industry.h:145
TimerGameEconomy::Year last_prod_year
last economy year of production
Definition industry.h:105
ProducedCargoes produced
produced cargo slots
Definition industry.h:97
uint16_t random
Random value used for randomisation of all kinds of things.
Definition industry.h:121
Town * town
Nearest town.
Definition industry.h:95
Owner founder
Founder of the industry.
Definition industry.h:113
uint8_t selected_layout
Which tile layout was used when creating the industry.
Definition industry.h:116
AcceptedCargoes accepted
accepted cargo slots
Definition industry.h:98
static uint16_t GetIndustryTypeCount(IndustryType type)
Get the count of industries for this type.
Definition industry.h:251
const AcceptedCargo & GetAccepted(size_t slot) const
Safely get an accepted cargo slot, or an empty data if the slot does not exist.
Definition industry.h:156
static std::array< std::vector< IndustryID >, NUM_INDUSTRYTYPES > industries
List of industries of each type.
Definition industry.h:263
TileArea location
Location of the industry.
Definition industry.h:94
uint16_t counter
used for animation and/or production (if available cargo)
Definition industry.h:100
ProducedCargoes::iterator GetCargoProduced(CargoID cargo)
Get produced cargo slot for a specific cargo type.
Definition industry.h:167
uint8_t was_cargo_delivered
flag that indicate this has been the closest industry chosen for cargo delivery by a station....
Definition industry.h:106
bool TileBelongsToIndustry(TileIndex tile) const
Check if a given tile belongs to this industry.
Definition industry.h:135
Information about a particular livery.
Definition livery.h:78
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:81
Colours colour1
First colour, for all vehicles.
Definition livery.h:80
uint16_t w
The width of the area.
TileIndex tile
The base tile of the area.
uint16_t h
The height of the area.
TYPE GetValue(uint pos) const
Gets the value from a given position.
void StoreValue(uint pos, int32_t value)
Stores some value at a given position.
Class for pooled persistent storage of data.
Tindex index
Index of this pool item.
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
CallbackID callback
Callback being resolved.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
ResolverObject & ro
Surrounding resolver object.
virtual const SpriteGroup * Resolve(ResolverObject &object) const
Base sprite group resolver.
Scope resolver for a town.
Definition newgrf_town.h:22
Town data structure.
Definition town.h:54
TileIndex xy
town center tile
Definition town.h:55
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
Definition of the game-calendar-timer.
Base of the town class.
HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile)
Returns the bit corresponding to the town zone of the specified tile.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3101
Window functions not directly related to making/drawing windows.
@ WC_INDUSTRY_VIEW
Industry view; Window numbers: