4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */
14 #include "newgrf_spritegroup.h"
15 #include "core/pool_func.hpp"
17 std::deque
<ttd_unique_ptr
<SpriteGroup
> > SpriteGroup::pool
;
19 TemporaryStorageArray
<int32
, 0x110> _temp_store
;
23 * ResolverObject (re)entry point.
24 * This cannot be made a call to a virtual function because virtual functions
25 * do not like NULL and checking for NULL *everywhere* is more cumbersome than
26 * this little helper function.
27 * @param group the group to resolve for
28 * @param object information needed to resolve the group
29 * @param top_level true if this is a top-level SpriteGroup, false if used nested in another SpriteGroup.
30 * @return the resolved group
32 /* static */ const SpriteGroup
*SpriteGroup::Resolve(const SpriteGroup
*group
, ResolverObject
&object
, bool top_level
)
34 if (group
== NULL
) return NULL
;
36 _temp_store
.ClearChanges();
38 return group
->Resolve(object
);
42 static inline uint32
GetVariable(const ResolverObject
&object
, ScopeResolver
*scope
, byte variable
, uint32 parameter
, bool *available
)
44 /* First handle variables common with Action7/9/D */
46 if (GetGlobalVariable(variable
, &value
, object
.grffile
)) return value
;
48 /* Non-common variable */
50 case 0x0C: return object
.callback
;
51 case 0x10: return object
.callback_param1
;
52 case 0x18: return object
.callback_param2
;
53 case 0x1C: return object
.last_value
;
55 case 0x5F: return (scope
->GetRandomBits() << 8) | scope
->GetTriggers();
57 case 0x7D: return _temp_store
.GetValue(parameter
);
60 if (object
.grffile
== NULL
) return 0;
61 return object
.grffile
->GetParam(parameter
);
63 /* Not a common variable, so evaluate the feature specific variables */
64 default: return scope
->GetVariable(variable
, parameter
, available
);
69 * Get a few random bits. Default implementation has no random bits.
70 * @return Random bits.
72 /* virtual */ uint32
ScopeResolver::GetRandomBits() const
78 * Get the triggers. Base class returns \c 0 to prevent trouble.
79 * @return The triggers.
81 /* virtual */ uint32
ScopeResolver::GetTriggers() const
87 * Set the triggers. Base class implementation does nothing.
88 * @param triggers Triggers to set.
90 /* virtual */ void ScopeResolver::SetTriggers(int triggers
) const {}
93 * Get a variable value. Default implementation has no available variables.
94 * @param variable Variable to read
95 * @param parameter Parameter for 60+x variables
96 * @param[out] available Set to false, in case the variable does not exist.
99 /* virtual */ uint32
ScopeResolver::GetVariable(byte variable
, uint32 parameter
, bool *available
) const
101 DEBUG(grf
, 1, "Unhandled scope variable 0x%X", variable
);
107 * Store a value into the persistent storage area (PSA). Default implementation does nothing (for newgrf classes without storage).
108 * @param pos Position to store into.
109 * @param value Value to store.
111 /* virtual */ void ScopeResolver::StorePSA(uint reg
, int32 value
) {}
114 * Resolver constructor.
115 * @param grffile NewGRF file associated with the object (or \c NULL if none).
116 * @param callback Callback code being resolved (default value is #CBID_NO_CALLBACK).
117 * @param callback_param1 First parameter (var 10) of the callback (only used when \a callback is also set).
118 * @param callback_param2 Second parameter (var 18) of the callback (only used when \a callback is also set).
120 ResolverObject::ResolverObject(const GRFFile
*grffile
, CallbackID callback
, uint32 callback_param1
, uint32 callback_param2
)
121 : grffile(grffile
), default_scope()
123 this->callback
= callback
;
124 this->callback_param1
= callback_param1
;
125 this->callback_param2
= callback_param2
;
129 ResolverObject::~ResolverObject() {}
132 * Get the real sprites of the grf.
133 * @param group Group to get.
134 * @return The available sprite group.
136 /* virtual */ const SpriteGroup
*ResolverObject::ResolveReal(const RealSpriteGroup
*group
) const
142 * Get a resolver for the \a scope.
143 * @param scope Scope to return.
144 * @param relative Additional parameter for #VSG_SCOPE_RELATIVE.
145 * @return The resolver for the requested scope.
147 /* virtual */ ScopeResolver
*ResolverObject::GetScope(VarSpriteGroupScope scope
, byte relative
)
149 return &this->default_scope
;
153 * Rotate val rot times to the right
154 * @param val the value to rotate
155 * @param rot the amount of times to rotate
156 * @return the rotated value
158 static uint32
RotateRight(uint32 val
, uint32 rot
)
160 /* Do not rotate more than necessary */
163 return (val
>> rot
) | (val
<< (32 - rot
));
167 /* Evaluate an adjustment for a variable of the given size.
168 * U is the unsigned type and S is the signed type to use. */
169 template <typename U
, typename S
>
170 static U
EvalAdjustT (const DeterministicSpriteGroup::Adjust
*adjust
, ScopeResolver
*scope
, U last_value
, uint32 value
)
172 value
>>= adjust
->shift_num
;
173 value
&= adjust
->and_mask
;
175 if (adjust
->type
!= 0) {
176 value
+= (S
)adjust
->add_val
;
178 if (adjust
->type
== 1) {
179 value
= (S
)value
/ (S
)adjust
->divmod_val
;
181 value
= (S
)value
% (S
)adjust
->divmod_val
;
185 switch (adjust
->operation
) {
186 case 0: return last_value
+ value
;
187 case 1: return last_value
- value
;
188 case 2: return min ((S
)last_value
, (S
)value
);
189 case 3: return max ((S
)last_value
, (S
)value
);
190 case 4: return min ((U
)last_value
, (U
)value
);
191 case 5: return max ((U
)last_value
, (U
)value
);
192 case 6: return value
== 0 ? (S
)last_value
: (S
)last_value
/ (S
)value
;
193 case 7: return value
== 0 ? (S
)last_value
: (S
)last_value
% (S
)value
;
194 case 8: return value
== 0 ? (U
)last_value
: (U
)last_value
/ (U
)value
;
195 case 9: return value
== 0 ? (U
)last_value
: (U
)last_value
% (U
)value
;
196 case 10: return last_value
* value
;
197 case 11: return last_value
& value
;
198 case 12: return last_value
| value
;
199 case 13: return last_value
^ value
;
200 case 14: _temp_store
.StoreValue ((U
)value
, (S
)last_value
); return last_value
;
201 case 15: return value
;
202 case 16: scope
->StorePSA ((U
)value
, (S
)last_value
); return last_value
;
203 case 17: return RotateRight (last_value
, value
);
204 case 18: return ((S
)last_value
== (S
)value
) ? 1 : ((S
)last_value
< (S
)value
? 0 : 2);
205 case 19: return ((U
)last_value
== (U
)value
) ? 1 : ((U
)last_value
< (U
)value
? 0 : 2);
206 case 20: return (uint32
)(U
)last_value
<< ((U
)value
& 0x1F); // Same behaviour as in ParamSet, mask 'value' to 5 bits, which should behave the same on all architectures.
207 case 21: return (uint32
)(U
)last_value
>> ((U
)value
& 0x1F);
208 case 22: return (int32
) (S
)last_value
>> ((U
)value
& 0x1F);
209 default: return value
;
214 const SpriteGroup
*DeterministicSpriteGroup::Resolve(ResolverObject
&object
) const
216 uint32 last_value
= 0;
220 ScopeResolver
*scope
= object
.GetScope(this->var_scope
);
222 for (i
= 0; i
< this->num_adjusts
; i
++) {
223 Adjust
*adjust
= &this->adjusts
[i
];
225 /* Try to get the variable. We shall assume it is available, unless told otherwise. */
226 bool available
= true;
227 if (adjust
->variable
== 0x7E) {
228 const SpriteGroup
*subgroup
= SpriteGroup::Resolve(adjust
->subroutine
, object
, false);
229 if (subgroup
== NULL
) {
230 value
= CALLBACK_FAILED
;
232 value
= subgroup
->GetCallbackResult();
235 /* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
237 byte variable
= adjust
->variable
;
238 uint32 parameter
= adjust
->parameter
;
239 if (variable
== 0x7B) {
240 variable
= parameter
;
241 parameter
= last_value
;
243 value
= GetVariable (object
, scope
, variable
, parameter
, &available
);
247 /* Unsupported variable: skip further processing and return either
248 * the group from the first range or the default group. */
249 return SpriteGroup::Resolve(this->num_ranges
> 0 ? this->ranges
[0].group
: this->default_group
, object
, false);
252 switch (this->size
) {
253 case 0: value
= EvalAdjustT
<uint8
, int8
> (adjust
, scope
, last_value
, value
); break;
254 case 1: value
= EvalAdjustT
<uint16
, int16
>(adjust
, scope
, last_value
, value
); break;
255 case 2: value
= EvalAdjustT
<uint32
, int32
>(adjust
, scope
, last_value
, value
); break;
256 default: NOT_REACHED();
261 object
.last_value
= last_value
;
263 if (this->num_ranges
== 0) {
264 /* nvar == 0 is a special case -- we turn our value into a callback result */
265 if (value
!= CALLBACK_FAILED
) value
= GB(value
, 0, 15);
266 static CallbackResultSpriteGroup
nvarzero(0, true);
267 nvarzero
.result
= value
;
271 for (i
= 0; i
< this->num_ranges
; i
++) {
272 if (this->ranges
[i
].low
<= value
&& value
<= this->ranges
[i
].high
) {
273 return SpriteGroup::Resolve(this->ranges
[i
].group
, object
, false);
277 return SpriteGroup::Resolve(this->default_group
, object
, false);
281 const SpriteGroup
*RandomizedSpriteGroup::Resolve(ResolverObject
&object
) const
283 ScopeResolver
*scope
= object
.GetScope(this->var_scope
, this->count
);
284 if (object
.trigger
!= 0) {
285 /* Handle triggers */
286 /* Magic code that may or may not do the right things... */
287 byte waiting_triggers
= scope
->GetTriggers();
288 byte match
= this->triggers
& (waiting_triggers
| object
.trigger
);
289 bool res
= this->cmp_mode
? (match
== this->triggers
) : (match
!= 0);
292 waiting_triggers
&= ~match
;
293 object
.reseed
[this->var_scope
] |= (this->num_groups
- 1) << this->lowest_randbit
;
295 waiting_triggers
|= object
.trigger
;
298 scope
->SetTriggers(waiting_triggers
);
301 uint32 mask
= (this->num_groups
- 1) << this->lowest_randbit
;
302 byte index
= (scope
->GetRandomBits() & mask
) >> this->lowest_randbit
;
304 return SpriteGroup::Resolve(this->groups
[index
], object
, false);
308 const SpriteGroup
*RealSpriteGroup::Resolve(ResolverObject
&object
) const
310 return object
.ResolveReal(this);
314 * Process registers and the construction stage into the sprite layout.
315 * The passed construction stage might get reset to zero, if it gets incorporated into the layout
316 * during the preprocessing.
317 * @param group Source layout.
318 * @param stage Construction stage (0-3).
320 TileLayoutSpriteGroup::Result::Result (const TileLayoutSpriteGroup
*group
, byte stage
)
322 if (!group
->dts
.NeedsPreprocessing()) {
323 this->seq
= group
->dts
.seq
;
324 this->ground
= group
->dts
.ground
;
325 uint n
= group
->dts
.consistent_max_offset
;
326 this->stage
= (n
> 0) ? GetConstructionStageOffset (stage
, n
) : 0;
330 this->prepare (&group
->dts
, stage
);
331 this->process (&group
->dts
);
332 this->ground
= this->get_ground();
333 this->seq
= this->get_seq();
335 /* Stage has been processed by PrepareLayout(), set it to zero. */