newgrf_animation_base.h

Go to the documentation of this file.
00001 /* $Id: newgrf_animation_base.h 23148 2011-11-08 17:27:13Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 /* No inclusion guards as this file must only be included from .cpp files. */
00013 
00014 #include "animated_tile_func.h"
00015 #include "core/random_func.hpp"
00016 #include "date_func.h"
00017 #include "viewport_func.h"
00018 #include "newgrf_animation_type.h"
00019 #include "newgrf_callbacks.h"
00020 
00029 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)>
00030 struct AnimationBase {
00040   static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = 0)
00041   {
00042     assert(spec != NULL);
00043 
00044     /* Acquire the animation speed from the NewGRF. */
00045     uint8 animation_speed = spec->animation.speed;
00046     if (HasBit(spec->callback_mask, Tbase::cbm_animation_speed)) {
00047       uint16 callback = GetCallback(Tbase::cb_animation_speed, 0, 0, spec, obj, tile, extra_data);
00048       if (callback != CALLBACK_FAILED) {
00049         if (callback >= 0x100 && spec->grf_prop.grffile->grf_version >= 8) ErrorUnknownCallbackResult(spec->grf_prop.grffile->grfid, Tbase::cb_animation_speed, callback);
00050         animation_speed = Clamp(callback & 0xFF, 0, 16);
00051       }
00052     }
00053 
00054     /* An animation speed of 2 means the animation frame changes 4 ticks, and
00055      * increasing this value by one doubles the wait. 0 is the minimum value
00056      * allowed for animation_speed, which corresponds to 30ms, and 16 is the
00057      * maximum, corresponding to around 33 minutes. */
00058     if (_tick_counter % (1 << animation_speed) != 0) return;
00059 
00060     uint8 frame      = GetAnimationFrame(tile);
00061     uint8 num_frames = spec->animation.frames;
00062 
00063     bool frame_set_by_callback = false;
00064 
00065     if (HasBit(spec->callback_mask, Tbase::cbm_animation_next_frame)) {
00066       uint16 callback = GetCallback(Tbase::cb_animation_next_frame, random_animation ? Random() : 0, 0, spec, obj, tile, extra_data);
00067 
00068       if (callback != CALLBACK_FAILED) {
00069         frame_set_by_callback = true;
00070 
00071         switch (callback & 0xFF) {
00072           case 0xFF:
00073             DeleteAnimatedTile(tile);
00074             break;
00075 
00076           case 0xFE:
00077             frame_set_by_callback = false;
00078             break;
00079 
00080           default:
00081             frame = callback & 0xFF;
00082             break;
00083         }
00084 
00085         /* If the lower 7 bits of the upper byte of the callback
00086          * result are not empty, it is a sound effect. */
00087         if (GB(callback, 8, 7) != 0) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile);
00088       }
00089     }
00090 
00091     if (!frame_set_by_callback) {
00092       if (frame < num_frames) {
00093         frame++;
00094       } else if (frame == num_frames && spec->animation.status == ANIM_STATUS_LOOPING) {
00095         /* This animation loops, so start again from the beginning */
00096         frame = 0;
00097       } else {
00098         /* This animation doesn't loop, so stay here */
00099         DeleteAnimatedTile(tile);
00100       }
00101     }
00102 
00103     SetAnimationFrame(tile, frame);
00104     MarkTileDirtyByTile(tile);
00105   }
00106 
00119   static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32 random_bits, uint32 trigger, Textra extra_data = 0)
00120   {
00121     uint16 callback = GetCallback(cb, random_bits, trigger, spec, obj, tile, extra_data);
00122     if (callback == CALLBACK_FAILED) return;
00123 
00124     switch (callback & 0xFF) {
00125       case 0xFD: /* Do nothing. */         break;
00126       case 0xFE: AddAnimatedTile(tile);    break;
00127       case 0xFF: DeleteAnimatedTile(tile); break;
00128       default:
00129         SetAnimationFrame(tile, callback);
00130         AddAnimatedTile(tile);
00131         break;
00132     }
00133 
00134     /* If the lower 7 bits of the upper byte of the callback
00135      * result are not empty, it is a sound effect. */
00136     if (GB(callback, 8, 7) != 0) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile);
00137   }
00138 };