Changeset - r9003:0b0148ae8377
[Not reviewed]
master
0 8 0
peter1138 - 16 years ago 2008-04-19 23:19:12
peter1138@openttd.org
(svn r12798) -Feature: Add some support for NewGRF station animation. (Thanks to mart3p for samples and fixes)
8 files changed with 251 insertions and 17 deletions:
0 comments (0 inline, 0 general)
src/economy.cpp
Show inline comments
 
@@ -23,12 +23,13 @@
 
#include "aircraft.h"
 
#include "newgrf_engine.h"
 
#include "newgrf_sound.h"
 
#include "newgrf_callbacks.h"
 
#include "newgrf_industries.h"
 
#include "newgrf_industrytiles.h"
 
#include "newgrf_station.h"
 
#include "unmovable.h"
 
#include "cargotype.h"
 
#include "player_face.h"
 
#include "group.h"
 
#include "strings_func.h"
 
#include "tile_cmd.h"
 
@@ -1688,12 +1689,14 @@ static void LoadUnloadVehicle(Vehicle *v
 

	
 
			ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, st->xy);
 

	
 
			st->time_since_load = 0;
 
			st->last_vehicle_type = v->type;
 

	
 
			StationAnimationTrigger(st, st->xy, STAT_ANIM_CARGO_TAKEN, v->cargo_type);
 

	
 
			unloading_time += cap;
 

	
 
			result |= 2;
 
		}
 

	
 
		if (v->cargo.Count() == v->cargo_cap) {
src/newgrf.cpp
Show inline comments
 
@@ -1117,25 +1117,23 @@ static bool StationChangeInfo(uint stid,
 
				break;
 

	
 
			case 0x15: // Blocked tiles
 
				statspec->blocked = grf_load_byte(&buf);
 
				break;
 

	
 
			case 0x16: // @todo Animation info
 
				grf_load_word(&buf);
 
				ret = true;
 
				break;
 

	
 
			case 0x17: // @todo Animation speed
 
				grf_load_byte(&buf);
 
				ret = true;
 
				break;
 

	
 
			case 0x18: // @todo Animation triggers
 
				grf_load_word(&buf);
 
				ret = true;
 
			case 0x16: // Animation info
 
				statspec->anim_frames = grf_load_byte(&buf);
 
				statspec->anim_status = grf_load_byte(&buf);
 
				break;
 

	
 
			case 0x17: // Animation speed
 
				statspec->anim_speed = grf_load_byte(&buf);
 
				break;
 

	
 
			case 0x18: // Animation triggers
 
				statspec->anim_triggers = grf_load_word(&buf);
 
				break;
 

	
 
			default:
 
				ret = true;
 
				break;
 
		}
src/newgrf_callbacks.h
Show inline comments
 
@@ -170,19 +170,19 @@ enum CallbackID {
 
	/** Called to determine if the industry can still accept or refuse more cargo arrival */
 
	CBID_INDUSTRY_REFUSE_CARGO           = 0x3D,
 

	
 
	/* There are no callbacks 0x3E - 0x13F */
 

	
 
	/** Called for periodically starting or stopping the animation. */
 
	CBID_STATION_ANIM_START_STOP         = 0x140, // not implemented
 
	CBID_STATION_ANIM_START_STOP         = 0x140,
 

	
 
	/** Called to determine station tile next animation frame. */
 
	CBID_STATION_ANIM_NEXT_FRAME         = 0x141, // not implemented
 
	CBID_STATION_ANIM_NEXT_FRAME         = 0x141,
 

	
 
	/** Called to indicate how long the current animation frame should last. */
 
	CBID_STATION_ANIMATION_SPEED         = 0x142, // not implemented
 
	CBID_STATION_ANIMATION_SPEED         = 0x142,
 

	
 
	/** Called to determine whether a town building can be destroyed. */
 
	CBID_HOUSE_DENY_DESTRUCTION          = 0x143,
 

	
 
	/** Select an ambient sound to play for a given type of tile. */
 
	CBID_SOUNDS_AMBIENT_EFFECT           = 0x144, // not implemented
src/newgrf_station.cpp
Show inline comments
 
@@ -737,14 +737,18 @@ void DeallocateSpecFromStation(Station* 
 
		if (st->num_specs > 1) {
 
			st->speclist = ReallocT(st->speclist, st->num_specs);
 
		} else {
 
			free(st->speclist);
 
			st->num_specs = 0;
 
			st->speclist  = NULL;
 
			st->cached_anim_triggers = 0;
 
			return;
 
		}
 
	}
 

	
 
	StationUpdateAnimTriggers(st);
 
}
 

	
 
/** Draw representation of a station tile for GUI purposes.
 
 * @param x Position x of image.
 
 * @param y Position y of image.
 
 * @param axis Axis.
 
@@ -850,6 +854,181 @@ bool IsStationTileElectrifiable(TileInde
 

	
 
	return
 
		statspec == NULL ||
 
		HasBit(statspec->pylons, GetStationGfx(tile)) ||
 
		!HasBit(statspec->wires, GetStationGfx(tile));
 
}
 

	
 
void AnimateStationTile(TileIndex tile)
 
{
 
	const StationSpec *ss = GetStationSpec(tile);
 
	if (ss == NULL) return;
 

	
 
	const Station *st = GetStationByTile(tile);
 

	
 
	uint8 animation_speed = ss->anim_speed;
 

	
 
	if (HasBit(ss->callbackmask, 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      = GetStationAnimationFrame(tile);
 
	uint8 num_frames = ss->anim_frames;
 

	
 
	bool frame_set_by_callback = false;
 

	
 
	if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_NEXT_FRAME)) {
 
		uint32 param = HasBit(ss->flags, 2) ? 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 (!frame_set_by_callback) {
 
		if (frame < num_frames) {
 
			frame++;
 
		} else if (frame == num_frames && HasBit(ss->anim_status, 0)) {
 
			/* This animation loops, so start again from the beginning */
 
			frame = 0;
 
		} else {
 
			/* This animation doesn't loop, so stay here */
 
			DeleteAnimatedTile(tile);
 
		}
 
	}
 

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

	
 

	
 
static void ChangeStationAnimationFrame(const StationSpec *ss, const Station *st, TileIndex tile, uint16 random_bits, StatAnimTrigger 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:
 
			SetStationAnimationFrame(tile, callback);
 
			AddAnimatedTile(tile);
 
			break;
 
	}
 
}
 

	
 
enum TriggerArea {
 
	TA_TILE,
 
	TA_PLATFORM,
 
	TA_WHOLE,
 
};
 

	
 
struct TileArea {
 
	TileIndex tile;
 
	uint8 w;
 
	uint8 h;
 

	
 
	TileArea(const Station *st, TileIndex tile, TriggerArea ta)
 
	{
 
		switch (ta) {
 
			default: NOT_REACHED();
 

	
 
			case TA_TILE:
 
				this->tile = tile;
 
				this->w    = 1;
 
				this->h    = 1;
 
				break;
 

	
 
			case TA_PLATFORM: {
 
				TileIndex start, end;
 
				Axis axis = GetRailStationAxis(tile);
 
				TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis));
 

	
 
				for (end = tile; IsRailwayStationTile(end + delta) && IsCompatibleTrainStationTile(tile, end + delta); end += delta);
 
				for (start = tile; IsRailwayStationTile(start - delta) && IsCompatibleTrainStationTile(tile, start - delta); start -= delta);
 

	
 
				this->tile = start;
 
				this->w = TileX(end) - TileX(start) + 1;
 
				this->h = TileY(end) - TileY(start) + 1;
 
				break;
 
			}
 

	
 
			case TA_WHOLE:
 
				this->tile = st->train_tile;
 
				this->w    = st->trainst_w + 1;
 
				this->h    = st->trainst_h + 1;
 
				break;
 
		}
 
	}
 
};
 

	
 
void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type)
 
{
 
	/* List of coverage areas for each animation trigger */
 
	static const TriggerArea tas[] = {
 
		TA_TILE, TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_WHOLE
 
	};
 

	
 
	/* Get Station if it wasn't supplied */
 
	if (st == NULL) st = GetStationByTile(tile);
 

	
 
	/* Check the cached animation trigger bitmask to see if we need
 
	 * to bother with any further processing. */
 
	if (!HasBit(st->cached_anim_triggers, trigger)) return;
 

	
 
	uint16 random_bits = Random();
 
	TileArea area = TileArea(st, tile, tas[trigger]);
 

	
 
	for (uint y = 0; y < area.h; y++) {
 
		for (uint x = 0; x < area.w; x++) {
 
			if (st->TileBelongsToRailStation(area.tile)) {
 
				const StationSpec *ss = GetStationSpec(area.tile);
 
				if (ss != NULL && HasBit(ss->anim_triggers, trigger)) {
 
					CargoID cargo;
 
					if (cargo_type == CT_INVALID) {
 
						cargo = CT_INVALID;
 
					} else {
 
						cargo = GetReverseCargoTranslation(cargo_type, ss->grffile);
 
					}
 
					ChangeStationAnimationFrame(ss, st, area.tile, random_bits, trigger, cargo);
 
				}
 
			}
 
			area.tile += TileDiffXY(1, 0);
 
		}
 
		area.tile += TileDiffXY(-area.w, 1);
 
	}
 
}
 

	
 
/**
 
 * Update the cached animation trigger bitmask for a station.
 
 * @param st Station to update.
 
 */
 
void StationUpdateAnimTriggers(Station *st)
 
{
 
	st->cached_anim_triggers = 0;
 

	
 
	/* Combine animation trigger bitmask for all station specs
 
	 * of this station. */
 
	for (uint i = 0; i < st->num_specs; i++) {
 
		const StationSpec *ss = st->speclist[i].spec;
 
		if (ss != NULL) st->cached_anim_triggers |= ss->anim_triggers;
 
	}
 
}
src/newgrf_station.h
Show inline comments
 
@@ -80,12 +80,17 @@ struct StationSpec {
 

	
 
	byte lengths;
 
	byte *platforms;
 
	StationLayout **layouts;
 
	bool copied_layouts;
 

	
 
	uint8  anim_frames;
 
	uint8  anim_status;
 
	uint8  anim_speed;
 
	uint16 anim_triggers;
 

	
 
	/**
 
	 * NUM_CARGO real cargo plus three pseudo cargo sprite groups.
 
	 * Used for obtaining the sprite offset of custom sprites, and for
 
	 * evaluating callbacks.
 
	 */
 
	const struct SpriteGroup *spritegroup[NUM_CARGO + 3];
 
@@ -129,7 +134,21 @@ int AllocateSpecToStation(const StationS
 
/* Deallocate a StationSpec from a Station. Called when removing a single station tile. */
 
void DeallocateSpecFromStation(Station* st, byte specindex);
 

	
 
/* Draw representation of a station tile for GUI purposes. */
 
bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station);
 

	
 
enum StatAnimTrigger {
 
	STAT_ANIM_BUILT,
 
	STAT_ANIM_NEW_CARGO,
 
	STAT_ANIM_CARGO_TAKEN,
 
	STAT_ANIM_TRAIN_ARRIVES,
 
	STAT_ANIM_TRAIN_DEPARTS,
 
	STAT_ANIM_TRAIN_LOADS,
 
	STAT_ANIM_250_TICKS,
 
};
 

	
 
void AnimateStationTile(TileIndex tile);
 
void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type = CT_INVALID);
 
void StationUpdateAnimTriggers(Station *st);
 

	
 
#endif /* NEWGRF_STATION_H */
src/station_base.h
Show inline comments
 
@@ -156,12 +156,13 @@ public:
 
	byte last_vehicle_type;
 
	std::list<Vehicle *> loading_vehicles;
 
	GoodsEntry goods[NUM_CARGO];
 

	
 
	uint16 random_bits;
 
	byte waiting_triggers;
 
	uint8 cached_anim_triggers; ///< Combined animation trigger bitmask, used to determine if trigger processing should happen.
 

	
 
	StationRect rect; ///< Station spread out rectangle (not saved) maintained by StationRect_xxx() functions
 

	
 
	static const int cDebugCtorLevel = 5;
 

	
 
	Station(TileIndex tile = 0);
src/station_cmd.cpp
Show inline comments
 
@@ -1035,12 +1035,18 @@ CommandCost CmdBuildRailroadStation(Tile
 

	
 
		st->trainst_w = finalvalues[1];
 
		st->trainst_h = finalvalues[2];
 

	
 
		st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY);
 

	
 
		if (statspec != NULL) {
 
			/* Include this station spec's animation trigger bitmask
 
			 * in the station's cached copy. */
 
			st->cached_anim_triggers |= statspec->anim_triggers;
 
		}
 

	
 
		tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
 
		track = AxisToTrack(axis);
 

	
 
		layout_ptr = (byte*)alloca(numtracks * plat_len);
 
		GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
 

	
 
@@ -1051,20 +1057,24 @@ CommandCost CmdBuildRailroadStation(Tile
 
			int w = plat_len;
 
			do {
 
				byte layout = *layout_ptr++;
 
				MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, (RailType)GB(p2, 0, 4));
 
				SetCustomStationSpecIndex(tile, specindex);
 
				SetStationTileRandomBits(tile, GB(Random(), 0, 4));
 
				SetStationAnimationFrame(tile, 0);
 

	
 
				if (statspec != NULL) {
 
					/* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
 
					uint32 platinfo = GetPlatformInfo(AXIS_X, 0, plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false);
 

	
 
					/* As the station is not yet completely finished, the station does not yet exist. */
 
					uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile);
 
					if (callback != CALLBACK_FAILED && callback < 8) SetStationGfx(tile, (callback & ~1) + axis);
 

	
 
					/* Trigger station animation -- after building? */
 
					StationAnimationTrigger(st, tile, STAT_ANIM_BUILT);
 
				}
 

	
 
				tile += tile_delta;
 
			} while (--w);
 
			AddTrackToSignalBuffer(tile_org, track, _current_player);
 
			YapfNotifyTrackLayoutChange(tile_org, track);
 
@@ -1280,12 +1290,13 @@ static CommandCost RemoveRailroadStation
 
		st->trainst_w = st->trainst_h = 0;
 
		st->facilities &= ~FACIL_TRAIN;
 

	
 
		free(st->speclist);
 
		st->num_specs = 0;
 
		st->speclist  = NULL;
 
		st->cached_anim_triggers = 0;
 

	
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		UpdateStationVirtCoordDirty(st);
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
@@ -2365,12 +2376,17 @@ static void AnimateTile_Station(TileInde
 
		{ GFX_RADAR_INTERNATIONAL_FIRST, GFX_RADAR_INTERNATIONAL_LAST, 3 },
 
		{ GFX_RADAR_METROPOLITAN_FIRST,  GFX_RADAR_METROPOLITAN_LAST,  3 },
 
		{ GFX_RADAR_DISTRICTWE_FIRST,    GFX_RADAR_DISTRICTWE_LAST,    3 },
 
		{ GFX_WINDSACK_INTERCON_FIRST,   GFX_WINDSACK_INTERCON_LAST,   1 }
 
	};
 

	
 
	if (IsRailwayStation(tile)) {
 
		AnimateStationTile(tile);
 
		return;
 
	}
 

	
 
	StationGfx gfx = GetStationGfx(tile);
 

	
 
	for (const AnimData *i = data; i != endof(data); i++) {
 
		if (i->from <= gfx && gfx <= i->to) {
 
			if ((_tick_counter & i->delay) == 0) {
 
				SetStationGfx(tile, gfx < i->to ? gfx + 1 : i->from);
 
@@ -2611,13 +2627,22 @@ void OnTick_Station()
 
	uint i = _station_tick_ctr;
 
	if (++_station_tick_ctr > GetMaxStationIndex()) _station_tick_ctr = 0;
 

	
 
	if (IsValidStationID(i)) StationHandleBigTick(GetStation(i));
 

	
 
	Station *st;
 
	FOR_ALL_STATIONS(st) StationHandleSmallTick(st);
 
	FOR_ALL_STATIONS(st) {
 
		StationHandleSmallTick(st);
 

	
 
		/* Run 250 tick interval trigger for station animation.
 
		 * Station index is included so that triggers are not all done
 
		 * at the same time. */
 
		if ((_tick_counter + st->index) % 250 == 0) {
 
			StationAnimationTrigger(st, st->xy, STAT_ANIM_250_TICKS);
 
		}
 
	}
 
}
 

	
 
void StationMonthlyLoop()
 
{
 
	/* not used */
 
}
 
@@ -2643,12 +2668,14 @@ void ModifyStationRatingAround(TileIndex
 

	
 
static void UpdateStationWaiting(Station *st, CargoID type, uint amount)
 
{
 
	st->goods[type].cargo.Append(new CargoPacket(st->index, amount));
 
	SetBit(st->goods[type].acceptance_pickup, GoodsEntry::PICKUP);
 

	
 
	StationAnimationTrigger(st, st->xy, STAT_ANIM_NEW_CARGO, type);
 

	
 
	InvalidateWindow(WC_STATION_VIEW, st->index);
 
	st->MarkTilesDirty(true);
 
}
 

	
 
static bool IsUniqueStationName(const char *name)
 
{
 
@@ -3005,12 +3032,14 @@ void AfterLoadStations()
 
			if (st->speclist[i].grfid == 0) continue;
 

	
 
			st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
 
		}
 

	
 
		for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
 

	
 
		StationUpdateAnimTriggers(st);
 
	}
 
}
 

	
 
static CommandCost TerraformTile_Station(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
 
{
 
	if (_patches.build_on_slopes && AutoslopeEnabled()) {
src/train_cmd.cpp
Show inline comments
 
@@ -45,12 +45,13 @@
 
#include "signal_func.h"
 
#include "variables.h"
 
#include "autoreplace_gui.h"
 
#include "gfx_func.h"
 
#include "settings_type.h"
 
#include "order_func.h"
 
#include "newgrf_station.h"
 

	
 
#include "table/strings.h"
 
#include "table/train_cmd.h"
 

	
 
static bool TrainCheckIfLineEnds(Vehicle *v);
 
static void TrainController(Vehicle *v, Vehicle *nomove, bool update_image);
 
@@ -2215,12 +2216,14 @@ void Train::PlayLeaveStationSound() cons
 
		SND_0A_TRAIN_HORN,
 
		SND_0A_TRAIN_HORN,
 
		SND_47_MAGLEV_2,
 
		SND_41_MAGLEV
 
	};
 

	
 
	if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(NULL, this->tile, STAT_ANIM_TRAIN_DEPARTS);
 

	
 
	if (PlayVehicleSound(this, VSE_START)) return;
 

	
 
	EngineID engtype = this->engine_type;
 
	SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
 
}
 

	
 
@@ -2635,12 +2638,14 @@ static void TrainEnterStation(Vehicle *v
 
			v->index,
 
			0
 
		);
 
	}
 

	
 
	v->BeginLoading();
 

	
 
	StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES);
 
}
 

	
 
static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
 
{
 
	byte old_z = v->z_pos;
 
	v->z_pos = GetSlopeZ(v->x_pos, v->y_pos);
0 comments (0 inline, 0 general)