OpenTTD Source 20260108-master-g8ba1860eaa
newgrf_spritegroup.h
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#ifndef NEWGRF_SPRITEGROUP_H
11#define NEWGRF_SPRITEGROUP_H
12
13#include "core/pool_type.hpp"
14#include "town_type.h"
15#include "engine_type.h"
16#include "house_type.h"
17#include "industry_type.h"
18
19#include "newgrf_callbacks.h"
20#include "newgrf_generic.h"
21#include "newgrf_storage.h"
22#include "newgrf_commons.h"
23
24struct SpriteGroup;
28struct ResolverObject;
29using CallbackResult = uint16_t;
30
37using ResolverResult = std::variant<std::monostate, CallbackResult, const ResultSpriteGroup *, const TileLayoutSpriteGroup *, const IndustryProductionSpriteGroup *>;
38
39/* SPRITE_WIDTH is 24. ECS has roughly 30 sprite groups per real sprite.
40 * Adding an 'extra' margin would be assuming 64 sprite groups per real
41 * sprite. 64 = 2^6, so 2^30 should be enough (for now) */
44extern SpriteGroupPool _spritegroup_pool;
45
46/* Common wrapper for all the different sprite group types */
47struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> {
48protected:
51 virtual ResolverResult Resolve(ResolverObject &object) const = 0;
52
53public:
54 virtual ~SpriteGroup() = default;
55
56 uint32_t nfo_line = 0;
57
58 static ResolverResult Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level = true);
59};
60
61
65template <class T>
68
74 template <typename... Targs>
75 static inline T *Create(Targs &&... args)
76 {
77 return SpriteGroup::Create<T>(std::forward<Targs&&>(args)...);
78 }
79};
80
81
82/* 'Real' sprite groups contain a list of other result or callback sprite
83 * groups. */
84struct RealSpriteGroup : SpecializedSpriteGroup<RealSpriteGroup> {
86
87 /* Loaded = in motion, loading = not moving
88 * Each group contains several spritesets, for various loading stages */
89
90 /* XXX: For stations the meaning is different - loaded is for stations
91 * with small amount of cargo whilst loading is for stations with a lot
92 * of da stuff. */
93
94 std::vector<const SpriteGroup *> loaded{};
95 std::vector<const SpriteGroup *> loading{};
96
97protected:
98 ResolverResult Resolve(ResolverObject &object) const override;
99};
100
101/* Shared by deterministic and random groups. */
102enum VarSpriteGroupScope : uint8_t {
103 VSG_BEGIN,
104
105 VSG_SCOPE_SELF = VSG_BEGIN,
108
109 VSG_END
110};
112
113enum DeterministicSpriteGroupSize : uint8_t {
114 DSG_SIZE_BYTE,
115 DSG_SIZE_WORD,
116 DSG_SIZE_DWORD,
117};
118
119enum DeterministicSpriteGroupAdjustType : uint8_t {
120 DSGA_TYPE_NONE,
121 DSGA_TYPE_DIV,
122 DSGA_TYPE_MOD,
123};
124
150
151
154 DeterministicSpriteGroupAdjustType type{};
155 uint8_t variable = 0;
156 uint8_t parameter = 0;
157 uint8_t shift_num = 0;
158 uint32_t and_mask = 0;
159 uint32_t add_val = 0;
160 uint32_t divmod_val = 0;
161 const SpriteGroup *subroutine = nullptr;
162};
163
164
166 bool calculated_result = false;
167 const SpriteGroup *group = nullptr;
168
169 bool operator==(const DeterministicSpriteGroupResult &) const = default;
170};
171
174 uint32_t low = 0;
175 uint32_t high = 0;
176};
177
178
179struct DeterministicSpriteGroup : SpecializedSpriteGroup<DeterministicSpriteGroup> {
181
182 VarSpriteGroupScope var_scope{};
183 DeterministicSpriteGroupSize size{};
184 std::vector<DeterministicSpriteGroupAdjust> adjusts{};
185 std::vector<DeterministicSpriteGroupRange> ranges{}; // Dynamically allocated
186
187 /* Dynamically allocated, this is the sole owner */
188 DeterministicSpriteGroupResult default_result;
189
190 const SpriteGroup *error_group = nullptr; // was first range, before sorting ranges
191
192protected:
193 ResolverResult Resolve(ResolverObject &object) const override;
194};
195
196enum RandomizedSpriteGroupCompareMode : uint8_t {
197 RSG_CMP_ANY,
198 RSG_CMP_ALL,
199};
200
201struct RandomizedSpriteGroup : SpecializedSpriteGroup<RandomizedSpriteGroup> {
203
205
206 RandomizedSpriteGroupCompareMode cmp_mode{};
207 uint8_t triggers = 0;
208 uint8_t count = 0;
209
210 uint8_t lowest_randbit = 0;
211
212 std::vector<const SpriteGroup *> groups{};
213
214protected:
215 ResolverResult Resolve(ResolverObject &object) const override;
216};
217
218
219/* This contains a callback result. A failed callback has a value of
220 * CALLBACK_FAILED */
221struct CallbackResultSpriteGroup : SpecializedSpriteGroup<CallbackResultSpriteGroup> {
227
228 CallbackResult result = 0;
229
230protected:
231 ResolverResult Resolve(ResolverObject &object) const override;
232};
233
234
235/* A result sprite group returns the first SpriteID and the number of
236 * sprites in the set */
237struct ResultSpriteGroup : SpecializedSpriteGroup<ResultSpriteGroup> {
244 ResultSpriteGroup(SpriteGroupID index, SpriteID sprite, uint8_t num_sprites) : SpecializedSpriteGroup<ResultSpriteGroup>(index), num_sprites(num_sprites), sprite(sprite) {}
245
246 uint8_t num_sprites = 0;
247 SpriteID sprite = 0;
248
249protected:
250 ResolverResult Resolve(ResolverObject &) const override { return this; }
251};
252
256struct TileLayoutSpriteGroup : SpecializedSpriteGroup<TileLayoutSpriteGroup> {
258
259 NewGRFSpriteLayout dts{};
260
261 SpriteLayoutProcessor ProcessRegisters(const ResolverObject &object, uint8_t *stage) const;
262
263protected:
264 ResolverResult Resolve(ResolverObject &) const override { return this; }
265};
266
267struct IndustryProductionSpriteGroup : SpecializedSpriteGroup<IndustryProductionSpriteGroup> {
269
270 uint8_t version = 0;
271 uint8_t num_input = 0;
272 std::array<int16_t, INDUSTRY_NUM_INPUTS> subtract_input{};
273 std::array<CargoType, INDUSTRY_NUM_INPUTS> cargo_input{};
274 uint8_t num_output = 0;
275 std::array<uint16_t, INDUSTRY_NUM_OUTPUTS> add_output{};
276 std::array<CargoType, INDUSTRY_NUM_OUTPUTS> cargo_output{};
277 uint8_t again = 0;
278
279protected:
280 ResolverResult Resolve(ResolverObject &) const override { return this; }
281};
282
291
293 virtual ~ScopeResolver() = default;
294
295 virtual uint32_t GetRandomBits() const;
296 virtual uint32_t GetRandomTriggers() const;
297
298 virtual uint32_t GetVariable(uint8_t variable, [[maybe_unused]] uint32_t parameter, bool &available) const;
299 virtual void StorePSA(uint reg, int32_t value);
300};
301
309private:
311
312public:
324
325 virtual ~ResolverObject() = default;
326
327 ResolverResult DoResolve()
328 {
329 temp_store.ClearChanges();
330 this->last_value = 0;
331 this->used_random_triggers = 0;
332 this->reseed.fill(0);
333 return SpriteGroup::Resolve(this->root_spritegroup, *this);
334 }
335
337
344 inline int32_t GetRegister(uint i) const
345 {
346 return temp_store.GetValue(i);
347 }
348
355 inline void SetRegister(uint i, int32_t value)
356 {
357 temp_store.StoreValue(i, value);
358 }
359
361 uint32_t callback_param1 = 0;
362 uint32_t callback_param2 = 0;
363
364 uint32_t last_value = 0;
365
366protected:
368 uint32_t used_random_triggers = 0;
369public:
370 std::array<uint32_t, VSG_END> reseed;
371
372 const GRFFile *grffile = nullptr;
373 const SpriteGroup *root_spritegroup = nullptr;
374
380 template <class TSpriteGroup>
381 inline const TSpriteGroup *Resolve()
382 {
383 auto result = this->DoResolve();
384 const auto *group = std::get_if<const TSpriteGroup *>(&result);
385 if (group == nullptr) return nullptr;
386 return *group;
387 }
388
397 {
398 /* The Resolve result has no meaning.
399 * It can be a SpriteSet, a callback result, or even an invalid SpriteGroup reference (nullptr). */
400 this->DoResolve();
401 }
402
408 inline CallbackResult ResolveCallback(std::span<int32_t> regs100)
409 {
410 auto result = this->DoResolve();
411 const auto *value = std::get_if<CallbackResult>(&result);
412 if (value == nullptr) return CALLBACK_FAILED;
413 for (uint i = 0; i < regs100.size(); ++i) {
414 regs100[i] = this->GetRegister(0x100 + i);
415 }
416 return *value;
417 }
418
419 virtual const SpriteGroup *ResolveReal(const RealSpriteGroup &group) const;
420
421 virtual ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, uint8_t relative = 0);
422
427 {
428 return this->waiting_random_triggers;
429 }
430
434 void AddUsedRandomTriggers(uint32_t triggers)
435 {
436 this->used_random_triggers |= triggers;
437 }
438
444 uint32_t GetReseedSum() const
445 {
446 uint32_t sum = 0;
447 for (VarSpriteGroupScope vsg = VSG_BEGIN; vsg < VSG_END; vsg++) {
448 sum |= this->reseed[vsg];
449 }
450 return sum;
451 }
452
457 virtual GrfSpecFeature GetFeature() const { return GSF_INVALID; }
463 virtual uint32_t GetDebugID() const { return 0; }
464};
465
469template <class RandomTriggers>
472
477 void SetWaitingRandomTriggers(RandomTriggers triggers)
478 {
479 this->waiting_random_triggers = triggers.base();
480 }
481
486 RandomTriggers GetUsedRandomTriggers() const
487 {
488 return static_cast<RandomTriggers>(this->used_random_triggers);
489 }
490};
491
492#endif /* NEWGRF_SPRITEGROUP_H */
Add dynamic register values to a sprite layout.
Types related to engines.
#define DECLARE_INCREMENT_DECREMENT_OPERATORS(enum_type)
For some enums it is useful to have pre/post increment/decrement operators.
Definition enum_type.hpp:63
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
Declaration of basic house types and enums.
Types related to the industry.
GrfSpecFeature
Definition newgrf.h:68
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:99
Callbacks that NewGRFs could implement.
CallbackID
List of implemented NewGRF callbacks.
@ CBID_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
This file simplifies and embeds a common mechanism of loading/saving and mapping of grf entities.
Functions related to generic callbacks.
DeterministicSpriteGroupAdjustOperation
@ DSGA_OP_OR
a | b
@ DSGA_OP_XOR
a ^ b
@ DSGA_OP_SUB
a - b
@ DSGA_OP_STOP
store a into persistent storage, indexed by b, return a
@ DSGA_OP_ROR
rotate a b positions to the right
@ DSGA_OP_SHL
a << b
@ DSGA_OP_UCMP
(unsigned) comparison (a < b -> 0, a == b = 1, a > b = 2)
@ DSGA_OP_MUL
a * b
@ DSGA_OP_SAR
(signed) a >> b
@ DSGA_OP_STO
store a into temporary storage, indexed by b. return a
@ DSGA_OP_SMOD
(signed) a % b
@ DSGA_OP_UDIV
(unsigned) a / b
@ DSGA_OP_UMAX
(unsigned) max(a, b)
@ DSGA_OP_SMIN
(signed) min(a, b)
@ DSGA_OP_ADD
a + b
@ DSGA_OP_UMOD
(unsigned) a & b
@ DSGA_OP_SHR
(unsigned) a >> b
@ DSGA_OP_RST
return b
@ DSGA_OP_AND
a & b
@ DSGA_OP_SDIV
(signed) a / b
@ DSGA_OP_SCMP
(signed) comparison (a < b -> 0, a == b = 1, a > b = 2)
@ DSGA_OP_UMIN
(unsigned) min(a, b)
@ DSGA_OP_SMAX
(signed) max(a, b)
VarSpriteGroupScope
@ VSG_SCOPE_SELF
Resolved object itself.
@ VSG_SCOPE_PARENT
Related object of the resolved one.
@ VSG_SCOPE_RELATIVE
Relative position (vehicles only)
std::variant< std::monostate, CallbackResult, const ResultSpriteGroup *, const TileLayoutSpriteGroup *, const IndustryProductionSpriteGroup * > ResolverResult
Result of resolving sprite groups:
Functionality related to the temporary and persistent storage arrays for NewGRFs.
Definition of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle,...
ResolverResult Resolve(ResolverObject &object) const override
Base sprite group resolver.
CallbackResultSpriteGroup(SpriteGroupID index, CallbackResult value)
Creates a spritegroup representing a callback result.
uint8_t parameter
Used for variables between 0x60 and 0x7F inclusive.
ResolverResult Resolve(ResolverObject &object) const override
Base sprite group resolver.
Dynamic data of a loaded NewGRF.
Definition newgrf.h:114
std::array< uint16_t, INDUSTRY_NUM_OUTPUTS > add_output
Add this much output cargo when successful (unsigned, is indirect in cb version 1+)
std::array< CargoType, INDUSTRY_NUM_OUTPUTS > cargo_output
Which output cargoes to add to (only cb version 2)
std::array< CargoType, INDUSTRY_NUM_INPUTS > cargo_input
Which input cargoes to take from (only cb version 2)
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+)
uint8_t num_input
How many subtract_input values are valid.
uint8_t version
Production callback version used, or 0xFF if marked invalid.
uint8_t num_output
How many add_output values are valid.
ResolverResult Resolve(ResolverObject &) const override
Base sprite group resolver.
NewGRF supplied spritelayout.
Templated helper to make a PoolID a single POD value.
Definition pool_type.hpp:47
Base class for all PoolItems.
const Tindex index
Index of this pool item.
Base class for all pools.
uint8_t lowest_randbit
Look for this in the per-object randomized bitmask:
VarSpriteGroupScope var_scope
Take this object:
std::vector< const SpriteGroup * > groups
Take the group with appropriate index:
ResolverResult Resolve(ResolverObject &object) const override
Base sprite group resolver.
RandomizedSpriteGroupCompareMode cmp_mode
Check for these triggers:
ResolverResult Resolve(ResolverObject &object) const override
Base sprite group resolver.
std::vector< const SpriteGroup * > loaded
List of loaded groups (can be SpriteIDs or Callback results)
std::vector< const SpriteGroup * > loading
List of loading groups (can be SpriteIDs or Callback results)
Interface for SpriteGroup-s to access the gamestate.
const GRFFile * grffile
GRFFile the resolved SpriteGroup belongs to.
virtual uint32_t GetDebugID() const
Get an identifier for the item being resolved.
void SetRegister(uint i, int32_t value)
Sets the value of a so-called newgrf "register".
uint32_t GetWaitingRandomTriggers() const
Used by RandomizedSpriteGroup: Triggers for rerandomisation.
void AddUsedRandomTriggers(uint32_t triggers)
Used by RandomizedSpriteGroup: Consume triggers.
uint32_t callback_param2
Second parameter (var 18) of the callback.
const TSpriteGroup * Resolve()
Resolve SpriteGroup.
uint32_t used_random_triggers
Subset of cur_triggers, which actually triggered some rerandomisation. (scope independent)
int32_t GetRegister(uint i) const
Gets the value of a so-called newgrf "register".
uint32_t GetReseedSum() const
Returns the OR-sum of all bits that need reseeding independent of the scope they were accessed with.
ResolverObject(const GRFFile *grffile, CallbackID callback=CBID_NO_CALLBACK, uint32_t callback_param1=0, uint32_t callback_param2=0)
Resolver constructor.
ScopeResolver default_scope
Default implementation of the grf scope.
CallbackID callback
Callback being resolved.
uint32_t callback_param1
First parameter (var 10) of the callback.
virtual const SpriteGroup * ResolveReal(const RealSpriteGroup &group) const
Get the real sprites of the grf.
uint32_t last_value
Result of most recent DeterministicSpriteGroup (including procedure calls)
virtual GrfSpecFeature GetFeature() const
Get the feature number being resolved for.
void ResolveRerandomisation()
Resolve bits to be rerandomised.
const SpriteGroup * root_spritegroup
Root SpriteGroup to use for resolving.
virtual ScopeResolver * GetScope(VarSpriteGroupScope scope=VSG_SCOPE_SELF, uint8_t relative=0)
Get a resolver for the scope.
uint32_t waiting_random_triggers
Waiting triggers to be used by any rerandomisation. (scope independent)
CallbackResult ResolveCallback(std::span< int32_t > regs100)
Resolve callback.
std::array< uint32_t, VSG_END > reseed
Collects bits to rerandomise while triggering triggers.
ResolverResult Resolve(ResolverObject &) const override
Base sprite group resolver.
ResultSpriteGroup(SpriteGroupID index, SpriteID sprite, uint8_t num_sprites)
Creates a spritegroup representing a sprite number result.
Interface to query and set values specific to a single VarSpriteGroupScope (action 2 scope).
virtual void StorePSA(uint reg, int32_t value)
Store a value into the persistent storage area (PSA).
virtual uint32_t GetVariable(uint8_t variable, uint32_t parameter, bool &available) const
Get a variable value.
ResolverObject & ro
Surrounding resolver object.
virtual uint32_t GetRandomTriggers() const
Get the triggers.
virtual uint32_t GetRandomBits() const
Get a few random bits.
Specialization of ResolverObject with type-safe access to RandomTriggers.
void SetWaitingRandomTriggers(RandomTriggers triggers)
Set waiting triggers for rerandomisation.
RandomTriggers GetUsedRandomTriggers() const
Get the triggers, which were "consumed" by some rerandomisation.
Class defining some overloaded accessors so we don't have to cast SpriteGroups that often.
static T * Create(Targs &&... args)
Creates a new T-object in the SpriteGroup pool.
virtual ResolverResult Resolve(ResolverObject &object) const =0
Base sprite group resolver.
Class for temporary storage of data.
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.
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
SpriteLayoutProcessor ProcessRegisters(const ResolverObject &object, uint8_t *stage) const
Process registers and the construction stage into the sprite layout.
ResolverResult Resolve(ResolverObject &) const override
Base sprite group resolver.
Types related to towns.