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_animation_base.h Function implementations related to NewGRF animation. */
12 /* No inclusion guards as this file must only be included from .cpp files. */
14 #include "animated_tile_func.h"
15 #include "core/random_func.hpp"
16 #include "date_func.h"
17 #include "viewport_func.h"
18 #include "newgrf_animation_type.h"
19 #include "newgrf_callbacks.h"
23 * Helper class for a unified approach to NewGRF animation.
24 * @tparam Tbase Instantiation of this class.
25 * @tparam Tspec NewGRF specification related to the animated tile.
26 * @tparam Tobj Object related to the animated tile.
27 * @tparam Textra Custom extra callback data.
28 * @tparam GetCallback The callback function pointer.
30 template <typename Tbase
, typename Tspec
, typename Tobj
, typename Textra
, uint16 (*GetCallback
)(CallbackID callback
, uint32 param1
, uint32 param2
, const Tspec
*statspec
, Tobj
*st
, TileIndex tile
, Textra extra_data
)>
31 struct AnimationBase
{
33 * Animate a single tile.
34 * @param cb The callback to actually call.
35 * @param spec Specification related to the tile.
36 * @param obj Object related to the tile.
37 * @param tile Tile to animate changes for.
38 * @param random_animation Whether to pass random bits to the "next frame" callback.
39 * @param extra_data Custom extra callback data.
41 static void AnimateTile(const Tspec
*spec
, Tobj
*obj
, TileIndex tile
, bool random_animation
, Textra extra_data
= 0)
43 assert(spec
!= nullptr);
45 /* Acquire the animation speed from the NewGRF. */
46 uint8 animation_speed
= spec
->animation
.speed
;
47 if (HasBit(spec
->callback_mask
, Tbase::cbm_animation_speed
)) {
48 uint16 callback
= GetCallback(Tbase::cb_animation_speed
, 0, 0, spec
, obj
, tile
, extra_data
);
49 if (callback
!= CALLBACK_FAILED
) {
50 if (callback
>= 0x100 && spec
->grf_prop
.grffile
->grf_version
>= 8) ErrorUnknownCallbackResult(spec
->grf_prop
.grffile
->grfid
, Tbase::cb_animation_speed
, callback
);
51 animation_speed
= Clamp(callback
& 0xFF, 0, 16);
55 /* An animation speed of 2 means the animation frame changes 4 ticks, and
56 * increasing this value by one doubles the wait. 0 is the minimum value
57 * allowed for animation_speed, which corresponds to 30ms, and 16 is the
58 * maximum, corresponding to around 33 minutes. */
59 if (_tick_counter
% (1 << animation_speed
) != 0) return;
61 uint8 frame
= GetAnimationFrame(tile
);
62 uint8 num_frames
= spec
->animation
.frames
;
64 bool frame_set_by_callback
= false;
66 if (HasBit(spec
->callback_mask
, Tbase::cbm_animation_next_frame
)) {
67 uint16 callback
= GetCallback(Tbase::cb_animation_next_frame
, random_animation
? Random() : 0, 0, spec
, obj
, tile
, extra_data
);
69 if (callback
!= CALLBACK_FAILED
) {
70 frame_set_by_callback
= true;
72 switch (callback
& 0xFF) {
74 DeleteAnimatedTile(tile
);
78 frame_set_by_callback
= false;
82 frame
= callback
& 0xFF;
86 /* If the lower 7 bits of the upper byte of the callback
87 * result are not empty, it is a sound effect. */
88 if (GB(callback
, 8, 7) != 0 && _settings_client
.sound
.ambient
) PlayTileSound(spec
->grf_prop
.grffile
, GB(callback
, 8, 7), tile
);
92 if (!frame_set_by_callback
) {
93 if (frame
< num_frames
) {
95 } else if (frame
== num_frames
&& spec
->animation
.status
== ANIM_STATUS_LOOPING
) {
96 /* This animation loops, so start again from the beginning */
99 /* This animation doesn't loop, so stay here */
100 DeleteAnimatedTile(tile
);
104 SetAnimationFrame(tile
, frame
);
105 MarkTileDirtyByTile(tile
, ZOOM_LVL_DRAW_MAP
);
109 * Check a callback to determine what the next animation step is and
110 * execute that step. This includes stopping and starting animations
111 * as well as updating animation frames and playing sounds.
112 * @param cb The callback to actually call.
113 * @param spec Specification related to the tile.
114 * @param obj Object related to the tile.
115 * @param tile Tile to consider animation changes for.
116 * @param random_bits Random bits for this update. To be passed as parameter to the NewGRF.
117 * @param trigger What triggered this update? To be passed as parameter to the NewGRF.
118 * @param extra_data Custom extra data for callback processing.
120 static void ChangeAnimationFrame(CallbackID cb
, const Tspec
*spec
, Tobj
*obj
, TileIndex tile
, uint32 random_bits
, uint32 trigger
, Textra extra_data
= 0)
122 uint16 callback
= GetCallback(cb
, random_bits
, trigger
, spec
, obj
, tile
, extra_data
);
123 if (callback
== CALLBACK_FAILED
) return;
125 switch (callback
& 0xFF) {
126 case 0xFD: /* Do nothing. */ break;
127 case 0xFE: AddAnimatedTile(tile
); break;
128 case 0xFF: DeleteAnimatedTile(tile
); break;
130 SetAnimationFrame(tile
, callback
);
131 AddAnimatedTile(tile
);
135 /* If the lower 7 bits of the upper byte of the callback
136 * result are not empty, it is a sound effect. */
137 if (GB(callback
, 8, 7) != 0 && _settings_client
.sound
.ambient
) PlayTileSound(spec
->grf_prop
.grffile
, GB(callback
, 8, 7), tile
);