OpenTTD Source: src/newgrf/newgrf_act2.cpp Source File

OpenTTD Source 15.0-RC2

newgrf_act2.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 <ranges>
12#include "../debug.h"
13#include "../newgrf_engine.h"
14#include "../newgrf_cargo.h"
15#include "../error.h"
16#include "../vehicle_base.h"
17#include "../road.h"
18#include "newgrf_bytereader.h"
19#include "newgrf_internal.h"
20
21#include "table/strings.h"
22
23#include "../safeguards.h"
24
25 constexpr uint16_t GROUPID_CALLBACK_FAILED = 0x7FFF;
26 constexpr uint16_t GROUPID_CALCULATED_RESULT = 0x7FFE;
27
32 void MapSpriteMappingRecolour(PalSpriteID *grf_sprite)
33{
34 if (HasBit(grf_sprite->pal, 14)) {
35 ClrBit(grf_sprite->pal, 14);
36 SetBit(grf_sprite->sprite, SPRITE_MODIFIER_OPAQUE);
37 }
38
39 if (HasBit(grf_sprite->sprite, 14)) {
40 ClrBit(grf_sprite->sprite, 14);
41 SetBit(grf_sprite->sprite, PALETTE_MODIFIER_TRANSPARENT);
42 }
43
44 if (HasBit(grf_sprite->sprite, 15)) {
45 ClrBit(grf_sprite->sprite, 15);
46 SetBit(grf_sprite->sprite, PALETTE_MODIFIER_COLOUR);
47 }
48}
49
63 TileLayoutFlags ReadSpriteLayoutSprite(ByteReader &buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, GrfSpecFeature feature, PalSpriteID *grf_sprite, uint16_t *max_sprite_offset, uint16_t *max_palette_offset)
64{
65 grf_sprite->sprite = buf.ReadWord();
66 grf_sprite->pal = buf.ReadWord();
67 TileLayoutFlags flags = read_flags ? (TileLayoutFlags)buf.ReadWord() : TLF_NOTHING;
68
69 MapSpriteMappingRecolour(grf_sprite);
70
71 bool custom_sprite = HasBit(grf_sprite->pal, 15) != invert_action1_flag;
72 ClrBit(grf_sprite->pal, 15);
73 if (custom_sprite) {
74 /* Use sprite from Action 1 */
75 uint index = GB(grf_sprite->sprite, 0, 14);
76 if (use_cur_spritesets && (!_cur_gps.IsValidSpriteSet(feature, index) || _cur_gps.GetNumEnts(feature, index) == 0)) {
77 GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset {}", index);
78 grf_sprite->sprite = SPR_IMG_QUERY;
79 grf_sprite->pal = PAL_NONE;
80 } else {
81 SpriteID sprite = use_cur_spritesets ? _cur_gps.GetSprite(feature, index) : index;
82 if (max_sprite_offset != nullptr) *max_sprite_offset = use_cur_spritesets ? _cur_gps.GetNumEnts(feature, index) : UINT16_MAX;
83 SB(grf_sprite->sprite, 0, SPRITE_WIDTH, sprite);
84 SetBit(grf_sprite->sprite, SPRITE_MODIFIER_CUSTOM_SPRITE);
85 }
86 } else if ((flags & TLF_SPRITE_VAR10) && !(flags & TLF_SPRITE_REG_FLAGS)) {
87 GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout specifies var10 value for non-action-1 sprite");
88 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
89 return flags;
90 }
91
92 if (flags & TLF_CUSTOM_PALETTE) {
93 /* Use palette from Action 1 */
94 uint index = GB(grf_sprite->pal, 0, 14);
95 if (use_cur_spritesets && (!_cur_gps.IsValidSpriteSet(feature, index) || _cur_gps.GetNumEnts(feature, index) == 0)) {
96 GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset {} for 'palette'", index);
97 grf_sprite->pal = PAL_NONE;
98 } else {
99 SpriteID sprite = use_cur_spritesets ? _cur_gps.GetSprite(feature, index) : index;
100 if (max_palette_offset != nullptr) *max_palette_offset = use_cur_spritesets ? _cur_gps.GetNumEnts(feature, index) : UINT16_MAX;
101 SB(grf_sprite->pal, 0, SPRITE_WIDTH, sprite);
102 SetBit(grf_sprite->pal, SPRITE_MODIFIER_CUSTOM_SPRITE);
103 }
104 } else if ((flags & TLF_PALETTE_VAR10) && !(flags & TLF_PALETTE_REG_FLAGS)) {
105 GrfMsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 value for non-action-1 palette");
106 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
107 return flags;
108 }
109
110 return flags;
111}
112
121 static void ReadSpriteLayoutRegisters(ByteReader &buf, TileLayoutFlags flags, bool is_parent, NewGRFSpriteLayout *dts, uint index)
122{
123 if (!(flags & TLF_DRAWING_FLAGS)) return;
124
125 if (dts->registers.empty()) dts->AllocateRegisters();
126 TileLayoutRegisters &regs = const_cast<TileLayoutRegisters&>(dts->registers[index]);
127 regs.flags = flags & TLF_DRAWING_FLAGS;
128
129 if (flags & TLF_DODRAW) regs.dodraw = buf.ReadByte();
130 if (flags & TLF_SPRITE) regs.sprite = buf.ReadByte();
131 if (flags & TLF_PALETTE) regs.palette = buf.ReadByte();
132
133 if (is_parent) {
134 if (flags & TLF_BB_XY_OFFSET) {
135 regs.delta.parent[0] = buf.ReadByte();
136 regs.delta.parent[1] = buf.ReadByte();
137 }
138 if (flags & TLF_BB_Z_OFFSET) regs.delta.parent[2] = buf.ReadByte();
139 } else {
140 if (flags & TLF_CHILD_X_OFFSET) regs.delta.child[0] = buf.ReadByte();
141 if (flags & TLF_CHILD_Y_OFFSET) regs.delta.child[1] = buf.ReadByte();
142 }
143
144 if (flags & TLF_SPRITE_VAR10) {
145 regs.sprite_var10 = buf.ReadByte();
146 if (regs.sprite_var10 > TLR_MAX_VAR10) {
147 GrfMsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 ({}) exceeding the maximal allowed value {}", regs.sprite_var10, TLR_MAX_VAR10);
148 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
149 return;
150 }
151 }
152
153 if (flags & TLF_PALETTE_VAR10) {
154 regs.palette_var10 = buf.ReadByte();
155 if (regs.palette_var10 > TLR_MAX_VAR10) {
156 GrfMsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 ({}) exceeding the maximal allowed value {}", regs.palette_var10, TLR_MAX_VAR10);
157 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
158 return;
159 }
160 }
161}
162
174 bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_spritesets, GrfSpecFeature feature, bool allow_var10, bool no_z_position, NewGRFSpriteLayout *dts)
175{
176 bool has_flags = HasBit(num_building_sprites, 6);
177 ClrBit(num_building_sprites, 6);
178 TileLayoutFlags valid_flags = TLF_KNOWN_FLAGS;
179 if (!allow_var10) valid_flags &= ~TLF_VAR10_FLAGS;
180 dts->Allocate(num_building_sprites); // allocate before reading groundsprite flags
181
182 std::vector<uint16_t> max_sprite_offset(num_building_sprites + 1, 0);
183 std::vector<uint16_t> max_palette_offset(num_building_sprites + 1, 0);
184
185 /* Groundsprite */
186 TileLayoutFlags flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &dts->ground, max_sprite_offset.data(), max_palette_offset.data());
187 if (_cur_gps.skip_sprites < 0) return true;
188
189 if (flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS)) {
190 GrfMsg(1, "ReadSpriteLayout: Spritelayout uses invalid flag 0x{:X} for ground sprite", flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS));
191 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
192 return true;
193 }
194
195 ReadSpriteLayoutRegisters(buf, flags, false, dts, 0);
196 if (_cur_gps.skip_sprites < 0) return true;
197
198 for (uint i = 0; i < num_building_sprites; i++) {
199 DrawTileSeqStruct *seq = const_cast<DrawTileSeqStruct*>(&dts->seq[i]);
200
201 flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &seq->image, max_sprite_offset.data() + i + 1, max_palette_offset.data() + i + 1);
202 if (_cur_gps.skip_sprites < 0) return true;
203
204 if (flags & ~valid_flags) {
205 GrfMsg(1, "ReadSpriteLayout: Spritelayout uses unknown flag 0x{:X}", flags & ~valid_flags);
206 DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT);
207 return true;
208 }
209
210 seq->origin.x = buf.ReadByte();
211 seq->origin.y = buf.ReadByte();
212
213 if (!no_z_position) seq->origin.z = buf.ReadByte();
214
215 if (seq->IsParentSprite()) {
216 seq->extent.x = buf.ReadByte();
217 seq->extent.y = buf.ReadByte();
218 seq->extent.z = buf.ReadByte();
219 }
220
221 ReadSpriteLayoutRegisters(buf, flags, seq->IsParentSprite(), dts, i + 1);
222 if (_cur_gps.skip_sprites < 0) return true;
223 }
224
225 /* Check if the number of sprites per spriteset is consistent */
226 bool is_consistent = true;
227 dts->consistent_max_offset = 0;
228 for (uint i = 0; i < num_building_sprites + 1; i++) {
229 if (max_sprite_offset[i] > 0) {
230 if (dts->consistent_max_offset == 0) {
231 dts->consistent_max_offset = max_sprite_offset[i];
232 } else if (dts->consistent_max_offset != max_sprite_offset[i]) {
233 is_consistent = false;
234 break;
235 }
236 }
237 if (max_palette_offset[i] > 0) {
238 if (dts->consistent_max_offset == 0) {
239 dts->consistent_max_offset = max_palette_offset[i];
240 } else if (dts->consistent_max_offset != max_palette_offset[i]) {
241 is_consistent = false;
242 break;
243 }
244 }
245 }
246
247 /* When the Action1 sets are unknown, everything should be 0 (no spriteset usage) or UINT16_MAX (some spriteset usage) */
248 assert(use_cur_spritesets || (is_consistent && (dts->consistent_max_offset == 0 || dts->consistent_max_offset == UINT16_MAX)));
249
250 if (!is_consistent || !dts->registers.empty()) {
251 dts->consistent_max_offset = 0;
252 if (dts->registers.empty()) dts->AllocateRegisters();
253
254 for (uint i = 0; i < num_building_sprites + 1; i++) {
255 TileLayoutRegisters &regs = const_cast<TileLayoutRegisters&>(dts->registers[i]);
256 regs.max_sprite_offset = max_sprite_offset[i];
257 regs.max_palette_offset = max_palette_offset[i];
258 }
259 }
260
261 return false;
262}
263
264using CachedCallback = std::pair<uint16_t, SpriteGroupID>;
265 static std::vector<CachedCallback> _cached_callback_groups;
266
267void ResetCallbacks(bool final)
268{
269 _cached_callback_groups.clear();
270 if (final) _cached_callback_groups.shrink_to_fit();
271}
272
273static const SpriteGroup *GetCallbackResultGroup(uint16_t value)
274{
275 /* Old style callback results (only valid for version < 8) have the highest byte 0xFF to signify it is a callback result.
276 * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */
277 if (_cur_gps.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) {
278 value &= ~0xFF00;
279 } else {
280 value &= ~0x8000;
281 }
282
283 /* Find position for value within the cached callback list. */
284 auto it = std::ranges::lower_bound(_cached_callback_groups, value, std::less{}, &CachedCallback::first);
285 if (it != std::end(_cached_callback_groups) && it->first == value) return SpriteGroup::Get(it->second);
286
287 /* Result value is not present, so make it and add to cache. */
288 assert(CallbackResultSpriteGroup::CanAllocateItem());
289 const SpriteGroup *group = new CallbackResultSpriteGroup(value);
290 it = _cached_callback_groups.emplace(it, value, group->index);
291 return group;
292}
293
294/* Helper function to either create a callback or link to a previously
295 * defined spritegroup. */
296static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint16_t groupid)
297{
298 if (HasBit(groupid, 15)) return GetCallbackResultGroup(groupid);
299 if (groupid == GROUPID_CALLBACK_FAILED) return nullptr;
300
301 if (groupid > MAX_SPRITEGROUP || _cur_gps.spritegroups[groupid] == nullptr) {
302 GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid);
303 return nullptr;
304 }
305
306 return _cur_gps.spritegroups[groupid];
307}
308
317 static const SpriteGroup *CreateGroupFromGroupID(GrfSpecFeature feature, uint8_t setid, uint8_t type, uint16_t spriteid)
318{
319 if (HasBit(spriteid, 15)) return GetCallbackResultGroup(spriteid);
320
321 if (!_cur_gps.IsValidSpriteSet(feature, spriteid)) {
322 GrfMsg(1, "CreateGroupFromGroupID(0x{:02X}:0x{:02X}): Sprite set {} invalid", setid, type, spriteid);
323 return nullptr;
324 }
325
326 SpriteID spriteset_start = _cur_gps.GetSprite(feature, spriteid);
327 uint num_sprites = _cur_gps.GetNumEnts(feature, spriteid);
328
329 /* Ensure that the sprites are loeded */
330 assert(spriteset_start + num_sprites <= _cur_gps.spriteid);
331
332 assert(ResultSpriteGroup::CanAllocateItem());
333 return new ResultSpriteGroup(spriteset_start, num_sprites);
334}
335
336/* Action 0x02 */
337static void NewSpriteGroup(ByteReader &buf)
338{
339 /* <02> <feature> <set-id> <type/num-entries> <feature-specific-data...>
340 *
341 * B feature see action 1
342 * B set-id ID of this particular definition
343 * B type/num-entries
344 * if 80 or greater, this is a randomized or variational
345 * list definition, see below
346 * otherwise it specifies a number of entries, the exact
347 * meaning depends on the feature
348 * V feature-specific-data (huge mess, don't even look it up --pasky) */
349 const SpriteGroup *act_group = nullptr;
350
351 GrfSpecFeature feature{buf.ReadByte()};
352 if (feature >= GSF_END) {
353 GrfMsg(1, "NewSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
354 return;
355 }
356
357 uint8_t setid = buf.ReadByte();
358 uint8_t type = buf.ReadByte();
359
360 /* Sprite Groups are created here but they are allocated from a pool, so
361 * we do not need to delete anything if there is an exception from the
362 * ByteReader. */
363
364 switch (type) {
365 /* Deterministic Sprite Group */
366 case 0x81: // Self scope, byte
367 case 0x82: // Parent scope, byte
368 case 0x85: // Self scope, word
369 case 0x86: // Parent scope, word
370 case 0x89: // Self scope, dword
371 case 0x8A: // Parent scope, dword
372 {
373 uint8_t varadjust;
374 uint8_t varsize;
375
376 assert(DeterministicSpriteGroup::CanAllocateItem());
377 DeterministicSpriteGroup *group = new DeterministicSpriteGroup();
378 group->nfo_line = _cur_gps.nfo_line;
379 act_group = group;
380 group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
381
382 switch (GB(type, 2, 2)) {
383 default: NOT_REACHED();
384 case 0: group->size = DSG_SIZE_BYTE; varsize = 1; break;
385 case 1: group->size = DSG_SIZE_WORD; varsize = 2; break;
386 case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break;
387 }
388
389 /* Loop through the var adjusts. Unfortunately we don't know how many we have
390 * from the outset, so we shall have to keep reallocing. */
391 do {
392 DeterministicSpriteGroupAdjust &adjust = group->adjusts.emplace_back();
393
394 /* The first var adjust doesn't have an operation specified, so we set it to add. */
395 adjust.operation = group->adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf.ReadByte();
396 adjust.variable = buf.ReadByte();
397 if (adjust.variable == 0x7E) {
398 /* Link subroutine group */
399 adjust.subroutine = GetGroupFromGroupID(setid, type, buf.ReadByte());
400 } else {
401 adjust.parameter = IsInsideMM(adjust.variable, 0x60, 0x80) ? buf.ReadByte() : 0;
402 }
403
404 varadjust = buf.ReadByte();
405 adjust.shift_num = GB(varadjust, 0, 5);
406 adjust.type = (DeterministicSpriteGroupAdjustType)GB(varadjust, 6, 2);
407 adjust.and_mask = buf.ReadVarSize(varsize);
408
409 if (adjust.type != DSGA_TYPE_NONE) {
410 adjust.add_val = buf.ReadVarSize(varsize);
411 adjust.divmod_val = buf.ReadVarSize(varsize);
412 if (adjust.divmod_val == 0) adjust.divmod_val = 1; // Ensure that divide by zero cannot occur
413 } else {
414 adjust.add_val = 0;
415 adjust.divmod_val = 0;
416 }
417
418 /* Continue reading var adjusts while bit 5 is set. */
419 } while (HasBit(varadjust, 5));
420
421 std::vector<DeterministicSpriteGroupRange> ranges;
422 ranges.resize(buf.ReadByte());
423 for (auto &range : ranges) {
424 auto groupid = buf.ReadWord();
425 if (groupid == GROUPID_CALCULATED_RESULT) {
426 range.result.calculated_result = true;
427 } else {
428 range.result.group = GetGroupFromGroupID(setid, type, groupid);
429 }
430 range.low = buf.ReadVarSize(varsize);
431 range.high = buf.ReadVarSize(varsize);
432 }
433
434 auto defgroupid = buf.ReadWord();
435 if (defgroupid == GROUPID_CALCULATED_RESULT) {
436 group->default_result.calculated_result = true;
437 } else {
438 group->default_result.group = GetGroupFromGroupID(setid, type, defgroupid);
439 }
440 /* 'calculated_result' makes no sense for the 'error' case. Use callback failure (nullptr) instead */
441 group->error_group = ranges.empty() ? group->default_result.group : ranges[0].result.group;
442 /* nvar == 0 is a special case:
443 * - set "default_result" to "calculated_result".
444 * - the old value specifies the "error_group". */
445 if (ranges.empty()) {
446 group->default_result.calculated_result = true;
447 group->default_result.group = nullptr;
448 }
449
450 /* Sort ranges ascending. When ranges overlap, this may required clamping or splitting them */
451 std::vector<uint32_t> bounds;
452 bounds.reserve(ranges.size());
453 for (const auto &range : ranges) {
454 bounds.push_back(range.low);
455 if (range.high != UINT32_MAX) bounds.push_back(range.high + 1);
456 }
457 std::sort(bounds.begin(), bounds.end());
458 bounds.erase(std::unique(bounds.begin(), bounds.end()), bounds.end());
459
460 std::vector<DeterministicSpriteGroupResult> target;
461 target.reserve(bounds.size());
462 for (const auto &bound : bounds) {
463 auto t = group->default_result;
464 for (const auto &range : ranges) {
465 if (range.low <= bound && bound <= range.high) {
466 t = range.result;
467 break;
468 }
469 }
470 target.push_back(t);
471 }
472 assert(target.size() == bounds.size());
473
474 for (uint j = 0; j < bounds.size(); ) {
475 if (target[j] != group->default_result) {
476 DeterministicSpriteGroupRange &r = group->ranges.emplace_back();
477 r.result = target[j];
478 r.low = bounds[j];
479 while (j < bounds.size() && target[j] == r.result) {
480 j++;
481 }
482 r.high = j < bounds.size() ? bounds[j] - 1 : UINT32_MAX;
483 } else {
484 j++;
485 }
486 }
487
488 break;
489 }
490
491 /* Randomized Sprite Group */
492 case 0x80: // Self scope
493 case 0x83: // Parent scope
494 case 0x84: // Relative scope
495 {
496 assert(RandomizedSpriteGroup::CanAllocateItem());
497 RandomizedSpriteGroup *group = new RandomizedSpriteGroup();
498 group->nfo_line = _cur_gps.nfo_line;
499 act_group = group;
500 group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF;
501
502 if (HasBit(type, 2)) {
503 if (feature <= GSF_AIRCRAFT) group->var_scope = VSG_SCOPE_RELATIVE;
504 group->count = buf.ReadByte();
505 }
506
507 uint8_t triggers = buf.ReadByte();
508 group->triggers = GB(triggers, 0, 7);
509 group->cmp_mode = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY;
510 group->lowest_randbit = buf.ReadByte();
511
512 uint8_t num_groups = buf.ReadByte();
513 if (!HasExactlyOneBit(num_groups)) {
514 GrfMsg(1, "NewSpriteGroup: Random Action 2 nrand should be power of 2");
515 }
516
517 group->groups.reserve(num_groups);
518 for (uint i = 0; i < num_groups; i++) {
519 group->groups.push_back(GetGroupFromGroupID(setid, type, buf.ReadWord()));
520 }
521
522 break;
523 }
524
525 /* Neither a variable or randomized sprite group... must be a real group */
526 default:
527 {
528 if (type >= 0x80) {
529 GrfMsg(0, "NewSpriteGroup: Reserved group type 0x{:02X}, skipping", type);
530 return;
531 }
532
533 switch (feature) {
534 case GSF_TRAINS:
535 case GSF_ROADVEHICLES:
536 case GSF_SHIPS:
537 case GSF_AIRCRAFT:
538 case GSF_STATIONS:
539 case GSF_CANALS:
540 case GSF_CARGOES:
541 case GSF_AIRPORTS:
542 case GSF_RAILTYPES:
543 case GSF_ROADTYPES:
544 case GSF_TRAMTYPES:
545 case GSF_BADGES:
546 {
547 uint8_t num_loaded = type;
548 uint8_t num_loading = buf.ReadByte();
549
550 if (!_cur_gps.HasValidSpriteSets(feature)) {
551 GrfMsg(0, "NewSpriteGroup: No sprite set to work on! Skipping");
552 return;
553 }
554
555 GrfMsg(6, "NewSpriteGroup: New SpriteGroup 0x{:02X}, {} loaded, {} loading",
556 setid, num_loaded, num_loading);
557
558 if (num_loaded + num_loading == 0) {
559 GrfMsg(1, "NewSpriteGroup: no result, skipping invalid RealSpriteGroup");
560 break;
561 }
562
563 if (num_loaded + num_loading == 1) {
564 /* Avoid creating 'Real' sprite group if only one option. */
565 uint16_t spriteid = buf.ReadWord();
566 act_group = CreateGroupFromGroupID(feature, setid, type, spriteid);
567 GrfMsg(8, "NewSpriteGroup: one result, skipping RealSpriteGroup = subset {}", spriteid);
568 break;
569 }
570
571 std::vector<uint16_t> loaded;
572 std::vector<uint16_t> loading;
573
574 loaded.reserve(num_loaded);
575 for (uint i = 0; i < num_loaded; i++) {
576 loaded.push_back(buf.ReadWord());
577 GrfMsg(8, "NewSpriteGroup: + rg->loaded[{}] = subset {}", i, loaded[i]);
578 }
579
580 loading.reserve(num_loading);
581 for (uint i = 0; i < num_loading; i++) {
582 loading.push_back(buf.ReadWord());
583 GrfMsg(8, "NewSpriteGroup: + rg->loading[{}] = subset {}", i, loading[i]);
584 }
585
586 bool loaded_same = !loaded.empty() && std::adjacent_find(loaded.begin(), loaded.end(), std::not_equal_to<>()) == loaded.end();
587 bool loading_same = !loading.empty() && std::adjacent_find(loading.begin(), loading.end(), std::not_equal_to<>()) == loading.end();
588 if (loaded_same && loading_same && loaded[0] == loading[0]) {
589 /* Both lists only contain the same value, so don't create 'Real' sprite group */
590 act_group = CreateGroupFromGroupID(feature, setid, type, loaded[0]);
591 GrfMsg(8, "NewSpriteGroup: same result, skipping RealSpriteGroup = subset {}", loaded[0]);
592 break;
593 }
594
595 assert(RealSpriteGroup::CanAllocateItem());
596 RealSpriteGroup *group = new RealSpriteGroup();
597 group->nfo_line = _cur_gps.nfo_line;
598 act_group = group;
599
600 if (loaded_same && loaded.size() > 1) loaded.resize(1);
601 group->loaded.reserve(loaded.size());
602 for (uint16_t spriteid : loaded) {
603 const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid);
604 group->loaded.push_back(t);
605 }
606
607 if (loading_same && loading.size() > 1) loading.resize(1);
608 group->loading.reserve(loading.size());
609 for (uint16_t spriteid : loading) {
610 const SpriteGroup *t = CreateGroupFromGroupID(feature, setid, type, spriteid);
611 group->loading.push_back(t);
612 }
613
614 break;
615 }
616
617 case GSF_HOUSES:
618 case GSF_AIRPORTTILES:
619 case GSF_OBJECTS:
620 case GSF_INDUSTRYTILES:
621 case GSF_ROADSTOPS: {
622 uint8_t num_building_sprites = std::max((uint8_t)1, type);
623
624 assert(TileLayoutSpriteGroup::CanAllocateItem());
625 TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup();
626 group->nfo_line = _cur_gps.nfo_line;
627 act_group = group;
628
629 /* On error, bail out immediately. Temporary GRF data was already freed */
630 if (ReadSpriteLayout(buf, num_building_sprites, true, feature, false, type == 0, &group->dts)) return;
631 break;
632 }
633
634 case GSF_INDUSTRIES: {
635 if (type > 2) {
636 GrfMsg(1, "NewSpriteGroup: Unsupported industry production version {}, skipping", type);
637 break;
638 }
639
640 assert(IndustryProductionSpriteGroup::CanAllocateItem());
641 IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup();
642 group->nfo_line = _cur_gps.nfo_line;
643 act_group = group;
644 group->version = type;
645 if (type == 0) {
646 group->num_input = INDUSTRY_ORIGINAL_NUM_INPUTS;
647 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) {
648 group->subtract_input[i] = (int16_t)buf.ReadWord(); // signed
649 }
650 group->num_output = INDUSTRY_ORIGINAL_NUM_OUTPUTS;
651 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_OUTPUTS; i++) {
652 group->add_output[i] = buf.ReadWord(); // unsigned
653 }
654 group->again = buf.ReadByte();
655 } else if (type == 1) {
656 group->num_input = INDUSTRY_ORIGINAL_NUM_INPUTS;
657 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_INPUTS; i++) {
658 group->subtract_input[i] = buf.ReadByte();
659 }
660 group->num_output = INDUSTRY_ORIGINAL_NUM_OUTPUTS;
661 for (uint i = 0; i < INDUSTRY_ORIGINAL_NUM_OUTPUTS; i++) {
662 group->add_output[i] = buf.ReadByte();
663 }
664 group->again = buf.ReadByte();
665 } else if (type == 2) {
666 group->num_input = buf.ReadByte();
667 if (group->num_input > std::size(group->subtract_input)) {
668 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
669 error->data = "too many inputs (max 16)";
670 return;
671 }
672 for (uint i = 0; i < group->num_input; i++) {
673 uint8_t rawcargo = buf.ReadByte();
674 CargoType cargo = GetCargoTranslation(rawcargo, _cur_gps.grffile);
675 if (!IsValidCargoType(cargo)) {
676 /* The mapped cargo is invalid. This is permitted at this point,
677 * as long as the result is not used. Mark it invalid so this
678 * can be tested later. */
679 group->version = 0xFF;
680 } else if (auto v = group->cargo_input | std::views::take(i); std::ranges::find(v, cargo) != v.end()) {
681 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
682 error->data = "duplicate input cargo";
683 return;
684 }
685 group->cargo_input[i] = cargo;
686 group->subtract_input[i] = buf.ReadByte();
687 }
688 group->num_output = buf.ReadByte();
689 if (group->num_output > std::size(group->add_output)) {
690 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
691 error->data = "too many outputs (max 16)";
692 return;
693 }
694 for (uint i = 0; i < group->num_output; i++) {
695 uint8_t rawcargo = buf.ReadByte();
696 CargoType cargo = GetCargoTranslation(rawcargo, _cur_gps.grffile);
697 if (!IsValidCargoType(cargo)) {
698 /* Mark this result as invalid to use */
699 group->version = 0xFF;
700 } else if (auto v = group->cargo_output | std::views::take(i); std::ranges::find(v, cargo) != v.end()) {
701 GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
702 error->data = "duplicate output cargo";
703 return;
704 }
705 group->cargo_output[i] = cargo;
706 group->add_output[i] = buf.ReadByte();
707 }
708 group->again = buf.ReadByte();
709 } else {
710 NOT_REACHED();
711 }
712 break;
713 }
714
715 /* Loading of Tile Layout and Production Callback groups would happen here */
716 default: GrfMsg(1, "NewSpriteGroup: Unsupported feature 0x{:02X}, skipping", feature);
717 }
718 }
719 }
720
721 _cur_gps.spritegroups[setid] = act_group;
722}
723
724template <> void GrfActionHandler<0x02>::FileScan(ByteReader &) { }
725template <> void GrfActionHandler<0x02>::SafetyScan(ByteReader &) { }
726template <> void GrfActionHandler<0x02>::LabelScan(ByteReader &) { }
727template <> void GrfActionHandler<0x02>::Init(ByteReader &) { }
728template <> void GrfActionHandler<0x02>::Reserve(ByteReader &) { }
729template <> void GrfActionHandler<0x02>::Activation(ByteReader &buf) { NewSpriteGroup(buf); }
HasExactlyOneBit
constexpr bool HasExactlyOneBit(T value)
Test whether value has exactly 1 bit set.
Definition bitmath_func.hpp:254
SB
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.
Definition bitmath_func.hpp:58
GB
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
Definition bitmath_func.hpp:32
SetBit
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
Definition bitmath_func.hpp:121
HasBit
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
Definition bitmath_func.hpp:103
ClrBit
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
Definition bitmath_func.hpp:139
CargoType
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:21
IsValidCargoType
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:104
ByteReader
Class to read from a NewGRF file.
Definition newgrf_bytereader.h:18
ByteReader::ReadWord
uint16_t ReadWord()
Read a single Word (16 bits).
Definition newgrf_bytereader.h:45
ByteReader::ReadVarSize
uint32_t ReadVarSize(uint8_t size)
Read a value of the given number of bytes.
Definition newgrf_bytereader.cpp:20
ByteReader::ReadByte
uint8_t ReadByte()
Read a single byte (8 bits).
Definition newgrf_bytereader.h:34
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
INDUSTRY_ORIGINAL_NUM_INPUTS
static const int INDUSTRY_ORIGINAL_NUM_INPUTS
Original number of accepted cargo types.
Definition industry_type.h:59
INDUSTRY_ORIGINAL_NUM_OUTPUTS
static const int INDUSTRY_ORIGINAL_NUM_OUTPUTS
Original number of produced cargo types.
Definition industry_type.h:60
IsInsideMM
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
Definition math_func.hpp:267
DisableGrf
GRFError * DisableGrf(StringID message, GRFConfig *config)
Disable a GRF.
Definition newgrf.cpp:135
GrfSpecFeature
GrfSpecFeature
Definition newgrf.h:68
GROUPID_CALLBACK_FAILED
constexpr uint16_t GROUPID_CALLBACK_FAILED
Explicit "failure" result.
Definition newgrf_act2.cpp:25
GROUPID_CALCULATED_RESULT
constexpr uint16_t GROUPID_CALCULATED_RESULT
Return calculated result from VarAction2.
Definition newgrf_act2.cpp:26
ReadSpriteLayoutSprite
TileLayoutFlags ReadSpriteLayoutSprite(ByteReader &buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, GrfSpecFeature feature, PalSpriteID *grf_sprite, uint16_t *max_sprite_offset, uint16_t *max_palette_offset)
Read a sprite and a palette from the GRF and convert them into a format suitable to OpenTTD.
Definition newgrf_act2.cpp:63
ReadSpriteLayoutRegisters
static void ReadSpriteLayoutRegisters(ByteReader &buf, TileLayoutFlags flags, bool is_parent, NewGRFSpriteLayout *dts, uint index)
Preprocess the TileLayoutFlags and read register modifiers from the GRF.
Definition newgrf_act2.cpp:121
ReadSpriteLayout
bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_spritesets, GrfSpecFeature feature, bool allow_var10, bool no_z_position, NewGRFSpriteLayout *dts)
Read a spritelayout from the GRF.
Definition newgrf_act2.cpp:174
MapSpriteMappingRecolour
void MapSpriteMappingRecolour(PalSpriteID *grf_sprite)
Map the colour modifiers of TTDPatch to those that Open is using.
Definition newgrf_act2.cpp:32
_cached_callback_groups
static std::vector< CachedCallback > _cached_callback_groups
Sorted list of cached callback result spritegroups.
Definition newgrf_act2.cpp:265
CreateGroupFromGroupID
static const SpriteGroup * CreateGroupFromGroupID(GrfSpecFeature feature, uint8_t setid, uint8_t type, uint16_t spriteid)
Helper function to either create a callback or a result sprite group.
Definition newgrf_act2.cpp:317
newgrf_bytereader.h
NewGRF buffer reader definition.
GetCargoTranslation
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Definition newgrf_cargo.cpp:80
TileLayoutFlags
TileLayoutFlags
Flags to enable register usage in sprite layouts.
Definition newgrf_commons.h:33
TLF_BB_Z_OFFSET
@ TLF_BB_Z_OFFSET
Add signed offset to bounding box Z positions from register TileLayoutRegisters::delta....
Definition newgrf_commons.h:42
TLF_CUSTOM_PALETTE
@ TLF_CUSTOM_PALETTE
Palette is from Action 1 (moved to SPRITE_MODIFIER_CUSTOM_SPRITE in palette during loading).
Definition newgrf_commons.h:39
TLF_SPRITE
@ TLF_SPRITE
Add signed offset to sprite from register TileLayoutRegisters::sprite.
Definition newgrf_commons.h:37
TLF_CHILD_X_OFFSET
@ TLF_CHILD_X_OFFSET
Add signed offset to child sprite X positions from register TileLayoutRegisters::delta....
Definition newgrf_commons.h:44
TLF_DRAWING_FLAGS
@ TLF_DRAWING_FLAGS
Flags which are still required after loading the GRF.
Definition newgrf_commons.h:53
TLF_DODRAW
@ TLF_DODRAW
Only draw sprite if value of register TileLayoutRegisters::dodraw is non-zero.
Definition newgrf_commons.h:36
TLF_PALETTE_REG_FLAGS
@ 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...
Definition newgrf_commons.h:65
TLF_NON_GROUND_FLAGS
@ TLF_NON_GROUND_FLAGS
Flags which do not work for the (first) ground sprite.
Definition newgrf_commons.h:56
TLF_BB_XY_OFFSET
@ TLF_BB_XY_OFFSET
Add signed offset to bounding box X and Y positions from register TileLayoutRegisters::delta....
Definition newgrf_commons.h:41
TLF_SPRITE_REG_FLAGS
@ 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...
Definition newgrf_commons.h:62
TLF_PALETTE_VAR10
@ TLF_PALETTE_VAR10
Resolve palette with a specific value in variable 10.
Definition newgrf_commons.h:48
TLF_SPRITE_VAR10
@ TLF_SPRITE_VAR10
Resolve sprite with a specific value in variable 10.
Definition newgrf_commons.h:47
TLF_KNOWN_FLAGS
@ TLF_KNOWN_FLAGS
Known flags. Any unknown set flag will disable the GRF.
Definition newgrf_commons.h:50
TLF_PALETTE
@ TLF_PALETTE
Add signed offset to palette from register TileLayoutRegisters::palette.
Definition newgrf_commons.h:38
TLF_CHILD_Y_OFFSET
@ TLF_CHILD_Y_OFFSET
Add signed offset to child sprite Y positions from register TileLayoutRegisters::delta....
Definition newgrf_commons.h:45
TLR_MAX_VAR10
static const uint TLR_MAX_VAR10
Maximum value for var 10.
Definition newgrf_commons.h:106
newgrf_internal.h
NewGRF internal processing state.
MAX_SPRITEGROUP
static constexpr uint MAX_SPRITEGROUP
Maximum GRF-local ID for a spritegroup.
Definition newgrf_internal.h:46
DeterministicSpriteGroupAdjustOperation
DeterministicSpriteGroupAdjustOperation
Definition newgrf_spritegroup.h:105
DSGA_OP_ADD
@ DSGA_OP_ADD
a + b
Definition newgrf_spritegroup.h:106
VSG_SCOPE_SELF
@ VSG_SCOPE_SELF
Resolved object itself.
Definition newgrf_spritegroup.h:85
VSG_SCOPE_PARENT
@ VSG_SCOPE_PARENT
Related object of the resolved one.
Definition newgrf_spritegroup.h:86
VSG_SCOPE_RELATIVE
@ VSG_SCOPE_RELATIVE
Relative position (vehicles only)
Definition newgrf_spritegroup.h:87
SPRITE_MODIFIER_OPAQUE
static constexpr uint8_t SPRITE_MODIFIER_OPAQUE
Set when a sprite must not ever be displayed transparently.
Definition sprites.h:1560
PALETTE_MODIFIER_TRANSPARENT
static constexpr uint8_t PALETTE_MODIFIER_TRANSPARENT
when a sprite is to be displayed transparently, this bit needs to be set.
Definition sprites.h:1561
SPRITE_MODIFIER_CUSTOM_SPRITE
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition sprites.h:1559
SPRITE_WIDTH
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition sprites.h:1549
PALETTE_MODIFIER_COLOUR
static constexpr uint8_t PALETTE_MODIFIER_COLOUR
this bit is set when a recolouring process is in action
Definition sprites.h:1562
CallbackResultSpriteGroup
Definition newgrf_spritegroup.h:201
Coord3D::x
T x
X coordinate.
Definition geometry_type.hpp:44
Coord3D::y
T y
Y coordinate.
Definition geometry_type.hpp:45
Coord3D::z
T z
Z coordinate.
Definition geometry_type.hpp:46
DeterministicSpriteGroupAdjust
Definition newgrf_spritegroup.h:132
DeterministicSpriteGroupAdjust::parameter
uint8_t parameter
Used for variables between 0x60 and 0x7F inclusive.
Definition newgrf_spritegroup.h:136
DeterministicSpriteGroupRange
Definition newgrf_spritegroup.h:152
DeterministicSpriteGroup
Definition newgrf_spritegroup.h:159
DrawTileSeqStruct
A tile child sprite and palette to draw for stations etc, with 3D bounding box.
Definition sprite.h:33
DrawTileSeqStruct::IsParentSprite
bool IsParentSprite() const
Check whether this is a parent sprite with a boundingbox.
Definition sprite.h:41
DrawTileSprites::ground
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:53
GRFError
Information about why GRF had problems during initialisation.
Definition newgrf_config.h:109
GRFError::data
std::string data
Additional data for message and custom_message.
Definition newgrf_config.h:114
GrfActionHandler
GRF action handler.
Definition newgrf_internal.h:37
GrfProcessingState::grffile
GRFFile * grffile
Currently processed GRF file.
Definition newgrf_internal.h:67
GrfProcessingState::HasValidSpriteSets
bool HasValidSpriteSets(GrfSpecFeature feature) const
Check whether there are any valid spritesets for a feature.
Definition newgrf_internal.h:114
GrfProcessingState::nfo_line
uint32_t nfo_line
Currently processed pseudo sprite number in the GRF.
Definition newgrf_internal.h:69
GrfProcessingState::GetSprite
SpriteID GetSprite(GrfSpecFeature feature, uint set) const
Returns the first sprite of a spriteset.
Definition newgrf_internal.h:139
GrfProcessingState::spriteid
SpriteID spriteid
First available SpriteID for loading realsprites.
Definition newgrf_internal.h:63
GrfProcessingState::IsValidSpriteSet
bool IsValidSpriteSet(GrfSpecFeature feature, uint set) const
Check whether a specific set is defined.
Definition newgrf_internal.h:127
GrfProcessingState::GetNumEnts
uint GetNumEnts(GrfSpecFeature feature, uint set) const
Returns the number of sprites in a spriteset.
Definition newgrf_internal.h:151
GrfProcessingState::skip_sprites
int skip_sprites
Number of pseudo sprites to skip before processing the next one. (-1 to skip to end of file)
Definition newgrf_internal.h:72
IndustryProductionSpriteGroup
Definition newgrf_spritegroup.h:247
IndustryProductionSpriteGroup::add_output
std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > add_output
Add this much output cargo when successful (unsigned, is indirect in cb version 1+)
Definition newgrf_spritegroup.h:255
IndustryProductionSpriteGroup::cargo_output
std::array< CargoType, INDUSTRY_NUM_OUTPUTS > cargo_output
Which output cargoes to add to (only cb version 2)
Definition newgrf_spritegroup.h:256
IndustryProductionSpriteGroup::cargo_input
std::array< CargoType, INDUSTRY_NUM_INPUTS > cargo_input
Which input cargoes to take from (only cb version 2)
Definition newgrf_spritegroup.h:253
IndustryProductionSpriteGroup::subtract_input
std::array< int16_t, INDUSTRY_NUM_INPUTS > subtract_input
Take this much of the input cargo (can be negative, is indirect in cb version 1+)
Definition newgrf_spritegroup.h:252
IndustryProductionSpriteGroup::num_input
uint8_t num_input
How many subtract_input values are valid.
Definition newgrf_spritegroup.h:251
IndustryProductionSpriteGroup::version
uint8_t version
Production callback version used, or 0xFF if marked invalid.
Definition newgrf_spritegroup.h:250
IndustryProductionSpriteGroup::num_output
uint8_t num_output
How many add_output values are valid.
Definition newgrf_spritegroup.h:254
NewGRFSpriteLayout
NewGRF supplied spritelayout.
Definition newgrf_commons.h:113
NewGRFSpriteLayout::Allocate
void Allocate(uint num_sprites)
Allocate a spritelayout for num_sprites building sprites.
Definition newgrf_commons.cpp:576
NewGRFSpriteLayout::consistent_max_offset
uint consistent_max_offset
Number of sprites in all referenced spritesets.
Definition newgrf_commons.h:121
NewGRFSpriteLayout::AllocateRegisters
void AllocateRegisters()
Allocate memory for register modifiers.
Definition newgrf_commons.cpp:586
PalSpriteID
Combination of a palette sprite and a 'real' sprite.
Definition gfx_type.h:22
PalSpriteID::sprite
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PalSpriteID::pal
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
Pool::PoolItem<&_spritegroup_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_spritegroup_pool >::CanAllocateItem
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition pool_type.hpp:357
RandomizedSpriteGroup
Definition newgrf_spritegroup.h:181
RandomizedSpriteGroup::lowest_randbit
uint8_t lowest_randbit
Look for this in the per-object randomized bitmask:
Definition newgrf_spritegroup.h:190
RandomizedSpriteGroup::var_scope
VarSpriteGroupScope var_scope
Take this object:
Definition newgrf_spritegroup.h:184
RandomizedSpriteGroup::groups
std::vector< const SpriteGroup * > groups
Take the group with appropriate index:
Definition newgrf_spritegroup.h:192
RandomizedSpriteGroup::cmp_mode
RandomizedSpriteGroupCompareMode cmp_mode
Check for these triggers:
Definition newgrf_spritegroup.h:186
RealSpriteGroup
Definition newgrf_spritegroup.h:64
RealSpriteGroup::loaded
std::vector< const SpriteGroup * > loaded
List of loaded groups (can be SpriteIDs or Callback results)
Definition newgrf_spritegroup.h:74
RealSpriteGroup::loading
std::vector< const SpriteGroup * > loading
List of loading groups (can be SpriteIDs or Callback results)
Definition newgrf_spritegroup.h:75
ResultSpriteGroup
Definition newgrf_spritegroup.h:217
SpriteBounds::origin
Coord3D< int8_t > origin
Position of northern corner within tile.
Definition sprite.h:19
SpriteBounds::extent
Coord3D< uint8_t > extent
Size of bounding box.
Definition sprite.h:20
SpriteGroup
Definition newgrf_spritegroup.h:47
TileLayoutRegisters
Additional modifiers for items in sprite layouts.
Definition newgrf_commons.h:91
TileLayoutRegisters::parent
uint8_t parent[3]
Registers for signed offsets for the bounding box position of parent sprites.
Definition newgrf_commons.h:99
TileLayoutRegisters::flags
TileLayoutFlags flags
Flags defining which members are valid and to be used.
Definition newgrf_commons.h:92
TileLayoutRegisters::dodraw
uint8_t dodraw
Register deciding whether the sprite shall be drawn at all. Non-zero means drawing.
Definition newgrf_commons.h:93
TileLayoutRegisters::max_sprite_offset
uint16_t max_sprite_offset
Maximum offset to add to the sprite. (limited by size of the spriteset)
Definition newgrf_commons.h:96
TileLayoutRegisters::palette
uint8_t palette
Register specifying a signed offset for the palette.
Definition newgrf_commons.h:95
TileLayoutRegisters::sprite_var10
uint8_t sprite_var10
Value for variable 10 when resolving the sprite.
Definition newgrf_commons.h:102
TileLayoutRegisters::max_palette_offset
uint16_t max_palette_offset
Maximum offset to add to the palette. (limited by size of the spriteset)
Definition newgrf_commons.h:97
TileLayoutRegisters::palette_var10
uint8_t palette_var10
Value for variable 10 when resolving the palette.
Definition newgrf_commons.h:103
TileLayoutRegisters::child
uint8_t child[2]
Registers for signed offsets for the position of child sprites.
Definition newgrf_commons.h:100
TileLayoutRegisters::sprite
uint8_t sprite
Register specifying a signed offset for the sprite.
Definition newgrf_commons.h:94
TileLayoutSpriteGroup
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
Definition newgrf_spritegroup.h:236