diff options
-rw-r--r-- | src/newgrf_airporttiles.cpp | 92 | ||||
-rw-r--r-- | src/newgrf_animation_base.h | 125 | ||||
-rw-r--r-- | src/newgrf_house.cpp | 93 | ||||
-rw-r--r-- | src/newgrf_house.h | 2 | ||||
-rw-r--r-- | src/newgrf_industrytiles.cpp | 98 | ||||
-rw-r--r-- | src/newgrf_station.cpp | 91 | ||||
-rw-r--r-- | src/town_cmd.cpp | 10 |
7 files changed, 194 insertions, 317 deletions
diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp index c15803e58..86de69a8b 100644 --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -28,6 +28,7 @@ #include "table/strings.h" #include "table/airporttiles.h" #include "date_func.h" +#include "newgrf_animation_base.h" AirportTileSpec AirportTileSpec::tiles[NUM_AIRPORTTILES]; @@ -312,96 +313,29 @@ bool DrawNewAirportTile(TileInfo *ti, Station *st, StationGfx gfx, const Airport return true; } -void AnimateAirportTile(TileIndex tile) -{ - Station *st = Station::GetByTile(tile); - const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); - uint8 animation_speed = ats->animation.speed; - - if (HasBit(ats->callback_mask, CBM_AIRT_ANIM_SPEED)) { - uint16 callback_res = GetAirportTileCallback(CBID_AIRPTILE_ANIMATION_SPEED, 0, 0, ats, st, tile); - if (callback_res != CALLBACK_FAILED) animation_speed = Clamp(callback_res & 0xFF, 0, 16); - } +/** Helper class for animation control. */ +struct AirportTileAnimationBase : public AnimationBase<AirportTileAnimationBase, AirportTileSpec, Station, GetAirportTileCallback> { + static const CallbackID cb_animation_speed = CBID_AIRPTILE_ANIMATION_SPEED; + static const CallbackID cb_animation_next_frame = CBID_AIRPTILE_ANIM_NEXT_FRAME; - /* An animation speed of 2 means the animation frame changes 4 ticks, and - * increasing this value by one doubles the wait. 0 is the minimum value - * allowed for animation_speed, which corresponds to 30ms, and 16 is the - * maximum, corresponding to around 33 minutes. */ - if ((_tick_counter % (1 << animation_speed)) != 0) return; - - bool frame_set_by_callback = false; - uint8 frame = GetAnimationFrame(tile); - uint16 num_frames = ats->animation.frames; - - if (HasBit(ats->callback_mask, CBM_AIRT_ANIM_NEXT_FRAME)) { - uint16 callback_res = GetAirportTileCallback(CBID_AIRPTILE_ANIM_NEXT_FRAME, HasBit(ats->animation_special_flags, 0) ? Random() : 0, 0, ats, st, tile); - - if (callback_res != CALLBACK_FAILED) { - frame_set_by_callback = true; - - switch (callback_res & 0xFF) { - case 0xFF: - DeleteAnimatedTile(tile); - break; - case 0xFE: - /* Carry on as normal. */ - frame_set_by_callback = false; - break; - default: - frame = callback_res & 0xFF; - break; - } + static const AirportTileCallbackMask cbm_animation_speed = CBM_AIRT_ANIM_SPEED; + static const AirportTileCallbackMask cbm_animation_next_frame = CBM_AIRT_ANIM_NEXT_FRAME; +}; - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback_res, 8, 7) != 0) PlayTileSound(ats->grf_prop.grffile, GB(callback_res, 8, 7), tile); - } - } - - if (!frame_set_by_callback) { - if (frame < num_frames) { - frame++; - } else if (frame == num_frames && ats->animation.status == ANIM_STATUS_LOOPING) { - /* This animation loops, so start again from the beginning */ - frame = 0; - } else { - /* This animation doesn't loop, so stay here */ - DeleteAnimatedTile(tile); - } - } - - SetAnimationFrame(tile, frame); - MarkTileDirtyByTile(tile); -} - -static void ChangeAirportTileAnimationFrame(const AirportTileSpec *ats, TileIndex tile, AirpAnimationTrigger trigger, Station *st) +void AnimateAirportTile(TileIndex tile) { - uint16 callback_res = GetAirportTileCallback(CBID_AIRPTILE_ANIM_START_STOP, Random(), trigger, ats, st, tile); - if (callback_res == CALLBACK_FAILED) return; - - switch (callback_res & 0xFF) { - case 0xFD: /* Do nothing. */ break; - case 0xFE: AddAnimatedTile(tile); break; - case 0xFF: DeleteAnimatedTile(tile); break; - default: - SetAnimationFrame(tile, callback_res & 0xFF); - AddAnimatedTile(tile); - break; - } + const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); + if (ats == NULL) return; - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback_res, 8, 7) != 0) PlayTileSound(ats->grf_prop.grffile, GB(callback_res, 8, 7), tile); + AirportTileAnimationBase::AnimateTile(ats, Station::GetByTile(tile), tile, HasBit(ats->animation_special_flags, 0)); } void AirportTileAnimationTrigger(Station *st, TileIndex tile, AirpAnimationTrigger trigger, CargoID cargo_type) { const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); - if (!HasBit(ats->animation.triggers, trigger)) return; - ChangeAirportTileAnimationFrame(ats, tile, trigger, st); - return; + AirportTileAnimationBase::ChangeAnimationFrame(CBID_AIRPTILE_ANIM_START_STOP, ats, st, tile, Random(), (uint8)trigger | (cargo_type << 8)); } void AirportAnimationTrigger(Station *st, AirpAnimationTrigger trigger, CargoID cargo_type) diff --git a/src/newgrf_animation_base.h b/src/newgrf_animation_base.h new file mode 100644 index 000000000..ee60f48f8 --- /dev/null +++ b/src/newgrf_animation_base.h @@ -0,0 +1,125 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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/>. + */ + +/** @file newgrf_animation_base.h Function implementations related to NewGRF animation. */ + +/* No inclusion guards as this file must only be included from .cpp files. */ + +/** + * Helper class for a unified approach to NewGRF animation. + * @tparam Tbase Instantiation of this class. + * @tparam Tspec NewGRF specification related to the animated tile. + * @tparam Tobj Object related to the animated tile. + * @tparam GetCallback The callback function pointer. + */ +template <typename Tbase, typename Tspec, typename Tobj, uint16 (*GetCallback)(CallbackID callback, uint32 param1, uint32 param2, const Tspec *statspec, const Tobj *st, TileIndex tile)> +struct AnimationBase { + /** + * Animate a single tile. + * @param cb The callback to actually call. + * @param spec Specification related to the tile. + * @param obj Object related to the tile. + * @param tile Tile to animate changes for. + * @param random_animation Whether to pass random bits to the "next frame" callback. + */ + static void AnimateTile(const Tspec *spec, const Tobj *obj, TileIndex tile, bool random_animation) + { + assert(spec != NULL); + + /* Acquire the animation speed from the NewGRF. */ + uint8 animation_speed = spec->animation.speed; + if (HasBit(spec->callback_mask, Tbase::cbm_animation_speed)) { + uint16 callback = GetCallback(Tbase::cb_animation_speed, 0, 0, spec, obj, tile); + if (callback != CALLBACK_FAILED) animation_speed = Clamp(callback & 0xFF, 0, 16); + } + + /* An animation speed of 2 means the animation frame changes 4 ticks, and + * increasing this value by one doubles the wait. 0 is the minimum value + * allowed for animation_speed, which corresponds to 30ms, and 16 is the + * maximum, corresponding to around 33 minutes. */ + if (_tick_counter % (1 << animation_speed) != 0) return; + + uint8 frame = GetAnimationFrame(tile); + uint8 num_frames = spec->animation.frames; + + bool frame_set_by_callback = false; + + if (HasBit(spec->callback_mask, Tbase::cbm_animation_next_frame)) { + uint16 callback = GetCallback(Tbase::cb_animation_next_frame, random_animation ? Random() : 0, 0, spec, obj, tile); + + if (callback != CALLBACK_FAILED) { + frame_set_by_callback = true; + + switch (callback & 0xFF) { + case 0xFF: + DeleteAnimatedTile(tile); + break; + + case 0xFE: + frame_set_by_callback = false; + break; + + default: + frame = callback & 0xFF; + break; + } + + /* If the lower 7 bits of the upper byte of the callback + * result are not empty, it is a sound effect. */ + if (GB(callback, 8, 7) != 0) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile); + } + } + + if (!frame_set_by_callback) { + if (frame < num_frames) { + frame++; + } else if (frame == num_frames && spec->animation.status == ANIM_STATUS_LOOPING) { + /* This animation loops, so start again from the beginning */ + frame = 0; + } else { + /* This animation doesn't loop, so stay here */ + DeleteAnimatedTile(tile); + } + } + + SetAnimationFrame(tile, frame); + MarkTileDirtyByTile(tile); + } + + /** + * Check a callback to determine what the next animation step is and + * execute that step. This includes stopping and starting animations + * as well as updating animation frames and playing sounds. + * @param cb The callback to actually call. + * @param spec Specification related to the tile. + * @param obj Object related to the tile. + * @param tile Tile to consider animation changes for. + * @param random_bits Random bits for this update. To be passed as parameter to the NewGRF. + * @param trigger What triggered this update? To be passed as parameter to the NewGRF. + */ + static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, const Tobj *obj, TileIndex tile, uint32 random_bits, uint32 trigger) + { + uint16 callback = GetCallback(cb, random_bits, trigger, spec, obj, tile); + if (callback == CALLBACK_FAILED) return; + + switch (callback & 0xFF) { + case 0xFD: /* Do nothing. */ break; + case 0xFE: AddAnimatedTile(tile); break; + case 0xFF: DeleteAnimatedTile(tile); break; + default: + SetAnimationFrame(tile, callback); + AddAnimatedTile(tile); + break; + } + + /* If the lower 7 bits of the upper byte of the callback + * result are not empty, it is a sound effect. */ + if (GB(callback, 8, 7) != 0) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile); + } +}; diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 4509cbeac..da4980b95 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -28,6 +28,7 @@ #include "sprite.h" #include "genworld.h" #include "date_func.h" +#include "newgrf_animation_base.h" static BuildingCounts<uint32> _building_counts; static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; @@ -471,82 +472,36 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id) } } -void AnimateNewHouseTile(TileIndex tile) +/* Simple wrapper for GetHouseCallback to keep the animation unified. */ +uint16 GetSimpleHouseCallback(CallbackID callback, uint32 param1, uint32 param2, const HouseSpec *spec, const Town *town, TileIndex tile) { - const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); - byte animation_speed = hs->animation.speed; - bool frame_set_by_callback = false; - - if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_SPEED)) { - uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); - if (callback_res != CALLBACK_FAILED) animation_speed = Clamp(callback_res & 0xFF, 2, 16); - } + return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile); +} - /* An animation speed of 2 means the animation frame changes 4 ticks, and - * increasing this value by one doubles the wait. 2 is the minimum value - * allowed for animation_speed, which corresponds to 120ms, and 16 is the - * maximum, corresponding to around 33 minutes. */ - if (_tick_counter % (1 << animation_speed) != 0) return; - - byte frame = GetAnimationFrame(tile); - byte num_frames = hs->animation.frames; - - if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_NEXT_FRAME)) { - uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0; - uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), Town::GetByTile(tile), tile); - - if (callback_res != CALLBACK_FAILED) { - frame_set_by_callback = true; - - switch (callback_res & 0xFF) { - case 0xFF: - DeleteAnimatedTile(tile); - break; - case 0xFE: - /* Carry on as normal. */ - frame_set_by_callback = false; - break; - default: - frame = callback_res & 0xFF; - break; - } +/** Helper class for animation control. */ +struct HouseAnimationBase : public AnimationBase<HouseAnimationBase, HouseSpec, Town, GetSimpleHouseCallback> { + static const CallbackID cb_animation_speed = CBID_HOUSE_ANIMATION_SPEED; + static const CallbackID cb_animation_next_frame = CBID_HOUSE_ANIMATION_NEXT_FRAME; - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback_res, 8, 7) != 0) PlayTileSound(hs->grf_prop.grffile, GB(callback_res, 8, 7), tile); - } - } + static const HouseCallbackMask cbm_animation_speed = CBM_HOUSE_ANIMATION_SPEED; + static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME; +}; - if (!frame_set_by_callback) { - if (frame < num_frames) { - frame++; - } else if (frame == num_frames && hs->animation.status == ANIM_STATUS_LOOPING) { - /* This animation loops, so start again from the beginning */ - frame = 0; - } else { - /* This animation doesn't loop, so stay here */ - DeleteAnimatedTile(tile); - } - } +void AnimateNewHouseTile(TileIndex tile) +{ + const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); + if (hs == NULL) return; - SetAnimationFrame(tile, frame); - MarkTileDirtyByTile(tile); + HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasBit(hs->extra_flags, CALLBACK_1A_RANDOM_BITS)); } -void ChangeHouseAnimationFrame(const GRFFile *file, TileIndex tile, uint16 callback_result) +void AnimateNewHouseConstruction(TileIndex tile) { - switch (callback_result & 0xFF) { - case 0xFD: /* Do nothing. */ break; - case 0xFE: AddAnimatedTile(tile); break; - case 0xFF: DeleteAnimatedTile(tile); break; - default: - SetAnimationFrame(tile, callback_result & 0xFF); - AddAnimatedTile(tile); - break; + const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); + + if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) { + HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, hs, Town::GetByTile(tile), tile, 0, 0); } - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback_result, 8, 7) != 0) PlayTileSound(file, GB(callback_result, 8, 7), tile); } bool CanDeleteHouse(TileIndex tile) @@ -573,9 +528,7 @@ static void AnimationControl(TileIndex tile, uint16 random_bits) if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); - uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), Town::GetByTile(tile), tile); - - if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grf_prop.grffile, tile, callback_res); + HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0); } } diff --git a/src/newgrf_house.h b/src/newgrf_house.h index 7a2b00acf..1b24a6747 100644 --- a/src/newgrf_house.h +++ b/src/newgrf_house.h @@ -42,7 +42,7 @@ void DecreaseBuildingCount(Town *t, HouseID house_id); void DrawNewHouseTile(TileInfo *ti, HouseID house_id); void AnimateNewHouseTile(TileIndex tile); -void ChangeHouseAnimationFrame(const struct GRFFile *file, TileIndex tile, uint16 callback_result); +void AnimateNewHouseConstruction(TileIndex tile); uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, const Town *town, TileIndex tile, bool not_yet_constructed = false, uint8 initial_random_bits = 0); diff --git a/src/newgrf_industrytiles.cpp b/src/newgrf_industrytiles.cpp index 291d4df75..c319c44b2 100644 --- a/src/newgrf_industrytiles.cpp +++ b/src/newgrf_industrytiles.cpp @@ -27,6 +27,7 @@ #include "water.h" #include "sprite.h" #include "date_func.h" +#include "newgrf_animation_base.h" #include "table/strings.h" @@ -297,99 +298,36 @@ CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind } } -void AnimateNewIndustryTile(TileIndex tile) +/* Simple wrapper for GetHouseCallback to keep the animation unified. */ +uint16 GetSimpleIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, const IndustryTileSpec *spec, const Industry *ind, TileIndex tile) { - Industry *ind = Industry::GetByTile(tile); - IndustryGfx gfx = GetIndustryGfx(tile); - const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); - byte animation_speed = itspec->animation.speed; - - if (HasBit(itspec->callback_mask, CBM_INDT_ANIM_SPEED)) { - uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIMATION_SPEED, 0, 0, gfx, ind, tile); - if (callback_res != CALLBACK_FAILED) animation_speed = Clamp(callback_res & 0xFF, 0, 16); - } - - /* An animation speed of 2 means the animation frame changes 4 ticks, and - * increasing this value by one doubles the wait. 0 is the minimum value - * allowed for animation_speed, which corresponds to 30ms, and 16 is the - * maximum, corresponding to around 33 minutes. */ - if ((_tick_counter % (1 << animation_speed)) != 0) return; - - bool frame_set_by_callback = false; - byte frame = GetAnimationFrame(tile); - uint16 num_frames = itspec->animation.frames; - - if (HasBit(itspec->callback_mask, CBM_INDT_ANIM_NEXT_FRAME)) { - uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_NEXT_FRAME, - (itspec->special_flags & INDTILE_SPECIAL_NEXTFRAME_RANDOMBITS) ? Random() : 0, 0, gfx, ind, tile); - - if (callback_res != CALLBACK_FAILED) { - frame_set_by_callback = true; - - switch (callback_res & 0xFF) { - case 0xFF: - DeleteAnimatedTile(tile); - break; - case 0xFE: - /* Carry on as normal. */ - frame_set_by_callback = false; - break; - default: - frame = callback_res & 0xFF; - break; - } - - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback_res, 8, 7) != 0) PlayTileSound(itspec->grf_prop.grffile, GB(callback_res, 8, 7), tile); - } - } + return GetIndustryTileCallback(callback, param1, param2, spec - GetIndustryTileSpec(0), const_cast<Industry *>(ind), tile); +} - if (!frame_set_by_callback) { - if (frame < num_frames) { - frame++; - } else if (frame == num_frames && itspec->animation.status == ANIM_STATUS_LOOPING) { - /* This animation loops, so start again from the beginning */ - frame = 0; - } else { - /* This animation doesn't loop, so stay here */ - DeleteAnimatedTile(tile); - } - } +/** Helper class for animation control. */ +struct IndustryAnimationBase : public AnimationBase<IndustryAnimationBase, IndustryTileSpec, Industry, GetSimpleIndustryCallback> { + static const CallbackID cb_animation_speed = CBID_INDTILE_ANIMATION_SPEED; + static const CallbackID cb_animation_next_frame = CBID_INDTILE_ANIM_NEXT_FRAME; - SetAnimationFrame(tile, frame); - MarkTileDirtyByTile(tile); -} + static const IndustryTileCallbackMask cbm_animation_speed = CBM_INDT_ANIM_SPEED; + static const IndustryTileCallbackMask cbm_animation_next_frame = CBM_INDT_ANIM_NEXT_FRAME; +}; -static void ChangeIndustryTileAnimationFrame(const IndustryTileSpec *itspec, TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind) +void AnimateNewIndustryTile(TileIndex tile) { - uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_START_STOP, random_bits, iat, gfx, ind, tile); - if (callback_res == CALLBACK_FAILED) return; - - switch (callback_res & 0xFF) { - case 0xFD: /* Do nothing. */ break; - case 0xFE: AddAnimatedTile(tile); break; - case 0xFF: DeleteAnimatedTile(tile); break; - default: - SetAnimationFrame(tile, callback_res & 0xFF); - AddAnimatedTile(tile); - break; - } + const IndustryTileSpec *itspec = GetIndustryTileSpec(GetIndustryGfx(tile)); + if (itspec == NULL) return; - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback_res, 8, 7) != 0) PlayTileSound(itspec->grf_prop.grffile, GB(callback_res, 8, 7), tile); + IndustryAnimationBase::AnimateTile(itspec, Industry::GetByTile(tile), tile, (itspec->special_flags & INDTILE_SPECIAL_NEXTFRAME_RANDOMBITS) != 0); } bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random) { - IndustryGfx gfx = GetIndustryGfx(tile); - const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); + const IndustryTileSpec *itspec = GetIndustryTileSpec(GetIndustryGfx(tile)); if (!HasBit(itspec->animation.triggers, iat)) return false; - Industry *ind = Industry::GetByTile(tile); - ChangeIndustryTileAnimationFrame(itspec, tile, iat, random, gfx, ind); + IndustryAnimationBase::ChangeAnimationFrame(CBID_INDTILE_ANIM_START_STOP, itspec, Industry::GetByTile(tile), tile, random, iat); return true; } diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index a95dad40c..6def19a8b 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -29,6 +29,7 @@ #include "tunnelbridge_map.h" #include "newgrf.h" #include "core/random_func.hpp" +#include "newgrf_animation_base.h" #include "newgrf_class_func.h" #include "table/strings.h" @@ -811,89 +812,21 @@ bool IsStationTileElectrifiable(TileIndex tile) !HasBit(statspec->wires, GetStationGfx(tile)); } +/** Helper class for animation control. */ +struct StationAnimationBase : public AnimationBase<StationAnimationBase, StationSpec, BaseStation, GetStationCallback> { + static const CallbackID cb_animation_speed = CBID_STATION_ANIMATION_SPEED; + static const CallbackID cb_animation_next_frame = CBID_STATION_ANIM_NEXT_FRAME; + + static const StationCallbackMask cbm_animation_speed = CBM_STATION_ANIMATION_SPEED; + static const StationCallbackMask cbm_animation_next_frame = CBM_STATION_ANIMATION_NEXT_FRAME; +}; + void AnimateStationTile(TileIndex tile) { const StationSpec *ss = GetStationSpec(tile); if (ss == NULL) return; - const BaseStation *st = BaseStation::GetByTile(tile); - - uint8 animation_speed = ss->animation.speed; - - if (HasBit(ss->callback_mask, CBM_STATION_ANIMATION_SPEED)) { - uint16 callback = GetStationCallback(CBID_STATION_ANIMATION_SPEED, 0, 0, ss, st, tile); - if (callback != CALLBACK_FAILED) animation_speed = Clamp(callback & 0xFF, 0, 16); - } - - if (_tick_counter % (1 << animation_speed) != 0) return; - - uint8 frame = GetAnimationFrame(tile); - uint8 num_frames = ss->animation.frames; - - bool frame_set_by_callback = false; - - if (HasBit(ss->callback_mask, CBM_STATION_ANIMATION_NEXT_FRAME)) { - uint32 param = HasBit(ss->flags, SSF_CB141_RANDOM_BITS) ? Random() : 0; - uint16 callback = GetStationCallback(CBID_STATION_ANIM_NEXT_FRAME, param, 0, ss, st, tile); - - if (callback != CALLBACK_FAILED) { - frame_set_by_callback = true; - - switch (callback & 0xFF) { - case 0xFF: - DeleteAnimatedTile(tile); - break; - - case 0xFE: - frame_set_by_callback = false; - break; - - default: - frame = callback & 0xFF; - break; - } - - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback, 8, 7) != 0) PlayTileSound(ss->grf_prop.grffile, GB(callback, 8, 7), tile); - } - } - - if (!frame_set_by_callback) { - if (frame < num_frames) { - frame++; - } else if (frame == num_frames && ss->animation.status == ANIM_STATUS_LOOPING) { - /* This animation loops, so start again from the beginning */ - frame = 0; - } else { - /* This animation doesn't loop, so stay here */ - DeleteAnimatedTile(tile); - } - } - - SetAnimationFrame(tile, frame); - MarkTileDirtyByTile(tile); -} - - -static void ChangeStationAnimationFrame(const StationSpec *ss, const BaseStation *st, TileIndex tile, uint16 random_bits, StationAnimationTrigger trigger, CargoID cargo_type) -{ - uint16 callback = GetStationCallback(CBID_STATION_ANIM_START_STOP, (random_bits << 16) | Random(), (uint8)trigger | (cargo_type << 8), ss, st, tile); - if (callback == CALLBACK_FAILED) return; - - switch (callback & 0xFF) { - case 0xFD: /* Do nothing. */ break; - case 0xFE: AddAnimatedTile(tile); break; - case 0xFF: DeleteAnimatedTile(tile); break; - default: - SetAnimationFrame(tile, callback); - AddAnimatedTile(tile); - break; - } - - /* If the lower 7 bits of the upper byte of the callback - * result are not empty, it is a sound effect. */ - if (GB(callback, 8, 7) != 0) PlayTileSound(ss->grf_prop.grffile, GB(callback, 8, 7), tile); + StationAnimationBase::AnimateTile(ss, BaseStation::GetByTile(tile), tile, HasBit(ss->flags, SSF_CB141_RANDOM_BITS)); } void TriggerStationAnimation(const BaseStation *st, TileIndex tile, StationAnimationTrigger trigger, CargoID cargo_type) @@ -924,7 +857,7 @@ void TriggerStationAnimation(const BaseStation *st, TileIndex tile, StationAnima } else { cargo = GetReverseCargoTranslation(cargo_type, ss->grf_prop.grffile); } - ChangeStationAnimationFrame(ss, st, tile, random_bits, trigger, cargo); + StationAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIM_START_STOP, ss, st, tile, (random_bits << 16) | Random(), (uint8)trigger | (cargo << 8)); } } } diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index f71768e54..47a858946 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -411,18 +411,12 @@ static void MakeSingleHouseBigger(TileIndex tile) IncHouseConstructionTick(tile); if (GetHouseConstructionTick(tile) != 0) return; - const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); - - /* Check and/or */ - if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) { - uint16 callback_res = GetHouseCallback(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); - if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grf_prop.grffile, tile, callback_res); - } + AnimateNewHouseConstruction(tile); if (IsHouseCompleted(tile)) { /* Now that construction is complete, we can add the population of the * building to the town. */ - ChangePopulation(Town::GetByTile(tile), hs->population); + ChangePopulation(Town::GetByTile(tile), HouseSpec::Get(GetHouseType(tile))->population); ResetHouseAge(tile); } MarkTileDirtyByTile(tile); |