Changeset - r15929:5d5037945a0e
[Not reviewed]
master
0 6 1
rubidium - 14 years ago 2010-08-26 17:01:17
rubidium@openttd.org
(svn r20627) -Codechange: unify the animation code of station, airport, house and industry tiles
7 files changed with 194 insertions and 317 deletions:
0 comments (0 inline, 0 general)
src/newgrf_airporttiles.cpp
Show inline comments
 
@@ -25,12 +25,13 @@
 
#include "town.h"
 
#include "functions.h"
 
#include "core/random_func.hpp"
 
#include "table/strings.h"
 
#include "table/airporttiles.h"
 
#include "date_func.h"
 
#include "newgrf_animation_base.h"
 

	
 

	
 
AirportTileSpec AirportTileSpec::tiles[NUM_AIRPORTTILES];
 

	
 
AirportTileOverrideManager _airporttile_mngr(NEW_AIRPORTTILE_OFFSET, NUM_AIRPORTTILES, INVALID_AIRPORTTILE);
 

	
 
@@ -309,102 +310,35 @@ bool DrawNewAirportTile(TileInfo *ti, St
 

	
 
	const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group;
 
	AirportDrawTileLayout(ti, tlgroup, Company::Get(st->owner)->colour, gfx);
 
	return true;
 
}
 

	
 
/** 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;
 

	
 
	static const AirportTileCallbackMask cbm_animation_speed      = CBM_AIRT_ANIM_SPEED;
 
	static const AirportTileCallbackMask cbm_animation_next_frame = CBM_AIRT_ANIM_NEXT_FRAME;
 
};
 

	
 
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);
 
	}
 

	
 
	/* 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;
 
			}
 
	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);
 
		}
 
	}
 

	
 
	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)
 
{
 
	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;
 
	}
 

	
 
	/* 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)
 
{
 
	if (st->airport.tile == INVALID_TILE) return;
 

	
src/newgrf_animation_base.h
Show inline comments
 
new file 100644
 
/* $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);
 
	}
 
};
src/newgrf_house.cpp
Show inline comments
 
@@ -25,12 +25,13 @@
 
#include "company_base.h"
 
#include "town.h"
 
#include "core/random_func.hpp"
 
#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];
 

	
 
HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, HOUSE_MAX, INVALID_HOUSE_ID);
 

	
 
@@ -468,88 +469,42 @@ void DrawNewHouseTile(TileInfo *ti, Hous
 
		byte stage = GetHouseBuildingStage(ti->tile);
 
		stage = Clamp(stage - 4 + tlgroup->num_building_stages, 0, tlgroup->num_building_stages - 1);
 
		DrawTileLayout(ti, tlgroup, stage, house_id);
 
	}
 
}
 

	
 
/* 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)
 
{
 
	return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile);
 
}
 

	
 
/** 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;
 

	
 
	static const HouseCallbackMask cbm_animation_speed      = CBM_HOUSE_ANIMATION_SPEED;
 
	static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME;
 
};
 

	
 
void AnimateNewHouseTile(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);
 
	}
 

	
 
	/* 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 (hs == NULL) return;
 

	
 
	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;
 
	HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasBit(hs->extra_flags, CALLBACK_1A_RANDOM_BITS));
 
			}
 

	
 
			/* 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);
 
		}
 
	}
 

	
 
	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 AnimateNewHouseConstruction(TileIndex tile)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 

	
 
	SetAnimationFrame(tile, frame);
 
	MarkTileDirtyByTile(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);
 
}
 

	
 
void ChangeHouseAnimationFrame(const GRFFile *file, TileIndex tile, uint16 callback_result)
 
{
 
	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;
 
	}
 
	/* 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)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 

	
 
@@ -570,15 +525,13 @@ bool CanDeleteHouse(TileIndex tile)
 
static void AnimationControl(TileIndex tile, uint16 random_bits)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
 

	
 
	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);
 
	}
 
}
 

	
 
bool NewHouseTileLoop(TileIndex tile)
 
{
 
	const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile));
src/newgrf_house.h
Show inline comments
 
@@ -39,13 +39,13 @@ HouseClassID AllocateHouseClassID(byte g
 
void InitializeBuildingCounts();
 
void IncreaseBuildingCount(Town *t, HouseID house_id);
 
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);
 

	
 
bool CanDeleteHouse(TileIndex tile);
 

	
 
bool NewHouseTileLoop(TileIndex tile);
src/newgrf_industrytiles.cpp
Show inline comments
 
@@ -24,12 +24,13 @@
 
#include "town.h"
 
#include "command_func.h"
 
#include "animated_tile_func.h"
 
#include "water.h"
 
#include "sprite.h"
 
#include "date_func.h"
 
#include "newgrf_animation_base.h"
 

	
 
#include "table/strings.h"
 

	
 
/**
 
 * Based on newhouses equivalent, but adapted for newindustries
 
 * @param parameter from callback.  It's in fact a pair of coordinates
 
@@ -294,105 +295,42 @@ CommandCost PerformIndustryTileSlopeChec
 
		case 0x402: return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST);
 
		case 0x403: return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT);
 
		default:    return_cmd_error(GetGRFStringID(its->grf_prop.grffile->grfid, 0xD000 + callback_res));
 
	}
 
}
 

	
 
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);
 
	return GetIndustryTileCallback(callback, param1, param2, spec - GetIndustryTileSpec(0), const_cast<Industry *>(ind), tile);
 
	}
 

	
 
	/* 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;
 
			}
 
/** 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;
 

	
 
			/* 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);
 
		}
 
	}
 

	
 
	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);
 
		}
 
	}
 
	static const IndustryTileCallbackMask cbm_animation_speed      = CBM_INDT_ANIM_SPEED;
 
	static const IndustryTileCallbackMask cbm_animation_next_frame = CBM_INDT_ANIM_NEXT_FRAME;
 
};
 

	
 
	SetAnimationFrame(tile, frame);
 
	MarkTileDirtyByTile(tile);
 
}
 

	
 
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;
 
	const IndustryTileSpec *itspec = GetIndustryTileSpec(GetIndustryGfx(tile));
 
	if (itspec == NULL) 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;
 
	}
 

	
 
	/* 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;
 
}
 

	
 
bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat)
 
{
 
	bool ret = true;
src/newgrf_station.cpp
Show inline comments
 
@@ -26,12 +26,13 @@
 
#include "company_func.h"
 
#include "animated_tile_func.h"
 
#include "functions.h"
 
#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"
 

	
 
template <typename Tspec, typename Tid, Tid Tmax>
 
/* static */ void NewGRFClass<Tspec, Tid, Tmax>::InsertDefaults()
 
@@ -808,95 +809,27 @@ bool IsStationTileElectrifiable(TileInde
 
	return
 
		statspec == NULL ||
 
		HasBit(statspec->pylons, GetStationGfx(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)
 
{
 
	/* List of coverage areas for each animation trigger */
 
	static const TriggerArea tas[] = {
 
@@ -921,13 +854,13 @@ void TriggerStationAnimation(const BaseS
 
				CargoID cargo;
 
				if (cargo_type == CT_INVALID) {
 
					cargo = CT_INVALID;
 
				} 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));
 
			}
 
		}
 
	}
 
}
 

	
 
/**
src/town_cmd.cpp
Show inline comments
 
@@ -408,24 +408,18 @@ static void MakeSingleHouseBigger(TileIn
 
	if (LiftHasDestination(tile)) return;
 

	
 
	/* progress in construction stages */
 
	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);
 
}
 

	
 
/**
0 comments (0 inline, 0 general)