OpenTTD
newgrf_animation_base.h
Go to the documentation of this file.
1 /* $Id: newgrf_animation_base.h 24846 2012-12-23 21:09:09Z frosch $ */
2 
3 /*
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/>.
8  */
9 
12 /* No inclusion guards as this file must only be included from .cpp files. */
13 
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"
20 #include "tile_map.h"
21 
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 {
41  static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = 0)
42  {
43  assert(spec != NULL);
44 
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);
52  }
53  }
54 
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;
60 
61  uint8 frame = GetAnimationFrame(tile);
62  uint8 num_frames = spec->animation.frames;
63 
64  bool frame_set_by_callback = false;
65 
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);
68 
69  if (callback != CALLBACK_FAILED) {
70  frame_set_by_callback = true;
71 
72  switch (callback & 0xFF) {
73  case 0xFF:
74  DeleteAnimatedTile(tile);
75  break;
76 
77  case 0xFE:
78  frame_set_by_callback = false;
79  break;
80 
81  default:
82  frame = callback & 0xFF;
83  break;
84  }
85 
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);
89  }
90  }
91 
92  if (!frame_set_by_callback) {
93  if (frame < num_frames) {
94  frame++;
95  } else if (frame == num_frames && spec->animation.status == ANIM_STATUS_LOOPING) {
96  /* This animation loops, so start again from the beginning */
97  frame = 0;
98  } else {
99  /* This animation doesn't loop, so stay here */
100  DeleteAnimatedTile(tile);
101  }
102  }
103 
104  SetAnimationFrame(tile, frame);
105  MarkTileDirtyByTile(tile);
106  }
107 
120  static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32 random_bits, uint32 trigger, Textra extra_data = 0)
121  {
122  uint16 callback = GetCallback(cb, random_bits, trigger, spec, obj, tile, extra_data);
123  if (callback == CALLBACK_FAILED) return;
124 
125  switch (callback & 0xFF) {
126  case 0xFD: /* Do nothing. */ break;
127  case 0xFE: AddAnimatedTile(tile); break;
128  case 0xFF: DeleteAnimatedTile(tile); break;
129  default:
130  SetAnimationFrame(tile, callback);
131  AddAnimatedTile(tile);
132  break;
133  }
134 
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);
138  }
139 };