OpenTTD Source 20251213-master-g1091fa6071
newgrf_animation_base.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/* No inclusion guards as this file must only be included from .cpp files. */
11
12#include "animated_tile_func.h"
13#include "core/random_func.hpp"
15#include "viewport_func.h"
17#include "newgrf_callbacks.h"
18#include "tile_map.h"
19
20template <typename Tobj>
22 static uint8_t Get(Tobj *, TileIndex tile) { return GetAnimationFrame(tile); }
23 static bool Set(Tobj *, TileIndex tile, uint8_t frame)
24 {
25 uint8_t prev_frame = GetAnimationFrame(tile);
26 if (prev_frame == frame) return false;
27
28 SetAnimationFrame(tile, frame);
29 return true;
30 }
31};
32
42template <typename Tbase, typename Tspec, typename Tobj, typename Textra, uint16_t (*GetCallback)(CallbackID callback, uint32_t param1, uint32_t param2, const Tspec *statspec, Tobj *st, TileIndex tile, Textra extra_data), typename Tframehelper>
52 static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = 0)
53 {
54 assert(spec != nullptr);
55
56 /* Acquire the animation speed from the NewGRF. */
57 uint8_t animation_speed = spec->animation.speed;
58 if (spec->callback_mask.Test(Tbase::cbm_animation_speed)) {
59 uint16_t callback = GetCallback(Tbase::cb_animation_speed, 0, 0, spec, obj, tile, extra_data);
60 if (callback != CALLBACK_FAILED) {
61 if (callback >= 0x100 && spec->grf_prop.grffile->grf_version >= 8) ErrorUnknownCallbackResult(spec->grf_prop.grfid, Tbase::cb_animation_speed, callback);
62 animation_speed = Clamp(callback & 0xFF, 0, 16);
63 }
64 }
65
66 /* An animation speed of 2 means the animation frame changes 4 ticks, and
67 * increasing this value by one doubles the wait. 0 is the minimum value
68 * allowed for animation_speed, which corresponds to 30ms, and 16 is the
69 * maximum, corresponding to around 33 minutes. */
70 if (TimerGameTick::counter % (1ULL << animation_speed) != 0) return;
71
72 uint8_t frame = Tframehelper::Get(obj, tile);
73 uint8_t num_frames = spec->animation.frames;
74
75 bool frame_set_by_callback = false;
76
77 if (spec->callback_mask.Test(Tbase::cbm_animation_next_frame)) {
78 uint16_t callback = GetCallback(Tbase::cb_animation_next_frame, random_animation ? Random() : 0, 0, spec, obj, tile, extra_data);
79
80 if (callback != CALLBACK_FAILED) {
81 frame_set_by_callback = true;
82
83 switch (callback & 0xFF) {
84 case 0xFF:
86 break;
87
88 case 0xFE:
89 frame_set_by_callback = false;
90 break;
91
92 default:
93 frame = callback & 0xFF;
94 break;
95 }
96
97 /* If the lower 7 bits of the upper byte of the callback
98 * result are not empty, it is a sound effect. */
99 if (GB(callback, 8, 7) != 0 && _settings_client.sound.ambient) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile);
100 }
101 }
102
103 if (!frame_set_by_callback) {
104 if (frame < num_frames) {
105 frame++;
106 } else if (frame == num_frames && spec->animation.status == AnimationStatus::Looping) {
107 /* This animation loops, so start again from the beginning */
108 frame = 0;
109 } else {
110 /* This animation doesn't loop, so stay here */
111 DeleteAnimatedTile(tile);
112 }
113 }
114
115 bool changed = Tframehelper::Set(obj, tile, frame);
116 if (changed) MarkTileDirtyByTile(tile);
117 }
118
131 static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, Textra extra_data = 0)
132 {
133 uint16_t callback = GetCallback(cb, random_bits, trigger, spec, obj, tile, extra_data);
134 if (callback == CALLBACK_FAILED) return;
135
136 switch (callback & 0xFF) {
137 case 0xFD: /* Do nothing. */ break;
138 case 0xFE: AddAnimatedTile(tile, false); break;
139 case 0xFF: DeleteAnimatedTile(tile); break;
140 default:
141 bool changed = Tframehelper::Set(obj, tile, callback);
142 AddAnimatedTile(tile, changed);
143 break;
144 }
145
146 /* If the lower 7 bits of the upper byte of the callback
147 * result are not empty, it is a sound effect. */
148 if (GB(callback, 8, 7) != 0 && _settings_client.sound.ambient) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile);
149 }
150};
void AddAnimatedTile(TileIndex tile, bool mark_dirty)
Add the given tile to the animated tile table (if it does not exist yet).
void DeleteAnimatedTile(TileIndex tile, bool immediate)
Stops animation on the given tile.
Tile animation!
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
static TickCounter counter
Monotonic counter, in ticks, since start of game.
void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset, int tile_height_override)
Mark a tile given by its index dirty for repaint.
@ Random
Randomise borders.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
Definitions related to NewGRF animation.
@ Looping
Animation is looping.
Callbacks that NewGRFs could implement.
CallbackID
List of implemented NewGRF callbacks.
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.
void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile)
Play a NewGRF sound effect at the location of a specific tile.
Pseudo random number generator.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Helper class for a unified approach to NewGRF animation.
static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data=0)
Animate a single tile.
static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32_t random_bits, uint32_t trigger, Textra extra_data=0)
Check a callback to determine what the next animation step is and execute that step.
SoundSettings sound
sound effect settings
bool ambient
Play ambient, industry and town sounds.
Map writing/reading functions for tiles.
uint8_t GetAnimationFrame(Tile t)
Get the current animation frame.
Definition tile_map.h:250
void SetAnimationFrame(Tile t, uint8_t frame)
Set a new animation frame.
Definition tile_map.h:262
Definition of the tick-based game-timer.
Functions related to (drawing on) viewports.