OpenTTD Source 20260108-master-g8ba1860eaa
newgrf_commons.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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "stdafx.h"
11#include "debug.h"
12#include "landscape.h"
13#include "house.h"
14#include "industrytype.h"
15#include "newgrf_config.h"
16#include "company_func.h"
17#include "clear_map.h"
18#include "station_map.h"
19#include "tree_map.h"
20#include "tunnelbridge_map.h"
21#include "newgrf_object.h"
22#include "genworld.h"
23#include "newgrf_spritegroup.h"
24#include "newgrf_text.h"
25#include "company_base.h"
26#include "error.h"
27#include "strings_func.h"
28#include "string_func.h"
29
30#include "table/strings.h"
31
32#include "safeguards.h"
33
40OverrideManagerBase::OverrideManagerBase(uint16_t offset, uint16_t maximum, uint16_t invalid)
41{
42 this->max_offset = offset;
43 this->max_entities = maximum;
44 this->invalid_id = invalid;
45
46 this->mappings.resize(this->max_entities);
47 this->entity_overrides.resize(this->max_offset);
48 std::fill(this->entity_overrides.begin(), this->entity_overrides.end(), this->invalid_id);
49 this->grfid_overrides.resize(this->max_offset);
50}
51
60void OverrideManagerBase::Add(uint16_t local_id, uint32_t grfid, uint entity_type)
61{
62 assert(entity_type < this->max_offset);
63 /* An override can be set only once */
64 if (this->entity_overrides[entity_type] != this->invalid_id) return;
65 this->entity_overrides[entity_type] = local_id;
66 this->grfid_overrides[entity_type] = grfid;
67}
68
71{
72 std::fill(this->mappings.begin(), this->mappings.end(), EntityIDMapping{});
73}
74
77{
78 std::fill(this->entity_overrides.begin(), this->entity_overrides.end(), this->invalid_id);
79 std::fill(this->grfid_overrides.begin(), this->grfid_overrides.end(), uint32_t());
80}
81
88uint16_t OverrideManagerBase::GetID(uint16_t grf_local_id, uint32_t grfid) const
89{
90 for (uint16_t id = 0; id < this->max_entities; id++) {
91 const EntityIDMapping *map = &this->mappings[id];
92 if (map->entity_id == grf_local_id && map->grfid == grfid) {
93 return id;
94 }
95 }
96
97 return this->invalid_id;
98}
99
107uint16_t OverrideManagerBase::AddEntityID(uint16_t grf_local_id, uint32_t grfid, uint16_t substitute_id)
108{
109 uint16_t id = this->GetID(grf_local_id, grfid);
110
111 /* Look to see if this entity has already been added. This is done
112 * separately from the loop below in case a GRF has been deleted, and there
113 * are any gaps in the array.
114 */
115 if (id != this->invalid_id) return id;
116
117 /* This entity hasn't been defined before, so give it an ID now. */
118 for (id = this->max_offset; id < this->max_entities; id++) {
119 EntityIDMapping *map = &this->mappings[id];
120
121 if (CheckValidNewID(id) && map->entity_id == 0 && map->grfid == 0) {
122 map->entity_id = grf_local_id;
123 map->grfid = grfid;
124 map->substitute_id = substitute_id;
125 return id;
126 }
127 }
128
129 return this->invalid_id;
130}
131
137uint32_t OverrideManagerBase::GetGRFID(uint16_t entity_id) const
138{
139 return this->mappings[entity_id].grfid;
140}
141
147uint16_t OverrideManagerBase::GetSubstituteID(uint16_t entity_id) const
148{
149 return this->mappings[entity_id].substitute_id;
150}
151
158{
159 HouseID house_id = this->AddEntityID(hs.grf_prop.local_id, hs.grf_prop.grfid, hs.grf_prop.subst_id);
160
161 if (house_id == this->invalid_id) {
162 GrfMsg(1, "House.SetEntitySpec: Too many houses allocated. Ignoring.");
163 return;
164 }
165
166 auto &house_specs = HouseSpec::Specs();
167
168 /* Now that we know we can use the given id, copy the spec to its final destination. */
169 if (house_id >= house_specs.size()) house_specs.resize(house_id + 1);
170 house_specs[house_id] = std::move(hs);
171
172 /* Now add the overrides. */
173 for (int i = 0; i < this->max_offset; i++) {
174 HouseSpec *overridden_hs = HouseSpec::Get(i);
175
176 if (this->entity_overrides[i] != house_specs[house_id].grf_prop.local_id || this->grfid_overrides[i] != house_specs[house_id].grf_prop.grfid) continue;
177
178 overridden_hs->grf_prop.override_id = house_id;
179 this->entity_overrides[i] = this->invalid_id;
180 this->grfid_overrides[i] = 0;
181 }
182}
183
190uint16_t IndustryOverrideManager::GetID(uint16_t grf_local_id, uint32_t grfid) const
191{
192 uint16_t id = OverrideManagerBase::GetID(grf_local_id, grfid);
193 if (id != this->invalid_id) return id;
194
195 /* No mapping found, try the overrides */
196 for (id = 0; id < this->max_offset; id++) {
197 if (this->entity_overrides[id] == grf_local_id && this->grfid_overrides[id] == grfid) return id;
198 }
199
200 return this->invalid_id;
201}
202
210uint16_t IndustryOverrideManager::AddEntityID(uint16_t grf_local_id, uint32_t grfid, uint16_t substitute_id)
211{
212 /* This entity hasn't been defined before, so give it an ID now. */
213 for (uint16_t id = 0; id < this->max_entities; id++) {
214 /* Skip overridden industries */
215 if (id < this->max_offset && this->entity_overrides[id] != this->invalid_id) continue;
216
217 /* Get the real live industry */
218 const IndustrySpec *inds = GetIndustrySpec(id);
219
220 /* This industry must be one that is not available(enabled), mostly because of climate.
221 * And it must not already be used by a grf (grffile == nullptr).
222 * So reserve this slot here, as it is the chosen one */
223 if (!inds->enabled && !inds->grf_prop.HasGrfFile()) {
224 EntityIDMapping *map = &this->mappings[id];
225
226 if (map->entity_id == 0 && map->grfid == 0) {
227 /* winning slot, mark it as been used */
228 map->entity_id = grf_local_id;
229 map->grfid = grfid;
230 map->substitute_id = substitute_id;
231 return id;
232 }
233 }
234 }
235
236 return this->invalid_id;
237}
238
246{
247 /* First step : We need to find if this industry is already specified in the savegame data. */
248 IndustryType ind_id = this->GetID(inds.grf_prop.local_id, inds.grf_prop.grfid);
249
250 if (ind_id == this->invalid_id) {
251 /* Not found.
252 * Or it has already been overridden, so you've lost your place.
253 * Or it is a simple substitute.
254 * We need to find a free available slot */
255 ind_id = this->AddEntityID(inds.grf_prop.local_id, inds.grf_prop.grfid, inds.grf_prop.subst_id);
256 inds.grf_prop.override_id = this->invalid_id; // make sure it will not be detected as overridden
257 }
258
259 if (ind_id == this->invalid_id) {
260 GrfMsg(1, "Industry.SetEntitySpec: Too many industries allocated. Ignoring.");
261 return;
262 }
263
264 /* Now that we know we can use the given id, copy the spec to its final destination... */
265 _industry_specs[ind_id] = std::move(inds);
266 /* ... and mark it as usable*/
267 _industry_specs[ind_id].enabled = true;
268}
269
270void IndustryTileOverrideManager::SetEntitySpec(IndustryTileSpec &&its)
271{
272 IndustryGfx indt_id = this->AddEntityID(its.grf_prop.local_id, its.grf_prop.grfid, its.grf_prop.subst_id);
273
274 if (indt_id == this->invalid_id) {
275 GrfMsg(1, "IndustryTile.SetEntitySpec: Too many industry tiles allocated. Ignoring.");
276 return;
277 }
278
279 _industry_tile_specs[indt_id] = std::move(its);
280
281 /* Now add the overrides. */
282 for (int i = 0; i < this->max_offset; i++) {
283 IndustryTileSpec *overridden_its = &_industry_tile_specs[i];
284
285 if (this->entity_overrides[i] != _industry_tile_specs[indt_id].grf_prop.local_id || this->grfid_overrides[i] != _industry_tile_specs[indt_id].grf_prop.grfid) continue;
286
287 overridden_its->grf_prop.override_id = indt_id;
288 overridden_its->enabled = false;
289 this->entity_overrides[i] = this->invalid_id;
290 this->grfid_overrides[i] = 0;
291 }
292}
293
301{
302 /* First step : We need to find if this object is already specified in the savegame data. */
303 ObjectType type = this->GetID(spec.grf_prop.local_id, spec.grf_prop.grfid);
304
305 if (type == this->invalid_id) {
306 /* Not found.
307 * Or it has already been overridden, so you've lost your place.
308 * Or it is a simple substitute.
309 * We need to find a free available slot */
310 type = this->AddEntityID(spec.grf_prop.local_id, spec.grf_prop.grfid, OBJECT_TRANSMITTER);
311 }
312
313 if (type == this->invalid_id) {
314 GrfMsg(1, "Object.SetEntitySpec: Too many objects allocated. Ignoring.");
315 return;
316 }
317
318 extern std::vector<ObjectSpec> _object_specs;
319
320 /* Now that we know we can use the given id, copy the spec to its final destination. */
321 if (type >= _object_specs.size()) _object_specs.resize(type + 1);
322 _object_specs[type] = std::move(spec);
323}
324
333uint32_t GetTerrainType(TileIndex tile, TileContext context)
334{
336 case LandscapeType::Tropic: return GetTropicZone(tile);
337 case LandscapeType::Arctic: {
338 bool has_snow;
339 switch (GetTileType(tile)) {
340 case MP_CLEAR:
341 /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
342 if (_generating_world) goto genworld;
343 has_snow = IsSnowTile(tile) && GetClearDensity(tile) >= 2;
344 break;
345
346 case MP_RAILWAY: {
347 /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
348 if (_generating_world) goto genworld; // we do not care about foundations here
349 RailGroundType ground = GetRailGroundType(tile);
350 has_snow = (ground == RailGroundType::SnowOrDesert || (context == TCX_UPPER_HALFTILE && ground == RailGroundType::HalfTileSnow));
351 break;
352 }
353
354 case MP_ROAD:
355 /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
356 if (_generating_world) goto genworld; // we do not care about foundations here
357 has_snow = IsOnSnowOrDesert(tile);
358 break;
359
360 case MP_TREES: {
361 /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
362 if (_generating_world) goto genworld;
363 TreeGround ground = GetTreeGround(tile);
364 has_snow = (ground == TREE_GROUND_SNOW_DESERT || ground == TREE_GROUND_ROUGH_SNOW) && GetTreeDensity(tile) >= 2;
365 break;
366 }
367
368 case MP_TUNNELBRIDGE:
369 if (context == TCX_ON_BRIDGE) {
370 has_snow = (GetBridgeHeight(tile) > GetSnowLine());
371 } else {
372 /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */
373 if (_generating_world) goto genworld; // we do not care about foundations here
374 has_snow = HasTunnelBridgeSnowOrDesert(tile);
375 }
376 break;
377
378 case MP_STATION:
379 case MP_HOUSE:
380 case MP_INDUSTRY:
381 case MP_OBJECT:
382 /* These tiles usually have a levelling foundation. So use max Z */
383 has_snow = (GetTileMaxZ(tile) > GetSnowLine());
384 break;
385
386 case MP_VOID:
387 case MP_WATER:
388 genworld:
389 has_snow = (GetTileZ(tile) > GetSnowLine());
390 break;
391
392 default: NOT_REACHED();
393 }
394 return has_snow ? 4 : 0;
395 }
396 default: return 0;
397 }
398}
399
408TileIndex GetNearbyTile(uint8_t parameter, TileIndex tile, bool signed_offsets, Axis axis)
409{
410 int8_t x = GB(parameter, 0, 4);
411 int8_t y = GB(parameter, 4, 4);
412
413 if (signed_offsets && x >= 8) x -= 16;
414 if (signed_offsets && y >= 8) y -= 16;
415
416 /* Swap width and height depending on axis for railway stations */
417 if (axis == INVALID_AXIS && HasStationTileRail(tile)) axis = GetRailStationAxis(tile);
418 if (axis == AXIS_Y) std::swap(x, y);
419
420 /* Make sure we never roam outside of the map, better wrap in that case */
421 return Map::WrapToMap(tile + TileDiffXY(x, y));
422}
423
431uint32_t GetNearbyTileInformation(TileIndex tile, bool grf_version8)
432{
433 TileType tile_type = GetTileType(tile);
434
435 /* Fake tile type for trees on shore */
436 if (IsTileType(tile, MP_TREES) && GetTreeGround(tile) == TREE_GROUND_SHORE) tile_type = MP_WATER;
437
438 /* Fake tile type for road waypoints */
439 if (IsRoadWaypointTile(tile)) tile_type = MP_ROAD;
440
441 auto [tileh, z] = GetTilePixelSlope(tile);
442 /* Return 0 if the tile is a land tile */
443 uint8_t terrain_type = (HasTileWaterClass(tile) ? (to_underlying(GetWaterClass(tile)) + 1) & 3 : 0) << 5 | GetTerrainType(tile) << 2 | (tile_type == MP_WATER ? 1 : 0) << 1;
444 if (grf_version8) z /= TILE_HEIGHT;
445 return tile_type << 24 | ClampTo<uint8_t>(z) << 16 | terrain_type << 8 | tileh;
446}
447
454uint32_t GetCompanyInfo(CompanyID owner, const Livery *l)
455{
456 if (l == nullptr && Company::IsValidID(owner)) l = &Company::Get(owner)->livery[LS_DEFAULT];
457 return owner.base() | (Company::IsValidAiID(owner) ? 0x10000 : 0) | (l != nullptr ? (l->colour1 << 24) | (l->colour2 << 28) : 0);
458}
459
468CommandCost GetErrorMessageFromLocationCallbackResult(uint16_t cb_res, std::span<const int32_t> textstack, const GRFFile *grffile, StringID default_error)
469{
470 auto get_newgrf_text = [&grffile](GRFStringID text_id, std::span<const int32_t> textstack) {
471 CommandCost res = CommandCost(GetGRFStringID(grffile->grfid, text_id));
472
473 /* If this error isn't for the local player then it won't be seen, so don't bother encoding anything. */
474 if (IsLocalCompany()) {
475 StringID stringid = GetGRFStringID(grffile->grfid, text_id);
476 auto params = GetGRFStringTextStackParameters(grffile, stringid, textstack);
477 res.SetEncodedMessage(GetEncodedStringWithArgs(stringid, params));
478 }
479
480 return res;
481 };
482
483 CommandCost res;
484 if (cb_res < 0x400) {
485 res = get_newgrf_text(GRFSTR_MISC_GRF_TEXT + cb_res, textstack);
486 } else {
487 switch (cb_res) {
488 case 0x400: return res; // No error.
489
490 default: // unknown reason -> default error
491 case 0x401: res = CommandCost(default_error); break;
492
493 case 0x402: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST); break;
494 case 0x403: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT); break;
495 case 0x404: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE); break;
496 case 0x405: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE); break;
497 case 0x406: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_SEA); break;
498 case 0x407: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_CANAL); break;
499 case 0x408: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_RIVER); break;
500 case 0x40F: res = get_newgrf_text(static_cast<GRFStringID>(textstack[0]), textstack.subspan(1)); break;
501 }
502 }
503
504 return res;
505}
506
514void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
515{
516 GRFConfig *grfconfig = GetGRFConfig(grfid);
517
518 if (grfconfig->grf_bugs.Test(GRFBug::UnknownCbResult)) {
520 ShowErrorMessage(GetEncodedString(STR_NEWGRF_BUGGY, grfconfig->GetName()),
521 GetEncodedString(STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, std::monostate{}, cbid, cb_res),
523 }
524
525 /* debug output */
526 Debug(grf, 0, "{}", StrMakeValid(GetString(STR_NEWGRF_BUGGY, grfconfig->GetName())));
527
528 Debug(grf, 0, "{}", StrMakeValid(GetString(STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, std::monostate{}, cbid, cb_res)));
529}
530
540bool ConvertBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
541{
542 assert(cb_res != CALLBACK_FAILED); // We do not know what to return
543
544 if (grffile->grf_version < 8) return cb_res != 0;
545
546 if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res);
547 return cb_res != 0;
548}
549
559bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
560{
561 assert(cb_res != CALLBACK_FAILED); // We do not know what to return
562
563 if (grffile->grf_version < 8) return GB(cb_res, 0, 8) != 0;
564
565 if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res);
566 return cb_res != 0;
567}
568
573void NewGRFSpriteLayout::Allocate(uint num_sprites)
574{
575 assert(this->seq.empty());
576
577 this->seq.resize(num_sprites, {});
578}
579
584{
585 assert(this->registers.empty());
586
587 this->registers.resize(1 + this->seq.size(), {}); // 1 for the ground sprite
588}
589
600SpriteLayoutProcessor::SpriteLayoutProcessor(const NewGRFSpriteLayout &raw_layout, uint32_t orig_offset, uint32_t newgrf_ground_offset, uint32_t newgrf_offset, uint constr_stage, bool separate_ground) :
601 raw_layout(&raw_layout), separate_ground(separate_ground)
602{
603 this->result_seq.reserve(this->raw_layout->seq.size() + 1);
604
605 /* Create a copy of the spritelayout, so we can modify some values.
606 * Also include the groundsprite into the sequence for easier processing. */
607 DrawTileSeqStruct &copy = this->result_seq.emplace_back();
608 copy.image = this->raw_layout->ground;
609 copy.origin.z = static_cast<int8_t>(0x80);
610
611 this->result_seq.insert(this->result_seq.end(), this->raw_layout->seq.begin(), this->raw_layout->seq.end());
612
613 /* Determine the var10 values the action-1-2-3 chains needs to be resolved for,
614 * and apply the default sprite offsets (unless disabled). */
615 const TileLayoutRegisters *regs = this->raw_layout->registers.empty() ? nullptr : this->raw_layout->registers.data();
616 bool ground = true;
617 for (DrawTileSeqStruct &result : this->result_seq) {
618 TileLayoutFlags flags = TLF_NOTHING;
619 if (regs != nullptr) flags = regs->flags;
620
621 /* Record var10 value for the sprite */
622 if (HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) {
623 uint8_t var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && this->separate_ground ? 1 : 0);
624 SetBit(this->var10_values, var10);
625 }
626
627 /* Add default sprite offset, unless there is a custom one */
628 if (!(flags & TLF_SPRITE)) {
629 if (HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) {
630 result.image.sprite += ground ? newgrf_ground_offset : newgrf_offset;
631 if (constr_stage > 0 && regs != nullptr) result.image.sprite += GetConstructionStageOffset(constr_stage, regs->max_sprite_offset);
632 } else {
633 result.image.sprite += orig_offset;
634 }
635 }
636
637 /* Record var10 value for the palette */
638 if (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS)) {
639 uint8_t var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && this->separate_ground ? 1 : 0);
640 SetBit(this->var10_values, var10);
641 }
642
643 /* Add default palette offset, unless there is a custom one */
644 if (!(flags & TLF_PALETTE)) {
645 if (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) {
646 result.image.sprite += ground ? newgrf_ground_offset : newgrf_offset;
647 if (constr_stage > 0 && regs != nullptr) result.image.sprite += GetConstructionStageOffset(constr_stage, regs->max_palette_offset);
648 }
649 }
650
651 ground = false;
652 if (regs != nullptr) regs++;
653 }
654}
655
662void SpriteLayoutProcessor::ProcessRegisters(const ResolverObject &object, uint8_t resolved_var10, uint32_t resolved_sprite)
663{
664 assert(this->raw_layout != nullptr);
665 const TileLayoutRegisters *regs = this->raw_layout->registers.empty() ? nullptr : this->raw_layout->registers.data();
666 bool ground = true;
667 for (DrawTileSeqStruct &result : this->result_seq) {
668 TileLayoutFlags flags = TLF_NOTHING;
669 if (regs != nullptr) flags = regs->flags;
670
671 /* Is the sprite or bounding box affected by an action-1-2-3 chain? */
672 if (HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) {
673 /* Does the var10 value apply to this sprite? */
674 uint8_t var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && this->separate_ground ? 1 : 0);
675 if (var10 == resolved_var10) {
676 /* Apply registers */
677 if ((flags & TLF_DODRAW) && object.GetRegister(regs->dodraw) == 0) {
678 result.image.sprite = 0;
679 } else {
680 if (HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) result.image.sprite += resolved_sprite;
681 if (flags & TLF_SPRITE) {
682 int16_t offset = static_cast<int16_t>(object.GetRegister(regs->sprite)); // mask to 16 bits to avoid trouble
683 if (!HasBit(result.image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (offset >= 0 && offset < regs->max_sprite_offset)) {
684 result.image.sprite += offset;
685 } else {
686 result.image.sprite = SPR_IMG_QUERY;
687 }
688 }
689
690 if (result.IsParentSprite()) {
691 if (flags & TLF_BB_XY_OFFSET) {
692 result.origin.x += object.GetRegister(regs->delta.parent[0]);
693 result.origin.y += object.GetRegister(regs->delta.parent[1]);
694 }
695 if (flags & TLF_BB_Z_OFFSET) result.origin.z += object.GetRegister(regs->delta.parent[2]);
696 } else {
697 if (flags & TLF_CHILD_X_OFFSET) result.origin.x += object.GetRegister(regs->delta.child[0]);
698 if (flags & TLF_CHILD_Y_OFFSET) result.origin.y += object.GetRegister(regs->delta.child[1]);
699 }
700 }
701 }
702 }
703
704 /* Is the palette affected by an action-1-2-3 chain? */
705 if (result.image.sprite != 0 && (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS))) {
706 /* Does the var10 value apply to this sprite? */
707 uint8_t var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && this->separate_ground ? 1 : 0);
708 if (var10 == resolved_var10) {
709 /* Apply registers */
710 if (HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) result.image.pal += resolved_sprite;
711 if (flags & TLF_PALETTE) {
712 int16_t offset = static_cast<int16_t>(object.GetRegister(regs->palette)); // mask to 16 bits to avoid trouble
713 if (!HasBit(result.image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (offset >= 0 && offset < regs->max_palette_offset)) {
714 result.image.pal += offset;
715 } else {
716 result.image.sprite = SPR_IMG_QUERY;
717 result.image.pal = PAL_NONE;
718 }
719 }
720 }
721 }
722
723 ground = false;
724 if (regs != nullptr) regs++;
725 }
726}
727
732void GRFFilePropsBase::SetGRFFile(const struct GRFFile *grffile)
733{
734 this->grffile = grffile;
735 this->grfid = grffile == nullptr ? 0 : grffile->grfid;
736}
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
int GetBridgeHeight(TileIndex t)
Get the height ('z') of a bridge.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
Common return value for all commands.
void SetEncodedMessage(EncodedString &&message)
Set the encoded message string.
void SetEntitySpec(HouseSpec &&hs)
Install the specs into the HouseSpecs array It will find itself the proper slot on which it will go.
uint16_t AddEntityID(uint16_t grf_local_id, uint32_t grfid, uint16_t substitute_id) override
Method to find an entity ID and to mark it as reserved for the Industry to be included.
uint16_t GetID(uint16_t grf_local_id, uint32_t grfid) const override
Return the ID (if ever available) of a previously inserted entity.
void SetEntitySpec(IndustrySpec &&inds)
Method to install the new industry data in its proper slot The slot assignment is internal of this me...
void SetEntitySpec(ObjectSpec &&spec)
Method to install the new object data in its proper slot The slot assignment is internal of this meth...
uint32_t GetGRFID(uint16_t entity_id) const
Gives the GRFID of the file the entity belongs to.
void ResetMapping()
Resets the mapping, which is used while initializing game.
uint16_t max_entities
what is the amount of entities, old and new summed
virtual uint16_t GetID(uint16_t grf_local_id, uint32_t grfid) const
Return the ID (if ever available) of a previously inserted entity.
uint16_t invalid_id
ID used to detected invalid entities.
void Add(uint16_t local_id, uint32_t grfid, uint entity_type)
Since the entity IDs defined by the GRF file does not necessarily correlate to those used by the game...
OverrideManagerBase(uint16_t offset, uint16_t maximum, uint16_t invalid)
Constructor of generic class.
std::vector< EntityIDMapping > mappings
mapping of ids from grf files. Public out of convenience
void ResetOverride()
Resets the override, which is used while initializing game.
uint16_t GetSubstituteID(uint16_t entity_id) const
Gives the substitute of the entity, as specified by the grf file.
uint16_t max_offset
what is the length of the original entity's array of specs
virtual uint16_t AddEntityID(uint16_t grf_local_id, uint32_t grfid, uint16_t substitute_id)
Reserves a place in the mapping array for an entity to be installed.
void ProcessRegisters(const struct ResolverObject &object, uint8_t resolved_var10, uint32_t resolved_sprite)
Evaluates the register modifiers and integrates them into the preprocessed sprite layout.
Map accessors for 'clear' tiles.
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:35
uint GetClearDensity(Tile t)
Get the density of a non-field clear tile.
Definition clear_map.h:71
Definition of stuff that is very close to a company, like the company struct itself.
Functions related to companies.
bool IsLocalCompany()
Is the current company the local company?
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Axis
Allow incrementing of DiagDirDiff variables.
@ INVALID_AXIS
Flag for an invalid Axis.
@ AXIS_Y
The y axis.
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_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:74
Functions related to world/map generation.
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
Definition of HouseSpec and accessors.
uint16_t HouseID
OpenTTD ID of house types.
Definition house_type.h:15
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
Industry type specs.
Functions related to OTTD's landscape.
TileIndexDiff TileDiffXY(int x, int y)
Calculates an offset for the given coordinate(-offset).
Definition map_func.h:401
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16_t cbid, uint16_t cb_res)
Converts a callback result into a boolean.
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.
uint32_t GetCompanyInfo(CompanyID owner, const Livery *l)
Returns company information like in vehicle var 43 or station var 43.
uint32_t GetNearbyTileInformation(TileIndex tile, bool grf_version8)
Common part of station var 0x67, house var 0x62, indtile var 0x60, industry var 0x62.
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.
TileContext
Context for tile accesses.
@ TCX_UPPER_HALFTILE
Querying information about the upper part of a tile with halftile foundation.
@ TCX_ON_BRIDGE
Querying information about stuff on the bridge (via some bridgehead).
TileLayoutFlags
Flags to enable register usage in sprite layouts.
@ TLF_BB_Z_OFFSET
Add signed offset to bounding box Z positions from register TileLayoutRegisters::delta....
@ TLF_SPRITE
Add signed offset to sprite from register TileLayoutRegisters::sprite.
@ TLF_CHILD_X_OFFSET
Add signed offset to child sprite X positions from register TileLayoutRegisters::delta....
@ TLF_DODRAW
Only draw sprite if value of register TileLayoutRegisters::dodraw is non-zero.
@ TLF_PALETTE_REG_FLAGS
Flags which require resolving the action-1-2-3 chain for the palette, even if it is no action-1 palet...
@ TLF_BB_XY_OFFSET
Add signed offset to bounding box X and Y positions from register TileLayoutRegisters::delta....
@ TLF_SPRITE_REG_FLAGS
Flags which require resolving the action-1-2-3 chain for the sprite, even if it is no action-1 sprite...
@ TLF_PALETTE_VAR10
Resolve palette with a specific value in variable 10.
@ TLF_SPRITE_VAR10
Resolve sprite with a specific value in variable 10.
@ TLF_PALETTE
Add signed offset to palette from register TileLayoutRegisters::palette.
@ TLF_CHILD_Y_OFFSET
Add signed offset to child sprite Y positions from register TileLayoutRegisters::delta....
uint GetConstructionStageOffset(uint construction_stage, uint num_sprites)
Determines which sprite to use from a spriteset for a specific construction stage.
GRFConfig * GetGRFConfig(uint32_t grfid, uint32_t mask)
Retrieve a NewGRF from the current config by its grfid.
Functions to find and configure NewGRFs.
@ UnknownCbResult
A callback returned an unknown/invalid result.
std::vector< ObjectSpec > _object_specs
All the object specifications.
Functions related to NewGRF objects.
Action 2 handling.
std::vector< StringParameter > GetGRFStringTextStackParameters(const GRFFile *grffile, StringID stringid, std::span< const int32_t > textstack)
Process the text ref stack for a GRF String and return its parameters.
StringID GetGRFStringID(uint32_t grfid, GRFStringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
uint16_t ObjectType
Types of objects.
Definition object_type.h:16
static const ObjectType OBJECT_TRANSMITTER
The large antenna.
Definition object_type.h:18
RailGroundType
The ground 'under' the rail.
Definition rail_map.h:484
@ HalfTileSnow
Snow only on higher part of slope (steep or one corner raised)
@ SnowOrDesert
Icy or sandy.
bool IsOnSnowOrDesert(Tile t)
Check if a road tile has snow/desert.
Definition road_map.h:441
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition sprites.h:1559
Maps accessors for stations.
bool HasStationTileRail(Tile t)
Has this station tile a rail? In other words, is this station tile a rail station or rail waypoint?
Axis GetRailStationAxis(Tile t)
Get the rail direction of a rail station.
bool IsRoadWaypointTile(Tile t)
Is this tile a station tile and a road waypoint?
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:119
Functions related to low-level strings.
EncodedString GetEncodedStringWithArgs(StringID str, std::span< const StringParameter > params)
Encode a string with its parameters into an encoded string.
Definition strings.cpp:102
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static bool IsValidAiID(auto index)
Is this company a valid company, controlled by the computer (a NoAI program)?
T z
Z coordinate.
A tile child sprite and palette to draw for stations etc, with 3D bounding box.
Definition sprite.h:33
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:53
Maps an entity id stored on the map to a GRF file.
uint16_t substitute_id
The (original) entity ID to use if this GRF is not available.
uint32_t grfid
The GRF ID of the file the entity belongs to.
uint16_t entity_id
The entity ID within the GRF file.
Information about GRF, used in the game and (part of it) in savegames.
GRFBugs grf_bugs
NOSAVE: bugs in this GRF in this run,.
std::string GetName() const
Get the name of this grf.
const struct GRFFile * grffile
grf file that introduced this entity
uint32_t grfid
grfid that introduced this entity.
void SetGRFFile(const struct GRFFile *grffile)
Set the NewGRF file, and its grfid, associated with grf props.
bool HasGrfFile() const
Test if this entity was introduced by NewGRF.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
LandscapeType landscape
the landscape we're currently in
GameCreationSettings game_creation
settings used during the creation of a game (map)
SubstituteGRFFileProps grf_prop
Properties related the the grf file.
Definition house.h:114
static HouseSpec * Get(size_t house_id)
Get the spec for a house ID.
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
Defines the data structure for constructing industry.
SubstituteGRFFileProps grf_prop
properties related to the grf file
bool enabled
entity still available (by default true).newgrf can disable it, though
Defines the data structure of each individual tile of an industry.
SubstituteGRFFileProps grf_prop
properties related to the grf file
bool enabled
entity still available (by default true).newgrf can disable it, though
Information about a particular livery.
Definition livery.h:79
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:88
Colours colour1
First colour, for all vehicles.
Definition livery.h:87
static TileIndex WrapToMap(TileIndex tile)
'Wraps' the given "tile" so it is within the map.
Definition map_func.h:329
NewGRF supplied spritelayout.
void Allocate(uint num_sprites)
Allocate a spritelayout for num_sprites building sprites.
void AllocateRegisters()
Allocate memory for register modifiers.
Allow incrementing of ObjectClassID variables.
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Interface for SpriteGroup-s to access the gamestate.
Coord3D< int8_t > origin
Position of northern corner within tile.
Definition sprite.h:19
uint16_t override_id
id of the entity been replaced by
Additional modifiers for items in sprite layouts.
uint8_t parent[3]
Registers for signed offsets for the bounding box position of parent sprites.
TileLayoutFlags flags
Flags defining which members are valid and to be used.
uint8_t dodraw
Register deciding whether the sprite shall be drawn at all. Non-zero means drawing.
uint16_t max_sprite_offset
Maximum offset to add to the sprite. (limited by size of the spriteset)
uint8_t palette
Register specifying a signed offset for the palette.
uint8_t sprite_var10
Value for variable 10 when resolving the sprite.
uint16_t max_palette_offset
Maximum offset to add to the palette. (limited by size of the spriteset)
uint8_t palette_var10
Value for variable 10 when resolving the palette.
uint8_t child[2]
Registers for signed offsets for the position of child sprites.
uint8_t sprite
Register specifying a signed offset for the sprite.
int GetTileMaxZ(TileIndex t)
Get top height of the tile inside the map.
Definition tile_map.cpp:136
int GetTileZ(TileIndex tile)
Get bottom height of the tile.
Definition tile_map.cpp:116
static bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
std::tuple< Slope, int > GetTilePixelSlope(TileIndex tile)
Return the slope of a given tile.
Definition tile_map.h:289
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
static constexpr uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
TileType
The different types of tiles.
Definition tile_type.h:47
@ MP_TREES
Tile got trees.
Definition tile_type.h:52
@ MP_ROAD
A tile with road (or tram tracks)
Definition tile_type.h:50
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition tile_type.h:57
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:48
@ MP_HOUSE
A house by a town.
Definition tile_type.h:51
@ MP_WATER
Water tile.
Definition tile_type.h:54
@ MP_RAILWAY
A railway.
Definition tile_type.h:49
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
@ MP_OBJECT
Contains objects such as transmitters and owned land.
Definition tile_type.h:58
Map accessors for tree tiles.
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
TreeGround
Enumeration for ground types of tiles with trees.
Definition tree_map.h:52
@ TREE_GROUND_SHORE
shore
Definition tree_map.h:56
@ TREE_GROUND_ROUGH_SNOW
A snow tile that is rough underneath.
Definition tree_map.h:57
@ TREE_GROUND_SNOW_DESERT
a desert or snow tile, depend on landscape
Definition tree_map.h:55
uint GetTreeDensity(Tile t)
Returns the 'density' of a tile with trees.
Definition tree_map.h:127
Functions that have tunnels and bridges in common.
bool HasTunnelBridgeSnowOrDesert(Tile t)
Tunnel: Is this tunnel entrance in a snowy or desert area? Bridge: Does the bridge ramp lie in a snow...
bool HasTileWaterClass(Tile t)
Checks whether the tile has an waterclass associated.
Definition water_map.h:103
WaterClass GetWaterClass(Tile t)
Get the water class at a tile.
Definition water_map.h:114