OpenTTD Source 20250528-master-g3aca5d62a8
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_badge.h"
14#include "newgrf_industries.h"
15#include "newgrf_town.h"
16#include "newgrf_cargo.h"
17#include "window_func.h"
18#include "town.h"
19#include "company_base.h"
20#include "error.h"
21#include "strings_func.h"
22#include "core/random_func.hpp"
24
25#include "table/strings.h"
26
27#include "safeguards.h"
28
29/* Since the industry IDs defined by the GRF file don't necessarily correlate
30 * to those used by the game, the IDs used for overriding old industries must be
31 * translated when the idustry spec is set. */
34
41IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32_t grf_id)
42{
43 if (grf_type == IT_INVALID) return IT_INVALID;
44 if (!HasBit(grf_type, 7)) return GB(grf_type, 0, 7);
45
46 return _industry_mngr.GetID(GB(grf_type, 0, 7), grf_id);
47}
48
57uint32_t GetIndustryIDAtOffset(TileIndex tile, const Industry *i, uint32_t cur_grfid)
58{
59 if (!i->TileBelongsToIndustry(tile)) {
60 /* No industry and/or the tile does not have the same industry as the one we match it with */
61 return 0xFFFF;
62 }
63
64 IndustryGfx gfx = GetCleanIndustryGfx(tile);
65 const IndustryTileSpec *indtsp = GetIndustryTileSpec(gfx);
66
67 if (gfx < NEW_INDUSTRYTILEOFFSET) { // Does it belongs to an old type?
68 /* It is an old tile. We have to see if it's been overridden */
69 if (indtsp->grf_prop.override_id == INVALID_INDUSTRYTILE) { // has it been overridden?
70 return 0xFF << 8 | gfx; // no. Tag FF + the gfx id of that tile
71 }
72 /* Overridden */
74
75 if (tile_ovr->grf_prop.grfid == cur_grfid) {
76 return tile_ovr->grf_prop.local_id; // same grf file
77 } else {
78 return 0xFFFE; // not the same grf file
79 }
80 }
81 /* Not an 'old type' tile */
82 if (indtsp->grf_prop.HasSpriteGroups()) {
83 if (indtsp->grf_prop.grfid == cur_grfid) { // same industry, same grf ?
84 return indtsp->grf_prop.local_id;
85 } else {
86 return 0xFFFE; // Defined in another grf file
87 }
88 }
89 /* The tile has no spritegroup */
90 return 0xFF << 8 | indtsp->grf_prop.subst_id; // so just give it the substitute
91}
92
93static uint32_t GetClosestIndustry(TileIndex tile, IndustryType type, const Industry *current)
94{
95 uint32_t best_dist = UINT32_MAX;
96
97 for (const IndustryID &industry : Industry::industries[type]) {
98 if (industry == current->index) continue;
99
100 best_dist = std::min(best_dist, DistanceManhattan(tile, Industry::Get(industry)->location.tile));
101 }
102
103 return best_dist;
104}
105
117static uint32_t GetCountAndDistanceOfClosestInstance(const ResolverObject &object, uint8_t param_set_id, uint8_t layout_filter, bool town_filter, const Industry *current)
118{
119 uint32_t grf_id = static_cast<uint32_t>(object.GetRegister(0x100));
120 IndustryType industry_type;
121 uint32_t closest_dist = UINT32_MAX;
122 uint8_t count = 0;
123
124 /* Determine what will be the industry type to look for */
125 switch (grf_id) {
126 case 0: // this is a default industry type
127 industry_type = param_set_id;
128 break;
129
130 case 0xFFFFFFFF: // current grf
131 grf_id = GetIndustrySpec(current->type)->grf_prop.grfid;
132 [[fallthrough]];
133
134 default: // use the grfid specified in register 100h
135 SetBit(param_set_id, 7); // bit 7 means it is not an old type
136 industry_type = MapNewGRFIndustryType(param_set_id, grf_id);
137 break;
138 }
139
140 /* If the industry type is invalid, there is none and the closest is far away. */
141 if (industry_type >= NUM_INDUSTRYTYPES) return 0 | 0xFFFF;
142
143 if (layout_filter == 0 && !town_filter) {
144 /* If the filter is 0, it could be because none was specified as well as being really a 0.
145 * In either case, just do the regular var67 */
146 closest_dist = GetClosestIndustry(current->location.tile, industry_type, current);
147 count = ClampTo<uint8_t>(Industry::GetIndustryTypeCount(industry_type));
148 } else {
149 /* Count only those who match the same industry type and layout filter
150 * Unfortunately, we have to do it manually */
151 for (const IndustryID &industry : Industry::industries[industry_type]) {
152 if (industry == current->index) continue;
153
154 const Industry *i = Industry::Get(industry);
155 if ((layout_filter == 0 || i->selected_layout == layout_filter) && (!town_filter || i->town == current->town)) {
156 closest_dist = std::min(closest_dist, DistanceManhattan(current->location.tile, i->location.tile));
157 count++;
158 }
159 }
160 }
161
162 return count << 16 | GB(closest_dist, 0, 16);
163}
164
165/* virtual */ uint32_t IndustriesScopeResolver::GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const
166{
167 if (this->ro.callback == CBID_INDUSTRY_LOCATION) {
168 /* Variables available during construction check. */
169
170 switch (variable) {
171 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, GetIndustrySpec(this->type)->badges, parameter);
172
173 case 0x80: return this->tile.base();
174 case 0x81: return GB(this->tile.base(), 8, 8);
175
176 /* Pointer to the town the industry is associated with */
177 case 0x82: return this->industry->town->index.base();
178 case 0x83:
179 case 0x84:
180 case 0x85: Debug(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported
181
182 /* Number of the layout */
183 case 0x86: return this->industry->selected_layout;
184
185 /* Ground type */
186 case 0x87: return GetTerrainType(this->tile);
187
188 /* Town zone */
189 case 0x88: return to_underlying(GetTownRadiusGroup(this->industry->town, this->tile));
190
191 /* Manhattan distance of the closest town */
192 case 0x89: return ClampTo<uint8_t>(DistanceManhattan(this->industry->town->xy, this->tile));
193
194 /* Lowest height of the tile */
195 case 0x8A: return ClampTo<uint8_t>(GetTileZ(this->tile) * (this->ro.grffile->grf_version >= 8 ? 1 : TILE_HEIGHT));
196
197 /* Distance to the nearest water/land tile */
199
200 /* Square of Euclidean distance from town */
201 case 0x8D: return ClampTo<uint16_t>(DistanceSquare(this->industry->town->xy, this->tile));
202
203 /* 32 random bits */
204 case 0x8F: return this->random_bits;
205 }
206 }
207
208 const IndustrySpec *indspec = GetIndustrySpec(this->type);
209
210 if (this->industry == nullptr) {
211 Debug(grf, 1, "Unhandled variable 0x{:X} (no available industry) in callback 0x{:x}", variable, this->ro.callback);
212
213 available = false;
214 return UINT_MAX;
215 }
216
217 switch (variable) {
218 case 0x40:
219 case 0x41:
220 case 0x42: { // waiting cargo, but only if those two callback flags are set
221 IndustryCallbackMasks callback = indspec->callback_mask;
222 if (callback.Any({IndustryCallbackMask::ProductionCargoArrival, IndustryCallbackMask::Production256Ticks})) {
224 if (this->industry->prod_level == 0) return 0;
225 return ClampTo<uint16_t>(this->industry->GetAccepted(variable - 0x40).waiting / this->industry->prod_level);
226 } else {
227 return ClampTo<uint16_t>(this->industry->GetAccepted(variable - 0x40).waiting);
228 }
229 } else {
230 return 0;
231 }
232 }
233
234 /* Manhattan distance of closes dry/water tile */
235 case 0x43:
236 if (this->tile == INVALID_TILE) break;
238
239 /* Layout number */
240 case 0x44: return this->industry->selected_layout;
241
242 /* Company info */
243 case 0x45: {
244 uint8_t colours = 0;
245 bool is_ai = false;
246
247 const Company *c = Company::GetIfValid(this->industry->founder);
248 if (c != nullptr) {
249 const Livery *l = &c->livery[LS_DEFAULT];
250
251 is_ai = c->is_ai;
252 colours = l->colour1 + l->colour2 * 16;
253 }
254
255 return this->industry->founder.base() | (is_ai ? 0x10000 : 0) | (colours << 24);
256 }
257
258 case 0x46: return this->industry->construction_date.base(); // Date when built - long format - (in days)
259
260 /* Override flags from GS */
261 case 0x47: return this->industry->ctlflags.base();
262
263 /* Get industry ID at offset param */
264 case 0x60: return GetIndustryIDAtOffset(GetNearbyTile(parameter, this->industry->location.tile, false), this->industry, this->ro.grffile->grfid);
265
266 /* Get random tile bits at offset param */
267 case 0x61: {
268 if (this->tile == INVALID_TILE) break;
269 TileIndex tile = GetNearbyTile(parameter, this->tile, false);
270 return this->industry->TileBelongsToIndustry(tile) ? GetIndustryRandomBits(tile) : 0;
271 }
272
273 /* Land info of nearby tiles */
274 case 0x62:
275 if (this->tile == INVALID_TILE) break;
276 return GetNearbyIndustryTileInformation(parameter, this->tile, IndustryID::Invalid(), false, this->ro.grffile->grf_version >= 8);
277
278 /* Animation stage of nearby tiles */
279 case 0x63: {
280 if (this->tile == INVALID_TILE) break;
281 TileIndex tile = GetNearbyTile(parameter, this->tile, false);
282 if (this->industry->TileBelongsToIndustry(tile)) {
283 return GetAnimationFrame(tile);
284 }
285 return 0xFFFFFFFF;
286 }
287
288 /* Distance of nearest industry of given type */
289 case 0x64: {
290 if (this->tile == INVALID_TILE) break;
291 IndustryType type = MapNewGRFIndustryType(parameter, indspec->grf_prop.grfid);
292 if (type >= NUM_INDUSTRYTYPES) return UINT32_MAX;
293 return GetClosestIndustry(this->tile, type, this->industry);
294 }
295 /* Get town zone and Manhattan distance of closest town */
296 case 0x65: {
297 if (this->tile == INVALID_TILE) break;
298 TileIndex tile = GetNearbyTile(parameter, this->tile, true);
299 return to_underlying(GetTownRadiusGroup(this->industry->town, tile)) << 16 | ClampTo<uint16_t>(DistanceManhattan(tile, this->industry->town->xy));
300 }
301 /* Get square of Euclidean distance of closest town */
302 case 0x66: {
303 if (this->tile == INVALID_TILE) break;
304 TileIndex tile = GetNearbyTile(parameter, this->tile, true);
305 return DistanceSquare(tile, this->industry->town->xy);
306 }
307
308 /* Count of industry, distance of closest instance
309 * 68 is the same as 67, but with a filtering on selected layout */
310 case 0x67:
311 case 0x68: {
312 uint8_t layout_filter = 0;
313 bool town_filter = false;
314 if (variable == 0x68) {
315 int32_t reg = this->ro.GetRegister(0x101);
316 layout_filter = GB(reg, 0, 8);
317 town_filter = HasBit(reg, 8);
318 }
319 return GetCountAndDistanceOfClosestInstance(this->ro, parameter, layout_filter, town_filter, this->industry);
320 }
321
322 case 0x69:
323 case 0x6A:
324 case 0x6B:
325 case 0x6C:
326 case 0x6D:
327 case 0x70:
328 case 0x71: {
329 CargoType cargo = GetCargoTranslation(parameter, this->ro.grffile);
330 if (!IsValidCargoType(cargo)) return 0;
331 auto it = this->industry->GetCargoProduced(cargo);
332 if (it == std::end(this->industry->produced)) return 0; // invalid cargo
333 switch (variable) {
334 case 0x69: return it->waiting;
335 case 0x6A: return it->history[THIS_MONTH].production;
336 case 0x6B: return it->history[THIS_MONTH].transported;
337 case 0x6C: return it->history[LAST_MONTH].production;
338 case 0x6D: return it->history[LAST_MONTH].transported;
339 case 0x70: return it->rate;
340 case 0x71: return it->history[LAST_MONTH].PctTransported();
341 default: NOT_REACHED();
342 }
343 }
344
345
346 case 0x6E:
347 case 0x6F: {
348 CargoType cargo = GetCargoTranslation(parameter, this->ro.grffile);
349 if (!IsValidCargoType(cargo)) return 0;
350 auto it = this->industry->GetCargoAccepted(cargo);
351 if (it == std::end(this->industry->accepted)) return 0; // invalid cargo
352 if (variable == 0x6E) return it->last_accepted.base();
353 if (variable == 0x6F) return it->waiting;
354 NOT_REACHED();
355 }
356
357 case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, GetIndustrySpec(this->type)->badges, parameter);
358
359 /* Get a variable from the persistent storage */
360 case 0x7C: return (this->industry->psa != nullptr) ? this->industry->psa->GetValue(parameter) : 0;
361
362 /* Industry structure access*/
363 case 0x80: return this->industry->location.tile.base();
364 case 0x81: return GB(this->industry->location.tile.base(), 8, 8);
365 /* Pointer to the town the industry is associated with */
366 case 0x82: return this->industry->town->index.base();
367 case 0x83:
368 case 0x84:
369 case 0x85: Debug(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported
370 case 0x86: return this->industry->location.w;
371 case 0x87: return this->industry->location.h;// xy dimensions
372
373 case 0x88:
374 case 0x89: return this->industry->GetProduced(variable - 0x88).cargo;
375 case 0x8A: return this->industry->GetProduced(0).waiting;
376 case 0x8B: return GB(this->industry->GetProduced(0).waiting, 8, 8);
377 case 0x8C: return this->industry->GetProduced(1).waiting;
378 case 0x8D: return GB(this->industry->GetProduced(1).waiting, 8, 8);
379 case 0x8E:
380 case 0x8F: return this->industry->GetProduced(variable - 0x8E).rate;
381 case 0x90:
382 case 0x91:
383 case 0x92: return this->industry->GetAccepted(variable - 0x90).cargo;
384 case 0x93: return this->industry->prod_level;
385 /* amount of cargo produced so far THIS month. */
386 case 0x94: return this->industry->GetProduced(0).history[THIS_MONTH].production;
387 case 0x95: return GB(this->industry->GetProduced(0).history[THIS_MONTH].production, 8, 8);
388 case 0x96: return this->industry->GetProduced(1).history[THIS_MONTH].production;
389 case 0x97: return GB(this->industry->GetProduced(1).history[THIS_MONTH].production, 8, 8);
390 /* amount of cargo transported so far THIS month. */
391 case 0x98: return this->industry->GetProduced(0).history[THIS_MONTH].transported;
392 case 0x99: return GB(this->industry->GetProduced(0).history[THIS_MONTH].transported, 8, 8);
393 case 0x9A: return this->industry->GetProduced(1).history[THIS_MONTH].transported;
394 case 0x9B: return GB(this->industry->GetProduced(1).history[THIS_MONTH].transported, 8, 8);
395 /* fraction of cargo transported LAST month. */
396 case 0x9C:
397 case 0x9D: return this->industry->GetProduced(variable - 0x9C).history[LAST_MONTH].PctTransported();
398 /* amount of cargo produced LAST month. */
399 case 0x9E: return this->industry->GetProduced(0).history[LAST_MONTH].production;
400 case 0x9F: return GB(this->industry->GetProduced(0).history[LAST_MONTH].production, 8, 8);
401 case 0xA0: return this->industry->GetProduced(1).history[LAST_MONTH].production;
402 case 0xA1: return GB(this->industry->GetProduced(1).history[LAST_MONTH].production, 8, 8);
403 /* amount of cargo transported last month. */
404 case 0xA2: return this->industry->GetProduced(0).history[LAST_MONTH].transported;
405 case 0xA3: return GB(this->industry->GetProduced(0).history[LAST_MONTH].transported, 8, 8);
406 case 0xA4: return this->industry->GetProduced(1).history[LAST_MONTH].transported;
407 case 0xA5: return GB(this->industry->GetProduced(1).history[LAST_MONTH].transported, 8, 8);
408
409 case 0xA6: return indspec->grf_prop.local_id;
410 case 0xA7: return this->industry->founder.base();
411 case 0xA8: return this->industry->random_colour;
412 case 0xA9: return ClampTo<uint8_t>(this->industry->last_prod_year - EconomyTime::ORIGINAL_BASE_YEAR);
413 case 0xAA: return this->industry->counter;
414 case 0xAB: return GB(this->industry->counter, 8, 8);
415 case 0xAC: return this->industry->was_cargo_delivered;
416
417 case 0xB0: return ClampTo<uint16_t>(this->industry->construction_date - CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date when built since 1920 (in days)
418 case 0xB3: return this->industry->construction_type; // Construction type
419 case 0xB4: {
420 if (this->industry->accepted.empty()) return 0;
421 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; });
422 return ClampTo<uint16_t>(it->last_accepted - EconomyTime::DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
423 }
424 }
425
426 Debug(grf, 1, "Unhandled industry variable 0x{:X}", variable);
427
428 available = false;
429 return UINT_MAX;
430}
431
432/* virtual */ uint32_t IndustriesScopeResolver::GetRandomBits() const
433{
434 return this->industry != nullptr ? this->industry->random : 0;
435}
436
437/* virtual */ uint32_t IndustriesScopeResolver::GetRandomTriggers() const
438{
439 return 0;
440}
441
442/* virtual */ void IndustriesScopeResolver::StorePSA(uint pos, int32_t value)
443{
444 if (this->industry->index == IndustryID::Invalid()) return;
445
446 if (this->industry->psa == nullptr) {
447 /* There is no need to create a storage if the value is zero. */
448 if (value == 0) return;
449
450 /* Create storage on first modification. */
451 const IndustrySpec *indsp = GetIndustrySpec(this->industry->type);
453 this->industry->psa = new PersistentStorage(indsp->grf_prop.grfid, GSF_INDUSTRIES, this->industry->location.tile);
454 }
455
456 this->industry->psa->StoreValue(pos, value);
457}
458
464static const GRFFile *GetGrffile(IndustryType type)
465{
466 const IndustrySpec *indspec = GetIndustrySpec(type);
467 return (indspec != nullptr) ? indspec->grf_prop.grffile : nullptr;
468}
469
480IndustriesResolverObject::IndustriesResolverObject(TileIndex tile, Industry *indus, IndustryType type, uint32_t random_bits,
481 CallbackID callback, uint32_t callback_param1, uint32_t callback_param2)
482 : ResolverObject(GetGrffile(type), callback, callback_param1, callback_param2),
483 industries_scope(*this, tile, indus, type, random_bits)
484{
485 this->root_spritegroup = GetIndustrySpec(type)->grf_prop.GetSpriteGroup(indus != nullptr && indus->index != IndustryID::Invalid());
486}
487
493{
494 if (!this->town_scope.has_value()) {
495 Town *t = nullptr;
496 bool readonly = true;
497 if (this->industries_scope.industry != nullptr) {
498 t = this->industries_scope.industry->town;
499 readonly = this->industries_scope.industry->index == IndustryID::Invalid();
500 } else if (this->industries_scope.tile != INVALID_TILE) {
501 t = ClosestTownFromTile(this->industries_scope.tile, UINT_MAX);
502 }
503 if (t == nullptr) return nullptr;
504 this->town_scope.emplace(*this, t, readonly);
505 }
506 return &*this->town_scope;
507}
508
510{
511 return GSF_INDUSTRIES;
512}
513
518
530uint16_t GetIndustryCallback(CallbackID callback, uint32_t param1, uint32_t param2, Industry *industry, IndustryType type, TileIndex tile, std::span<int32_t> regs100)
531{
532 IndustriesResolverObject object(tile, industry, type, 0, callback, param1, param2);
533 return object.ResolveCallback(regs100);
534}
535
547CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, size_t layout, uint32_t seed, uint16_t initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type)
548{
549 const IndustrySpec *indspec = GetIndustrySpec(type);
550
551 Industry ind;
552 ind.index = IndustryID::Invalid();
553 ind.location.tile = tile;
554 ind.location.w = 0; // important to mark the industry invalid
555 ind.type = type;
556 ind.selected_layout = (uint8_t)layout;
557 ind.town = ClosestTownFromTile(tile, UINT_MAX);
558 ind.random = initial_random_bits;
559 ind.founder = founder;
560 ind.psa = nullptr;
561
562 IndustriesResolverObject object(tile, &ind, type, seed, CBID_INDUSTRY_LOCATION, 0, creation_type);
563 std::array<int32_t, 16> regs100;
564 uint16_t result = object.ResolveCallback(regs100);
565
566 /* Unlike the "normal" cases, not having a valid result means we allow
567 * the building of the industry, as that's how it's done in TTDP. */
568 if (result == CALLBACK_FAILED) return CommandCost();
569
570 return GetErrorMessageFromLocationCallbackResult(result, regs100, indspec->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE);
571}
572
579uint32_t GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32_t default_prob)
580{
581 const IndustrySpec *indspec = GetIndustrySpec(type);
582
584 uint16_t res = GetIndustryCallback(CBID_INDUSTRY_PROBABILITY, 0, creation_type, nullptr, type, INVALID_TILE);
585 if (res != CALLBACK_FAILED) {
586 if (indspec->grf_prop.grffile->grf_version < 8) {
587 /* Disallow if result != 0 */
588 if (res != 0) default_prob = 0;
589 } else {
590 /* Use returned probability. 0x100 to use default */
591 if (res < 0x100) {
592 default_prob = res;
593 } else if (res > 0x100) {
595 }
596 }
597 }
598 }
599 return default_prob;
600}
601
608{
609 const IndustrySpec *spec = GetIndustrySpec(ind->type);
610 IndustriesResolverObject object(ind->location.tile, ind, ind->type);
611 if (spec->behaviour.Test(IndustryBehaviour::ProdCallbackRandom)) object.callback_param1 = Random();
612 int multiplier = 1;
614 object.callback_param2 = reason;
615
616 auto deref_ind_prod = [&object](int field, bool use_register) -> int32_t {
617 return use_register ? object.GetRegister(field) : field;
618 };
619
620 for (uint loop = 0;; loop++) {
621 /* limit the number of calls to break infinite loops.
622 * 'loop' is provided as 16 bits to the newgrf, so abort when those are exceeded. */
623 if (loop >= 0x10000) {
624 /* display error message */
625 ShowErrorMessage(GetEncodedString(STR_NEWGRF_BUGGY, spec->grf_prop.grffile->filename),
626 GetEncodedString(STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK, std::monostate{}, spec->name),
627 WL_WARNING);
628
629 /* abort the function early, this error isn't critical and will allow the game to continue to run */
630 break;
631 }
632
633 SB(object.callback_param2, 8, 16, loop);
634 const auto *group = object.Resolve<IndustryProductionSpriteGroup>();
635 if (group == nullptr) break;
636
637 if (group->version == 0xFF) {
638 /* Result was marked invalid on load, display error message */
639 ShowErrorMessage(GetEncodedString(STR_NEWGRF_BUGGY, spec->grf_prop.grffile->filename),
640 GetEncodedString(STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK, std::monostate{}, spec->name, ind->location.tile),
641 WL_WARNING);
642
643 /* abort the function early, this error isn't critical and will allow the game to continue to run */
644 break;
645 }
646
647 bool deref = (group->version >= 1);
648
649 if (group->version < 2) {
650 /* Callback parameters map directly to industry cargo slot indices */
651 for (uint i = 0; i < group->num_input && i < ind->accepted.size(); i++) {
652 if (!IsValidCargoType(ind->accepted[i].cargo)) continue;
653 ind->accepted[i].waiting = ClampTo<uint16_t>(ind->accepted[i].waiting - deref_ind_prod(group->subtract_input[i], deref) * multiplier);
654 }
655 for (uint i = 0; i < group->num_output && i < ind->produced.size(); i++) {
656 if (!IsValidCargoType(ind->produced[i].cargo)) continue;
657 ind->produced[i].waiting = ClampTo<uint16_t>(ind->produced[i].waiting + std::max(deref_ind_prod(group->add_output[i], deref), 0) * multiplier);
658 }
659 } else {
660 /* Callback receives list of cargos to apply for, which need to have their cargo slots in industry looked up */
661 for (uint i = 0; i < group->num_input; i++) {
662 auto it = ind->GetCargoAccepted(group->cargo_input[i]);
663 if (it == std::end(ind->accepted)) continue;
664 it->waiting = ClampTo<uint16_t>(it->waiting - deref_ind_prod(group->subtract_input[i], deref) * multiplier);
665 }
666 for (uint i = 0; i < group->num_output; i++) {
667 auto it = ind->GetCargoProduced(group->cargo_output[i]);
668 if (it == std::end(ind->produced)) continue;
669 it->waiting = ClampTo<uint16_t>(it->waiting + std::max(deref_ind_prod(group->add_output[i], deref), 0) * multiplier);
670 }
671 }
672
673 int32_t again = deref_ind_prod(group->again, deref);
674 if (again == 0) break;
675
676 SB(object.callback_param2, 24, 8, again);
677 }
678
680}
681
690{
691 assert(ind->IsCargoAccepted(cargo_type));
692
693 const IndustrySpec *indspec = GetIndustrySpec(ind->type);
696 0, indspec->grf_prop.grffile->cargo_map[cargo_type],
697 ind, ind->type, ind->location.tile);
699 }
700 return false;
701}
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 CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr bool Any(const Timpl &other) const
Test if any of the given values are set.
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.
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Functions related to errors.
@ WL_WARNING
Other information.
Definition error.h:25
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
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 IT_...
static const IndustryGfx INVALID_INDUSTRYTILE
one above amount is considered invalid
static const IndustryGfx NUM_INDUSTRYTILES
total number of industry tiles, new and old
@ ProdCallbackRandom
Production callback needs random bits in var 10.
@ BuiltOnWater
is built on water (oil rig)
@ ProdMultiHandling
Automatic production multiplier handling.
@ Random
Randomise borders.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:159
uint DistanceManhattan(TileIndex t0, TileIndex t1)
Gets the Manhattan distance between the two given tiles.
Definition map.cpp:142
uint GetClosestWaterDistance(TileIndex tile, bool water)
Finds the distance for the closest tile with water/land given a tile.
Definition map.cpp:236
GrfSpecFeature
Definition newgrf.h:69
uint32_t GetBadgeVariableResult(const GRFFile &grffile, std::span< const BadgeID > badges, uint32_t parameter)
Test for a matching badge in a list of badges, returning the number of matching bits.
Functions related to NewGRF badges.
@ Probability
industry availability/probability callback
@ RefuseCargo
option out of accepting cargo
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.
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Cargo support for NewGRFs.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, std::span< const int32_t > textstack, const GRFFile *grffile, StringID default_error)
Get the error message from a shape/location/slope check 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(const ResolverObject &object, uint8_t param_set_id, 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.
uint16_t GetIndustryCallback(CallbackID callback, uint32_t param1, uint32_t param2, Industry *industry, IndustryType type, TileIndex tile, std::span< int32_t > regs100)
Perform an industry callback.
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.
bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoType cargo_type)
Check whether an industry temporarily refuses to accept a certain cargo.
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.
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.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
Functions related to OTTD's strings.
bool is_ai
If true, the company is (also) controlled by the computer (a NoAI program).
const struct GRFFile * grffile
grf file that introduced this entity
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:115
std::array< uint8_t, NUM_CARGO > cargo_map
Inverse cargo translation table (CargoType -> local ID)
Definition newgrf.h:137
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 GetRandomTriggers() 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.
Defines the data structure for constructing industry.
IndustryCallbackMasks callback_mask
Bitmask of industry callbacks that have to be called.
SubstituteGRFFileProps grf_prop
properties related to the grf file
StringID name
Displayed name of the industry.
IndustryBehaviours behaviour
How this industry will behave, and how others entities can use it.
Defines the data structure of each individual tile of an industry.
SubstituteGRFFileProps grf_prop
properties related to the grf file
CargoType cargo
Cargo type.
Definition industry.h:84
uint16_t waiting
Amount of cargo waiting to processed.
Definition industry.h:85
uint16_t waiting
Amount of cargo produced.
Definition industry.h:78
std::array< ProducedHistory, 25 > history
History of cargo produced and transported for this month and 24 previous months.
Definition industry.h:80
CargoType cargo
Cargo type.
Definition industry.h:77
uint8_t rate
Production rate.
Definition industry.h:79
Defines the internal data of a functional industry.
Definition industry.h:64
IndustryType type
type of industry.
Definition industry.h:100
TimerGameCalendar::Date construction_date
Date of the construction of the industry.
Definition industry.h:112
IndustryControlFlags ctlflags
flags overriding standard behaviours
Definition industry.h:105
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
Definition industry.h:208
PersistentStorage * psa
Persistent storage for NewGRF industries.
Definition industry.h:121
uint8_t prod_level
general production level
Definition industry.h:97
Colours random_colour
randomized colour of the industry, for display purpose
Definition industry.h:102
ProducedCargoes::iterator GetCargoProduced(CargoType cargo)
Get produced cargo slot for a specific cargo type.
Definition industry.h:165
uint8_t construction_type
Way the industry was constructed (.
Definition industry.h:113
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:143
TimerGameEconomy::Year last_prod_year
last economy year of production
Definition industry.h:103
ProducedCargoes produced
produced cargo slots
Definition industry.h:95
uint16_t random
Random value used for randomisation of all kinds of things.
Definition industry.h:119
Town * town
Nearest town.
Definition industry.h:93
Owner founder
Founder of the industry.
Definition industry.h:111
uint8_t selected_layout
Which tile layout was used when creating the industry.
Definition industry.h:114
AcceptedCargoes accepted
accepted cargo slots
Definition industry.h:96
static uint16_t GetIndustryTypeCount(IndustryType type)
Get the count of industries for this type.
Definition industry.h:249
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:154
TileArea location
Location of the industry.
Definition industry.h:92
uint16_t counter
used for animation and/or production (if available cargo)
Definition industry.h:98
uint8_t was_cargo_delivered
flag that indicate this has been the closest industry chosen for cargo delivery by a station....
Definition industry.h:104
bool TileBelongsToIndustry(TileIndex tile) const
Check if a given tile belongs to this industry.
Definition industry.h:133
AcceptedCargoes::iterator GetCargoAccepted(CargoType cargo)
Get accepted cargo slot for a specific cargo type.
Definition industry.h:187
static std::array< FlatSet< IndustryID >, NUM_INDUSTRYTYPES > industries
List of industries of each type.
Definition industry.h:261
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.
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:43
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
int32_t GetRegister(uint i) const
Gets the value of a so-called newgrf "register".
CallbackID callback
Callback being resolved.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
ResolverObject & ro
Surrounding resolver object.
const struct SpriteGroup * GetSpriteGroup(bool entity_exists) const
Get the standard sprite group.
bool HasSpriteGroups() const
Check whether the entity has sprite groups.
uint16_t override_id
id of the entity been replaced by
Scope resolver for a town.
Definition newgrf_town.h:22
Town data structure.
Definition town.h:52
TileIndex xy
town center tile
Definition town.h:53
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.
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
HouseZone GetTownRadiusGroup(const Town *t, TileIndex tile)
Returns the bit corresponding to the town zone of the specified tile.
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3147
Window functions not directly related to making/drawing windows.
@ WC_INDUSTRY_VIEW
Industry view; Window numbers: