Changeset - r19723:ed364738c640
[Not reviewed]
master
0 15 0
alberth - 12 years ago 2012-11-10 20:37:31
alberth@openttd.org
(svn r24678) -Codechange: Introduce scope resolver base class and prepare for adding derived classes.
15 files changed with 173 insertions and 29 deletions:
0 comments (0 inline, 0 general)
src/newgrf_airport.cpp
Show inline comments
 
@@ -172,97 +172,97 @@ static const SpriteGroup *AirportResolve
 

	
 
	return NULL;
 
}
 

	
 
static uint32 AirportGetRandomBits(const ResolverObject *object)
 
{
 
	const Station *st = object->u.airport.st;
 
	return st == NULL ? 0 : st->random_bits;
 
}
 

	
 
static uint32 AirportGetTriggers(const ResolverObject *object)
 
{
 
	return 0;
 
}
 

	
 
static void AirportSetTriggers(const ResolverObject *object, int triggers)
 
{
 
}
 

	
 
/**
 
 * Store a value into the object's persistent storage.
 
 * @param object Object that we want to query.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
 
 */
 
void AirportStorePSA(ResolverObject *object, uint pos, int32 value)
 
{
 
	Station *st = object->u.airport.st;
 
	if (object->scope != VSG_SCOPE_SELF || st == NULL) return;
 

	
 
	if (st->airport.psa == NULL) {
 
		/* There is no need to create a storage if the value is zero. */
 
		if (value == 0) return;
 

	
 
		/* Create storage on first modification. */
 
		uint32 grfid = (object->grffile != NULL) ? object->grffile->grfid : 0;
 
		assert(PersistentStorage::CanAllocateItem());
 
		st->airport.psa = new PersistentStorage(grfid);
 
	}
 
	st->airport.psa->StoreValue(pos, value);
 
}
 

	
 
static void NewAirportResolver(ResolverObject *res, TileIndex tile, Station *st, byte airport_id, byte layout)
 
{
 
	res->GetRandomBits = AirportGetRandomBits;
 
	res->GetTriggers   = AirportGetTriggers;
 
	res->SetTriggers   = AirportSetTriggers;
 
	res->GetVariable   = AirportGetVariable;
 
	res->ResolveReal   = AirportResolveReal;
 
	res->ResolveRealMethod = AirportResolveReal;
 
	res->StorePSA      = AirportStorePSA;
 

	
 
	res->u.airport.st         = st;
 
	res->u.airport.airport_id = airport_id;
 
	res->u.airport.layout     = layout;
 
	res->u.airport.tile       = tile;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	const AirportSpec *as = AirportSpec::Get(airport_id);
 
	res->grffile         = as->grf_prop.grffile;
 
}
 

	
 
SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout)
 
{
 
	const SpriteGroup *group;
 
	ResolverObject object;
 

	
 
	NewAirportResolver(&object, INVALID_TILE, NULL, as->GetIndex(), layout);
 

	
 
	group = SpriteGroup::Resolve(as->grf_prop.spritegroup[0], &object);
 
	if (group == NULL) return as->preview_sprite;
 

	
 
	return group->GetResult();
 
}
 

	
 
uint16 GetAirportCallback(CallbackID callback, uint32 param1, uint32 param2, Station *st, TileIndex tile)
 
{
 
	ResolverObject object;
 

	
 
	NewAirportResolver(&object, tile, st, st->airport.type, st->airport.layout);
 
	object.callback = callback;
 
	object.callback_param1 = param1;
 
	object.callback_param2 = param2;
 

	
 
	const SpriteGroup *group = SpriteGroup::Resolve(st->airport.GetSpec()->grf_prop.spritegroup[0], &object);
 
	if (group == NULL) return CALLBACK_FAILED;
 

	
 
	return group->GetCallbackResult();
 
}
 

	
 
/**
 
 * Get a custom text for the airport.
 
 * @param as The airport type's specification.
 
 * @param layout The layout index.
src/newgrf_airporttiles.cpp
Show inline comments
 
@@ -181,97 +181,97 @@ static uint32 AirportTileGetVariable(con
 

	
 
	switch (variable) {
 
		/* Terrain type */
 
		case 0x41: return GetTerrainType(tile);
 

	
 
		/* Current town zone of the tile in the nearest town */
 
		case 0x42: return GetTownRadiusGroup(ClosestTownFromTile(tile, UINT_MAX), tile);
 

	
 
		/* Position relative to most northern airport tile. */
 
		case 0x43: return GetRelativePosition(tile, st->airport.tile);
 

	
 
		/* Animation frame of tile */
 
		case 0x44: return GetAnimationFrame(tile);
 

	
 
		/* Land info of nearby tiles */
 
		case 0x60: return GetNearbyAirportTileInformation(parameter, tile, st->index, object->grffile->grf_version >= 8);
 

	
 
		/* Animation stage of nearby tiles */
 
		case 0x61:
 
			tile = GetNearbyTile(parameter, tile);
 
			if (st->TileBelongsToAirport(tile)) {
 
				return GetAnimationFrame(tile);
 
			}
 
			return UINT_MAX;
 

	
 
		/* Get airport tile ID at offset */
 
		case 0x62: return GetAirportTileIDAtOffset(GetNearbyTile(parameter, tile), st, object->grffile->grfid);
 
	}
 

	
 
	DEBUG(grf, 1, "Unhandled airport tile variable 0x%X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
static uint32 AirportTileGetRandomBits(const ResolverObject *object)
 
{
 
	const Station *st = object->u.airport.st;
 
	const TileIndex tile = object->u.airport.tile;
 
	return (st == NULL ? 0 : st->random_bits) | (tile == INVALID_TILE ? 0 : GetStationTileRandomBits(tile) << 16);
 
}
 

	
 
static void AirportTileResolver(ResolverObject *res, const AirportTileSpec *ats, TileIndex tile, Station *st)
 
{
 
	res->GetRandomBits = AirportTileGetRandomBits;
 
	res->GetTriggers   = NULL;
 
	res->SetTriggers   = NULL;
 
	res->GetVariable   = AirportTileGetVariable;
 
	res->ResolveReal   = AirportTileResolveReal;
 
	res->ResolveRealMethod = AirportTileResolveReal;
 
	res->StorePSA      = NULL;
 

	
 
	assert(st != NULL);
 
	res->u.airport.airport_id = st->airport.type;
 
	res->u.airport.st         = st;
 
	res->u.airport.tile       = tile;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	res->grffile         = ats->grf_prop.grffile;
 
}
 

	
 
uint16 GetAirportTileCallback(CallbackID callback, uint32 param1, uint32 param2, const AirportTileSpec *ats, Station *st, TileIndex tile, int extra_data = 0)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	AirportTileResolver(&object, ats, tile, st);
 
	object.callback = callback;
 
	object.callback_param1 = param1;
 
	object.callback_param2 = param2;
 

	
 
	group = SpriteGroup::Resolve(ats->grf_prop.spritegroup[0], &object);
 
	if (group == NULL) return CALLBACK_FAILED;
 

	
 
	return group->GetCallbackResult();
 
}
 

	
 
static void AirportDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte colour, StationGfx gfx)
 
{
 
	const DrawTileSprites *dts = group->ProcessRegisters(NULL);
 

	
 
	SpriteID image = dts->ground.sprite;
 
	SpriteID pal   = dts->ground.pal;
 

	
 
	if (GB(image, 0, SPRITE_WIDTH) != 0) {
 
		if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
 
			DrawWaterClassGround(ti);
 
		} else {
 
			DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, GENERAL_SPRITE_COLOUR(colour)));
 
		}
 
	}
 

	
 
	DrawNewGRFTileSeq(ti, dts, TO_BUILDINGS, 0, GENERAL_SPRITE_COLOUR(colour));
 
}
src/newgrf_canal.cpp
Show inline comments
 
@@ -37,97 +37,97 @@ static uint32 CanalGetTriggers(const Res
 

	
 
static void CanalSetTriggers(const ResolverObject *object, int triggers)
 
{
 
	return;
 
}
 

	
 

	
 
static uint32 CanalGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
 
{
 
	TileIndex tile = object->u.canal.tile;
 

	
 
	switch (variable) {
 
		/* Height of tile */
 
		case 0x80: {
 
			int z = GetTileZ(tile);
 
			/* Return consistent height within locks */
 
			if (IsTileType(tile, MP_WATER) && IsLock(tile) && GetLockPart(tile) == LOCK_PART_UPPER) z--;
 
			return z;
 
		}
 

	
 
		/* Terrain type */
 
		case 0x81: return GetTerrainType(tile);
 

	
 
		/* Random data for river or canal tiles, otherwise zero */
 
		case 0x83: return IsTileType(tile, MP_WATER) ? GetWaterTileRandomBits(tile) : 0;
 
	}
 

	
 
	DEBUG(grf, 1, "Unhandled canal variable 0x%02X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 

	
 
static const SpriteGroup *CanalResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 
{
 
	if (group->num_loaded == 0) return NULL;
 

	
 
	return group->loaded[0];
 
}
 

	
 

	
 
static void NewCanalResolver(ResolverObject *res, TileIndex tile, const GRFFile *grffile)
 
{
 
	res->GetRandomBits = &CanalGetRandomBits;
 
	res->GetTriggers   = &CanalGetTriggers;
 
	res->SetTriggers   = &CanalSetTriggers;
 
	res->GetVariable   = &CanalGetVariable;
 
	res->ResolveReal   = &CanalResolveReal;
 
	res->ResolveRealMethod = &CanalResolveReal;
 

	
 
	res->u.canal.tile = tile;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	res->grffile         = grffile;
 
}
 

	
 

	
 
/**
 
 * Lookup the base sprite to use for a canal.
 
 * @param feature Which canal feature we want.
 
 * @param tile Tile index of canal, if appropriate.
 
 * @return Base sprite returned by GRF, or 0 if none.
 
 */
 
SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	NewCanalResolver(&object, tile, _water_feature[feature].grffile);
 

	
 
	group = SpriteGroup::Resolve(_water_feature[feature].group, &object);
 
	if (group == NULL) return 0;
 

	
 
	return group->GetResult();
 
}
 

	
 
/**
 
 * Run a specific callback for canals.
 
 * @param callback Callback ID.
 
 * @param param1   Callback parameter 1.
 
 * @param param2   Callback parameter 2.
 
 * @param feature  For which feature to run the callback.
 
 * @param tile     Tile index of canal.
 
 * @return Callback result or CALLBACK_FAILED if the callback failed.
 
 */
 
static uint16 GetCanalCallback(CallbackID callback, uint32 param1, uint32 param2, CanalFeature feature, TileIndex tile)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	NewCanalResolver(&object, tile, _water_feature[feature].grffile);
 

	
 
	object.callback = callback;
src/newgrf_cargo.cpp
Show inline comments
 
@@ -12,97 +12,97 @@
 
#include "stdafx.h"
 
#include "debug.h"
 
#include "newgrf_spritegroup.h"
 

	
 
static uint32 CargoGetRandomBits(const ResolverObject *object)
 
{
 
	return 0;
 
}
 

	
 

	
 
static uint32 CargoGetTriggers(const ResolverObject *object)
 
{
 
	return 0;
 
}
 

	
 

	
 
static void CargoSetTriggers(const ResolverObject *object, int triggers)
 
{
 
	return;
 
}
 

	
 

	
 
static uint32 CargoGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
 
{
 
	DEBUG(grf, 1, "Unhandled cargo variable 0x%X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 

	
 
static const SpriteGroup *CargoResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 
{
 
	/* Cargo action 2s should always have only 1 "loaded" state, but some
 
	 * times things don't follow the spec... */
 
	if (group->num_loaded > 0) return group->loaded[0];
 
	if (group->num_loading > 0) return group->loading[0];
 

	
 
	return NULL;
 
}
 

	
 

	
 
static void NewCargoResolver(ResolverObject *res, const CargoSpec *cs)
 
{
 
	res->GetRandomBits = &CargoGetRandomBits;
 
	res->GetTriggers   = &CargoGetTriggers;
 
	res->SetTriggers   = &CargoSetTriggers;
 
	res->GetVariable   = &CargoGetVariable;
 
	res->ResolveReal   = &CargoResolveReal;
 
	res->ResolveRealMethod = &CargoResolveReal;
 

	
 
	res->u.cargo.cs = cs;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	res->grffile         = cs->grffile;
 
}
 

	
 

	
 
SpriteID GetCustomCargoSprite(const CargoSpec *cs)
 
{
 
	const SpriteGroup *group;
 
	ResolverObject object;
 

	
 
	NewCargoResolver(&object, cs);
 

	
 
	group = SpriteGroup::Resolve(cs->group, &object);
 
	if (group == NULL) return 0;
 

	
 
	return group->GetResult();
 
}
 

	
 

	
 
uint16 GetCargoCallback(CallbackID callback, uint32 param1, uint32 param2, const CargoSpec *cs)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	NewCargoResolver(&object, cs);
 
	object.callback = callback;
 
	object.callback_param1 = param1;
 
	object.callback_param2 = param2;
 

	
 
	group = SpriteGroup::Resolve(cs->group, &object);
 
	if (group == NULL) return CALLBACK_FAILED;
 

	
 
	return group->GetCallbackResult();
 
}
 

	
 
/**
 
 * Translate a GRF-local cargo slot/bitnum into a CargoID.
 
 * @param cargo   GRF-local cargo slot/bitnum.
 
 * @param grffile Originating GRF file.
 
 * @param usebit  Defines the meaning of \a cargo for GRF version < 7.
 
 *                If true, then \a cargo is a bitnum. If false, then \a cargo is a cargoslot.
src/newgrf_debug_gui.cpp
Show inline comments
 
@@ -117,97 +117,97 @@ public:
 

	
 
	/**
 
	 * Get the parent "window_number" of a given instance.
 
	 * @param index the instance to get the parent for.
 
	 * @return the parent's window_number or UINT32_MAX if there is none.
 
	 */
 
	virtual uint GetParent(uint index) const = 0;
 

	
 
	/**
 
	 * Get the instance given an index.
 
	 * @param index the index to get the instance for.
 
	 * @return the instance.
 
	 */
 
	virtual const void *GetInstance(uint index) const = 0;
 

	
 
	/**
 
	 * Get (NewGRF) specs given an index.
 
	 * @param index the index to get the specs for for.
 
	 * @return the specs.
 
	 */
 
	virtual const void *GetSpec(uint index) const = 0;
 

	
 
	/**
 
	 * Set the string parameters to write the right data for a STRINGn.
 
	 * @param index the index to get the string parameters for.
 
	 */
 
	virtual void SetStringParameters(uint index) const = 0;
 

	
 
	/**
 
	 * Get the GRFID of the file that includes this item.
 
	 * @param index index to check.
 
	 * @return GRFID of the item. 0 means that the item is not inspectable.
 
	 */
 
	virtual uint32 GetGRFID(uint index) const = 0;
 

	
 
	/**
 
	 * Resolve (action2) variable for a given index.
 
	 * @param index The (instance) index to resolve the variable for.
 
	 * @param var   The variable to actually resolve.
 
	 * @param param The varaction2 0x60+x parameter to pass.
 
	 * @param avail Return whether the variable is available.
 
	 * @return The resolved variable's value.
 
	 */
 
	virtual uint Resolve(uint index, uint var, uint param, bool *avail) const
 
	{
 
		ResolverObject ro;
 
		memset(&ro, 0, sizeof(ro));
 
		this->Resolve(&ro, index);
 
		return ro.GetVariable(&ro, var, param, avail);
 
		return ro.GetScope(ro.scope)->GetVariable(var, param, avail);
 
	}
 

	
 
	/**
 
	 * Used to decide if the PSA needs a parameter or not.
 
	 * @return True iff this item has a PSA that requires a parameter.
 
	 */
 
	virtual bool PSAWithParameter() const
 
	{
 
		return false;
 
	}
 

	
 
	/**
 
	 * Allows to know the size of the persistent storage.
 
	 * @param index Index of the item.
 
	 * @param grfid Parameter for the PSA. Only required for items with parameters.
 
	 * @return Size of the persistent storage in indices.
 
	 */
 
	virtual uint GetPSASize(uint index, uint32 grfid) const
 
	{
 
		return 0;
 
	}
 

	
 
	/**
 
	 * Gets the first position of the array containing the persistent storage.
 
	 * @param index Index of the item.
 
	 * @param grfid Parameter for the PSA. Only required for items with parameters.
 
	 * @return Pointer to the first position of the storage array or NULL if not present.
 
	 */
 
	virtual const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const
 
	{
 
		return NULL;
 
	}
 

	
 
protected:
 
	/**
 
	 * Actually execute the real resolving for a given (instance) index.
 
	 * @param ro    The resolver object to fill with everything
 
	 *              needed to be able to resolve a variable.
 
	 * @param index The (instance) index of the to-be-resolved variable.
 
	 */
 
	virtual void Resolve(ResolverObject *ro, uint index) const {}
 

	
 
	/**
 
	 * Helper to make setting the strings easier.
 
	 * @param string the string to actually draw.
 
	 * @param index  the (instance) index for the string.
 
	 */
 
	void SetSimpleStringParameters(StringID string, uint32 index) const
src/newgrf_engine.cpp
Show inline comments
 
@@ -893,97 +893,97 @@ static uint32 VehicleGetVariable(const R
 
			}
 
			case 0x48: return Engine::Get(object->u.vehicle.self_type)->flags; // Vehicle Type Info
 
			case 0x49: return _cur_year; // 'Long' format build year
 
			case 0x4B: return _date; // Long date of last service
 
			case 0x92: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF); // Date of last service
 
			case 0x93: return GB(Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF), 8, 8);
 
			case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year
 
			case 0xDA: return INVALID_VEHICLE; // Next vehicle
 
			case 0xF2: return 0; // Cargo subtype
 
		}
 

	
 
		*available = false;
 
		return UINT_MAX;
 
	}
 

	
 
	return VehicleGetVariable(v, object, variable, parameter, available);
 
}
 

	
 

	
 
static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 
{
 
	const Vehicle *v = object->u.vehicle.self;
 

	
 
	if (v == NULL) {
 
		if (group->num_loading > 0) return group->loading[0];
 
		if (group->num_loaded  > 0) return group->loaded[0];
 
		return NULL;
 
	}
 

	
 
	bool in_motion = !v->First()->current_order.IsType(OT_LOADING);
 

	
 
	uint totalsets = in_motion ? group->num_loaded : group->num_loading;
 

	
 
	if (totalsets == 0) return NULL;
 

	
 
	uint set = (v->cargo.Count() * totalsets) / max((uint16)1, v->cargo_cap);
 
	set = min(set, totalsets - 1);
 

	
 
	return in_motion ? group->loaded[set] : group->loading[set];
 
}
 

	
 

	
 
static inline void NewVehicleResolver(ResolverObject *res, EngineID engine_type, const Vehicle *v)
 
{
 
	res->GetRandomBits = &VehicleGetRandomBits;
 
	res->GetTriggers   = &VehicleGetTriggers;
 
	res->SetTriggers   = &VehicleSetTriggers;
 
	res->GetVariable   = &VehicleGetVariable;
 
	res->ResolveReal   = &VehicleResolveReal;
 
	res->ResolveRealMethod = &VehicleResolveReal;
 

	
 
	res->u.vehicle.self   = v;
 
	res->u.vehicle.parent = (v != NULL) ? v->First() : v;
 

	
 
	res->u.vehicle.self_type = engine_type;
 
	res->u.vehicle.info_view = false;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	const Engine *e = Engine::Get(engine_type);
 
	res->grffile         = (e != NULL ? e->GetGRF() : NULL);
 
}
 

	
 

	
 
/**
 
 * Retrieve the SpriteGroup for the specified vehicle.
 
 * If the vehicle is not specified, the purchase list group for the engine is
 
 * chosen. For trains, an additional engine override lookup is performed.
 
 * @param engine    Engine type of the vehicle.
 
 * @param v         The vehicle itself.
 
 * @param use_cache Use cached override
 
 * @returns         The selected SpriteGroup for the vehicle.
 
 */
 
static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle *v, bool use_cache = true)
 
{
 
	const SpriteGroup *group;
 
	CargoID cargo;
 

	
 
	if (v == NULL) {
 
		cargo = CT_PURCHASE;
 
	} else {
 
		cargo = v->cargo_type;
 

	
 
		if (v->IsGroundVehicle()) {
 
			/* For trains we always use cached value, except for callbacks because the override spriteset
 
			 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
 
			 * as v->cargo_type is temporary changed to the new type */
 
			if (use_cache && v->type == VEH_TRAIN) {
 
				group = Train::From(v)->tcache.cached_override;
 
			} else {
 
				group = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine);
 
			}
 
			if (group != NULL) return group;
 
		}
 
	}
 
@@ -1285,54 +1285,54 @@ void CommitVehicleListOrderChanges()
 
	}
 

	
 
	/* Store final sort-order */
 
	const EngineID *idend = ordering.End();
 
	uint index = 0;
 
	for (const EngineID *it = ordering.Begin(); it != idend; ++it, ++index) {
 
		Engine::Get(*it)->list_position = index;
 
	}
 

	
 
	/* Clear out the queue */
 
	_list_order_changes.Reset();
 
}
 

	
 
/**
 
 * Resolve an engine's spec and such so we can get a variable.
 
 * @param ro    The resolver object to fill.
 
 * @param index The vehicle to get the data from.
 
 */
 
void GetVehicleResolver(ResolverObject *ro, uint index)
 
{
 
	Vehicle *v = Vehicle::Get(index);
 
	NewVehicleResolver(ro, v->engine_type, v);
 
}
 

	
 
/**
 
 * Fill the grf_cache of the given vehicle.
 
 * @param v The vehicle to fill the cache for.
 
 */
 
void FillNewGRFVehicleCache(const Vehicle *v)
 
{
 
	ResolverObject ro;
 
	memset(&ro, 0, sizeof(ro));
 
	GetVehicleResolver(&ro, v->index);
 

	
 
	/* These variables we have to check; these are the ones with a cache. */
 
	static const int cache_entries[][2] = {
 
		{ 0x40, NCVV_POSITION_CONSIST_LENGTH },
 
		{ 0x41, NCVV_POSITION_SAME_ID_LENGTH },
 
		{ 0x42, NCVV_CONSIST_CARGO_INFORMATION },
 
		{ 0x43, NCVV_COMPANY_INFORMATION },
 
	};
 
	assert_compile(NCVV_END == lengthof(cache_entries));
 

	
 
	/* Resolve all the variables, so their caches are set. */
 
	for (size_t i = 0; i < lengthof(cache_entries); i++) {
 
		/* Only resolve when the cache isn't valid. */
 
		if (HasBit(v->grf_cache.cache_valid, cache_entries[i][1])) continue;
 
		bool stub;
 
		ro.GetVariable(&ro, cache_entries[i][0], 0, &stub);
 
		ro.GetScope(ro.scope)->GetVariable(cache_entries[i][0], 0, &stub);
 
	}
 

	
 
	/* Make sure really all bits are set. */
 
	assert(v->grf_cache.cache_valid == (1 << NCVV_END) - 1);
 
}
src/newgrf_generic.cpp
Show inline comments
 
@@ -85,97 +85,97 @@ static void GenericCallbackSetTriggers(c
 

	
 
static uint32 GenericCallbackGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
 
{
 
	DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
static uint32 GenericAiCallbackGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
 
{
 
	switch (variable) {
 
		case 0x40: return object->grffile->cargo_map[object->u.generic.cargo_type];
 

	
 
		case 0x80: return object->u.generic.cargo_type;
 
		case 0x81: return CargoSpec::Get(object->u.generic.cargo_type)->bitnum;
 
		case 0x82: return object->u.generic.default_selection;
 
		case 0x83: return object->u.generic.src_industry;
 
		case 0x84: return object->u.generic.dst_industry;
 
		case 0x85: return object->u.generic.distance;
 
		case 0x86: return object->u.generic.event;
 
		case 0x87: return object->u.generic.count;
 
		case 0x88: return object->u.generic.station_size;
 

	
 
		default: break;
 
	}
 

	
 
	DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 

	
 
static const SpriteGroup *GenericCallbackResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 
{
 
	if (group->num_loaded == 0) return NULL;
 

	
 
	return group->loaded[0];
 
}
 

	
 

	
 
static inline void NewGenericResolver(ResolverObject *res, bool ai_callback)
 
{
 
	res->GetRandomBits = &GenericCallbackGetRandomBits;
 
	res->GetTriggers   = &GenericCallbackGetTriggers;
 
	res->SetTriggers   = &GenericCallbackSetTriggers;
 
	res->GetVariable   = ai_callback ? &GenericAiCallbackGetVariable : &GenericCallbackGetVariable;
 
	res->ResolveReal   = &GenericCallbackResolveReal;
 
	res->ResolveRealMethod = &GenericCallbackResolveReal;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 
}
 

	
 

	
 
/**
 
 * Follow a generic feature callback list and return the first successful
 
 * answer
 
 * @param feature GRF Feature of callback
 
 * @param object  pre-populated resolver object
 
 * @param param1_grfv7 callback_param1 for GRFs up to version 7.
 
 * @param param1_grfv8 callback_param1 for GRFs from version 8 on.
 
 * @param [out] file Optionally returns the GRFFile which made the final decision for the callback result.
 
 *                   May be NULL if not required.
 
 * @return callback value if successful or CALLBACK_FAILED
 
 */
 
static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject *object, uint32 param1_grfv7, uint32 param1_grfv8, const GRFFile **file)
 
{
 
	assert(feature < lengthof(_gcl));
 

	
 
	/* Test each feature callback sprite group. */
 
	for (GenericCallbackList::const_iterator it = _gcl[feature].begin(); it != _gcl[feature].end(); ++it) {
 
		const SpriteGroup *group = it->group;
 
		object->grffile = it->file;
 
		/* Set callback param based on GRF version. */
 
		object->callback_param1 = it->file->grf_version >= 8 ? param1_grfv8 : param1_grfv7;
 
		group = SpriteGroup::Resolve(group, object);
 
		if (group == NULL || group->GetCallbackResult() == CALLBACK_FAILED) continue;
 

	
 
		/* Return NewGRF file if necessary */
 
		if (file != NULL) *file = it->file;
 

	
 
		return group->GetCallbackResult();
 
	}
 

	
 
	/* No callback returned a valid result, so we've failed. */
 
	return CALLBACK_FAILED;
 
}
 

	
 

	
 
/**
 
 * 'Execute' an AI purchase selection callback
 
 *
 
 * @param feature GRF Feature to call callback for.
 
 * @param cargo_type Cargotype to pass to callback. (Variable 80)
src/newgrf_house.cpp
Show inline comments
 
@@ -378,97 +378,97 @@ static uint32 HouseGetVariable(const Res
 
			TileIndex testtile = GetNearbyTile(parameter, tile);
 
			if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF;
 
			HouseID house_id = GetHouseType(testtile);
 
			if (house_id < NEW_HOUSE_OFFSET) return 0;
 
			/* Checking the grffile information via HouseSpec doesn't work
 
			 * in case the newgrf was removed. */
 
			return _house_mngr.GetGRFID(house_id);
 
		}
 
	}
 

	
 
	DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
static const SpriteGroup *HouseResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 
{
 
	/* Houses do not have 'real' groups */
 
	return NULL;
 
}
 

	
 
/**
 
 * Store a value into the persistent storage of the object's parent.
 
 * @param object Object that we want to query.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
 
 */
 
void HouseStorePSA(ResolverObject *object, uint pos, int32 value)
 
{
 
	/* Houses have no persistent storage. */
 
	if (object->scope != VSG_SCOPE_PARENT || object->u.house.not_yet_constructed) return;
 

	
 
	/* Pass the request on to the town of the house */
 
	TownStorePSA(object->u.house.town, object->grffile, pos, value);
 
}
 

	
 
/**
 
 * NewHouseResolver():
 
 *
 
 * Returns a resolver object to be used with feature 07 spritegroups.
 
 */
 
static void NewHouseResolver(ResolverObject *res, HouseID house_id, TileIndex tile, Town *town)
 
{
 
	res->GetRandomBits = HouseGetRandomBits;
 
	res->GetTriggers   = HouseGetTriggers;
 
	res->SetTriggers   = HouseSetTriggers;
 
	res->GetVariable   = HouseGetVariable;
 
	res->ResolveReal   = HouseResolveReal;
 
	res->ResolveRealMethod = HouseResolveReal;
 
	res->StorePSA      = HouseStorePSA;
 

	
 
	res->u.house.tile     = tile;
 
	res->u.house.town     = town;
 
	res->u.house.house_id = house_id;
 
	res->u.house.not_yet_constructed = false;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	const HouseSpec *hs  = HouseSpec::Get(house_id);
 
	res->grffile         = (hs != NULL ? hs->grf_prop.grffile : NULL);
 
}
 

	
 
uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	assert(IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE)));
 

	
 
	NewHouseResolver(&object, house_id, tile, town);
 
	object.callback = callback;
 
	object.callback_param1 = param1;
 
	object.callback_param2 = param2;
 
	object.u.house.not_yet_constructed = not_yet_constructed;
 
	object.u.house.initial_random_bits = initial_random_bits;
 
	object.u.house.watched_cargo_triggers = watched_cargo_triggers;
 

	
 
	group = SpriteGroup::Resolve(HouseSpec::Get(house_id)->grf_prop.spritegroup[0], &object);
 
	if (group == NULL) return CALLBACK_FAILED;
 

	
 
	return group->GetCallbackResult();
 
}
 

	
 
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte stage, HouseID house_id)
 
{
 
	const DrawTileSprites *dts = group->ProcessRegisters(&stage);
 

	
 
	const HouseSpec *hs = HouseSpec::Get(house_id);
 
	PaletteID palette = hs->random_colour[TileHash2Bit(ti->x, ti->y)] + PALETTE_RECOLOUR_START;
 
	if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) {
 
		uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile);
 
		if (callback != CALLBACK_FAILED) {
 
			/* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
 
			palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
src/newgrf_industries.cpp
Show inline comments
 
@@ -365,97 +365,97 @@ static uint32 IndustryGetTriggers(const 
 
	const Industry *ind = object->u.industry.ind;
 
	return ind != NULL ? ind->random_triggers : 0;
 
}
 

	
 
static void IndustrySetTriggers(const ResolverObject *object, int triggers)
 
{
 
	Industry *ind = object->u.industry.ind;
 
	assert(ind != NULL && ind->index != INVALID_INDUSTRY);
 
	ind->random_triggers = triggers;
 
}
 

	
 
/**
 
 * Store a value into the object's persistent storage.
 
 * @param object Object that we want to query.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
 
 */
 
void IndustryStorePSA(ResolverObject *object, uint pos, int32 value)
 
{
 
	Industry *ind = object->u.industry.ind;
 
	if (ind->index == INVALID_INDUSTRY) return;
 

	
 
	if (object->scope != VSG_SCOPE_SELF) {
 
		/* Pass the request on to the town of the industry. */
 
		TownStorePSA(ind->town, object->grffile, pos, value);
 
		return;
 
	}
 

	
 
	if (ind->psa == NULL) {
 
		/* There is no need to create a storage if the value is zero. */
 
		if (value == 0) return;
 

	
 
		/* Create storage on first modification. */
 
		const IndustrySpec *indsp = GetIndustrySpec(ind->type);
 
		uint32 grfid = (indsp->grf_prop.grffile != NULL) ? indsp->grf_prop.grffile->grfid : 0;
 
		assert(PersistentStorage::CanAllocateItem());
 
		ind->psa = new PersistentStorage(grfid);
 
	}
 

	
 
	ind->psa->StoreValue(pos, value);
 
}
 

	
 
static void NewIndustryResolver(ResolverObject *res, TileIndex tile, Industry *indus, IndustryType type)
 
{
 
	res->GetRandomBits = IndustryGetRandomBits;
 
	res->GetTriggers   = IndustryGetTriggers;
 
	res->SetTriggers   = IndustrySetTriggers;
 
	res->GetVariable   = IndustryGetVariable;
 
	res->ResolveReal   = IndustryResolveReal;
 
	res->ResolveRealMethod = IndustryResolveReal;
 
	res->StorePSA      = IndustryStorePSA;
 

	
 
	res->u.industry.tile = tile;
 
	res->u.industry.ind  = indus;
 
	res->u.industry.gfx  = INVALID_INDUSTRYTILE;
 
	res->u.industry.type = type;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	const IndustrySpec *indspec = GetIndustrySpec(type);
 
	res->grffile         = (indspec != NULL ? indspec->grf_prop.grffile : NULL);
 
}
 

	
 
/**
 
 * Perform an industry callback.
 
 * @param callback The callback to perform.
 
 * @param param1 The first parameter.
 
 * @param param2 The second parameter.
 
 * @param industry The industry to do the callback for.
 
 * @param type The type of industry to do the callback for.
 
 * @param tile The tile associated with the callback.
 
 * @return The callback result.
 
 */
 
uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, Industry *industry, IndustryType type, TileIndex tile)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	NewIndustryResolver(&object, tile, industry, type);
 
	object.callback = callback;
 
	object.callback_param1 = param1;
 
	object.callback_param2 = param2;
 

	
 
	group = SpriteGroup::Resolve(GetIndustrySpec(type)->grf_prop.spritegroup[0], &object);
 
	if (group == NULL) return CALLBACK_FAILED;
 

	
 
	return group->GetCallbackResult();
 
}
 

	
 
uint32 IndustryLocationGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
 
{
 
	const Industry *industry = object->u.industry.ind;
 
	TileIndex tile = object->u.industry.tile;
 

	
 
	if (object->scope == VSG_SCOPE_PARENT) {
src/newgrf_industrytiles.cpp
Show inline comments
 
@@ -131,97 +131,97 @@ static uint32 IndustryTileGetTriggers(co
 
	if (ind->index == INVALID_INDUSTRY) return 0;
 
	return (object->scope == VSG_SCOPE_SELF) ? GetIndustryTriggers(tile) : ind->random_triggers;
 
}
 

	
 
static void IndustryTileSetTriggers(const ResolverObject *object, int triggers)
 
{
 
	const TileIndex tile = object->u.industry.tile;
 
	Industry *ind = object->u.industry.ind;
 
	assert(ind != NULL && ind->index != INVALID_INDUSTRY && IsValidTile(tile) && IsTileType(tile, MP_INDUSTRY));
 

	
 
	if (object->scope == VSG_SCOPE_SELF) {
 
		SetIndustryTriggers(tile, triggers);
 
	} else {
 
		ind->random_triggers = triggers;
 
	}
 
}
 

	
 
/**
 
 * Store a value into the persistent storage of the object's parent.
 
 * @param object Object that we want to query.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
 
 */
 
void IndustryTileStorePSA(ResolverObject *object, uint pos, int32 value)
 
{
 
	Industry *ind = object->u.industry.ind;
 
	if (object->scope != VSG_SCOPE_PARENT || ind->index == INVALID_INDUSTRY) return;
 

	
 
	if (ind->psa == NULL) {
 
		/* There is no need to create a storage if the value is zero. */
 
		if (value == 0) return;
 

	
 
		/* Create storage on first modification. */
 
		const IndustrySpec *indsp = GetIndustrySpec(ind->type);
 
		uint32 grfid = (indsp->grf_prop.grffile != NULL) ? indsp->grf_prop.grffile->grfid : 0;
 
		assert(PersistentStorage::CanAllocateItem());
 
		ind->psa = new PersistentStorage(grfid);
 
	}
 

	
 
	ind->psa->StoreValue(pos, value);
 
}
 

	
 
static void NewIndustryTileResolver(ResolverObject *res, IndustryGfx gfx, TileIndex tile, Industry *indus)
 
{
 
	res->GetRandomBits = IndustryTileGetRandomBits;
 
	res->GetTriggers   = IndustryTileGetTriggers;
 
	res->SetTriggers   = IndustryTileSetTriggers;
 
	res->GetVariable   = IndustryTileGetVariable;
 
	res->ResolveReal   = IndustryTileResolveReal;
 
	res->ResolveRealMethod = IndustryTileResolveReal;
 
	res->StorePSA      = IndustryTileStorePSA;
 

	
 
	res->u.industry.tile = tile;
 
	res->u.industry.ind  = indus;
 
	res->u.industry.gfx  = gfx;
 
	res->u.industry.type = indus->type;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	const IndustryTileSpec *its = GetIndustryTileSpec(gfx);
 
	res->grffile         = (its != NULL ? its->grf_prop.grffile : NULL);
 
}
 

	
 
static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte rnd_colour, byte stage, IndustryGfx gfx)
 
{
 
	const DrawTileSprites *dts = group->ProcessRegisters(&stage);
 

	
 
	SpriteID image = dts->ground.sprite;
 
	PaletteID pal  = dts->ground.pal;
 

	
 
	if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
 
	if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
 

	
 
	if (GB(image, 0, SPRITE_WIDTH) != 0) {
 
		/* If the ground sprite is the default flat water sprite, draw also canal/river borders
 
		 * Do not do this if the tile's WaterClass is 'land'. */
 
		if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) {
 
			DrawWaterClassGround(ti);
 
		} else {
 
			DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, GENERAL_SPRITE_COLOUR(rnd_colour)));
 
		}
 
	}
 

	
 
	DrawNewGRFTileSeq(ti, dts, TO_INDUSTRIES, stage, GENERAL_SPRITE_COLOUR(rnd_colour));
 
}
 

	
 
uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile)
 
{
 
	ResolverObject object;
 
	const SpriteGroup *group;
 

	
 
	assert(industry != NULL && IsValidTile(tile));
 
	assert(industry->index == INVALID_INDUSTRY || IsTileType(tile, MP_INDUSTRY));
 

	
 
	NewIndustryTileResolver(&object, gfx_id, tile, industry);
src/newgrf_object.cpp
Show inline comments
 
@@ -353,97 +353,97 @@ static const SpriteGroup *ObjectResolveR
 
{
 
	/* Objects do not have 'real' groups */
 
	return NULL;
 
}
 

	
 
/**
 
 * Get the object's sprite group.
 
 * @param spec The specification to get the sprite group from.
 
 * @param o    The object to get he sprite group for.
 
 * @return The resolved sprite group.
 
 */
 
static const SpriteGroup *GetObjectSpriteGroup(const ObjectSpec *spec, const Object *o)
 
{
 
	const SpriteGroup *group = NULL;
 

	
 
	if (o == NULL) group = spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT];
 
	if (group != NULL) return group;
 

	
 
	/* Fall back to the default set if the selected cargo type is not defined */
 
	return spec->grf_prop.spritegroup[0];
 

	
 
}
 

	
 
/**
 
 * Store a value into the persistent storage of the object's parent.
 
 * @param object Object that we want to query.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
 
 */
 
void ObjectStorePSA(ResolverObject *object, uint pos, int32 value)
 
{
 
	/* Objects have no persistent storage. */
 
	Object *o = object->u.object.o;
 
	if (object->scope != VSG_SCOPE_PARENT || o == NULL) return;
 

	
 
	/* Pass the request on to the town of the object */
 
	TownStorePSA(o->town, object->grffile, pos, value);
 
}
 

	
 
/**
 
 * Returns a resolver object to be used with feature 0F spritegroups.
 
 */
 
static void NewObjectResolver(ResolverObject *res, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0)
 
{
 
	res->GetRandomBits = ObjectGetRandomBits;
 
	res->GetTriggers   = ObjectGetTriggers;
 
	res->SetTriggers   = ObjectSetTriggers;
 
	res->GetVariable   = ObjectGetVariable;
 
	res->ResolveReal   = ObjectResolveReal;
 
	res->ResolveRealMethod = ObjectResolveReal;
 
	res->StorePSA      = ObjectStorePSA;
 

	
 
	res->u.object.o    = o;
 
	res->u.object.tile = tile;
 
	res->u.object.view = view;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	res->grffile = spec->grf_prop.grffile;
 
}
 

	
 
/**
 
 * Perform a callback for an object.
 
 * @param callback The callback to perform.
 
 * @param param1   The first parameter to pass to the NewGRF.
 
 * @param param2   The second parameter to pass to the NewGRF.
 
 * @param spec     The specification of the object / the entry point.
 
 * @param o        The object to call the callback for.
 
 * @param tile     The tile the callback is called for.
 
 * @param view     The view of the object (only used when o == NULL).
 
 * @return The result of the callback.
 
 */
 
uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view)
 
{
 
	ResolverObject object;
 
	NewObjectResolver(&object, spec, o, tile, view);
 
	object.callback = callback;
 
	object.callback_param1 = param1;
 
	object.callback_param2 = param2;
 

	
 
	const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, o), &object);
 
	if (group == NULL) return CALLBACK_FAILED;
 

	
 
	return group->GetCallbackResult();
 
}
 

	
 
/**
 
 * Draw an group of sprites on the map.
 
 * @param ti    Information about the tile to draw on.
 
 * @param group The group of sprites to draw.
 
 * @param spec  Object spec to draw.
 
 */
 
static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec)
 
{
 
	const DrawTileSprites *dts = group->ProcessRegisters(NULL);
src/newgrf_railtype.cpp
Show inline comments
 
@@ -38,97 +38,97 @@ static uint32 RailTypeGetVariable(const 
 

	
 
	if (tile == INVALID_TILE) {
 
		switch (variable) {
 
			case 0x40: return 0;
 
			case 0x41: return 0;
 
			case 0x42: return 0;
 
			case 0x43: return _date;
 
			case 0x44: return HZB_TOWN_EDGE;
 
		}
 
	}
 

	
 
	switch (variable) {
 
		case 0x40: return GetTerrainType(tile, object->u.routes.context);
 
		case 0x41: return 0;
 
		case 0x42: return IsLevelCrossingTile(tile) && IsCrossingBarred(tile);
 
		case 0x43:
 
			if (IsRailDepotTile(tile)) return Depot::GetByTile(tile)->build_date;
 
			return _date;
 
		case 0x44: {
 
			const Town *t = NULL;
 
			if (IsRailDepotTile(tile)) {
 
				t = Depot::GetByTile(tile)->town;
 
			} else if (IsLevelCrossingTile(tile)) {
 
				t = ClosestTownFromTile(tile, UINT_MAX);
 
			}
 
			return t != NULL ? GetTownRadiusGroup(t, tile) : HZB_TOWN_EDGE;
 
		}
 
	}
 

	
 
	DEBUG(grf, 1, "Unhandled rail type tile variable 0x%X", variable);
 

	
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
static const SpriteGroup *RailTypeResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
 
{
 
	if (group->num_loading > 0) return group->loading[0];
 
	if (group->num_loaded  > 0) return group->loaded[0];
 
	return NULL;
 
}
 

	
 
static inline void NewRailTypeResolver(ResolverObject *res, TileIndex tile, TileContext context, const GRFFile *grffile, uint32 param1 = 0, uint32 param2 = 0)
 
{
 
	res->GetRandomBits = &RailTypeGetRandomBits;
 
	res->GetTriggers   = &RailTypeGetTriggers;
 
	res->SetTriggers   = &RailTypeSetTriggers;
 
	res->GetVariable   = &RailTypeGetVariable;
 
	res->ResolveReal   = &RailTypeResolveReal;
 
	res->ResolveRealMethod = &RailTypeResolveReal;
 

	
 
	res->u.routes.tile = tile;
 
	res->u.routes.context = context;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = param1;
 
	res->callback_param2 = param2;
 
	res->ResetState();
 

	
 
	res->grffile         = grffile;
 
}
 

	
 
/**
 
 * Get the sprite to draw for the given tile.
 
 * @param rti The rail type data (spec).
 
 * @param tile The tile to get the sprite for.
 
 * @param rtsg The type of sprite to draw.
 
 * @param content Where are we drawing the tile?
 
 * @return The sprite to draw.
 
 */
 
SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context)
 
{
 
	assert(rtsg < RTSG_END);
 

	
 
	if (rti->group[rtsg] == NULL) return 0;
 

	
 
	const SpriteGroup *group;
 
	ResolverObject object;
 

	
 
	NewRailTypeResolver(&object, tile, context, rti->grffile[rtsg]);
 

	
 
	group = SpriteGroup::Resolve(rti->group[rtsg], &object);
 
	if (group == NULL || group->GetNumResults() == 0) return 0;
 

	
 
	return group->GetResult();
 
}
 

	
 
/**
 
 * Get the sprite to draw for a given signal.
 
 * @param rti The rail type data (spec).
 
 * @param tile The tile to get the sprite for.
 
 * @param type Signal type.
 
 * @param var Signal variant.
 
 * @param state Signal state.
 
 * @param gui Is the sprite being used on the map or in the GUI?
 
 * @return The sprite to draw.
 
 */
 
SpriteID GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, SignalState state, bool gui)
src/newgrf_spritegroup.cpp
Show inline comments
 
/* $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_spritegroup.cpp Handling of primarily NewGRF action 2. */
 

	
 
#include "stdafx.h"
 
#include "debug.h"
 
#include "newgrf_spritegroup.h"
 
#include "core/pool_func.hpp"
 

	
 
SpriteGroupPool _spritegroup_pool("SpriteGroup");
 
INSTANTIATE_POOL_METHODS(SpriteGroup)
 

	
 
RealSpriteGroup::~RealSpriteGroup()
 
{
 
	free(this->loaded);
 
	free(this->loading);
 
}
 

	
 
DeterministicSpriteGroup::~DeterministicSpriteGroup()
 
{
 
	free(this->adjusts);
 
	free(this->ranges);
 
}
 

	
 
RandomizedSpriteGroup::~RandomizedSpriteGroup()
 
{
 
	free(this->groups);
 
}
 

	
 
TemporaryStorageArray<int32, 0x110> _temp_store;
 

	
 

	
 
static inline uint32 GetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
 
static inline uint32 GetVariable(const ResolverObject *object, ScopeResolver *scope, byte variable, uint32 parameter, bool *available)
 
{
 
	/* First handle variables common with Action7/9/D */
 
	uint32 value;
 
	if (GetGlobalVariable(variable, &value, object->grffile)) return value;
 

	
 
	/* Non-common variable */
 
	switch (variable) {
 
		case 0x0C: return object->callback;
 
		case 0x10: return object->callback_param1;
 
		case 0x18: return object->callback_param2;
 
		case 0x1C: return object->last_value;
 

	
 
		case 0x5F: return (object->GetRandomBits(object) << 8) | object->GetTriggers(object);
 
		case 0x5F: return (scope->GetRandomBits() << 8) | scope->GetTriggers();
 

	
 
		case 0x7D: return _temp_store.GetValue(parameter);
 

	
 
		case 0x7F:
 
			if (object == NULL || object->grffile == NULL) return 0;
 
			return object->grffile->GetParam(parameter);
 

	
 
		/* Not a common variable, so evalute the feature specific variables */
 
		default: return object->GetVariable(object, variable, parameter, available);
 
		default: return scope->GetVariable(variable, parameter, available);
 
	}
 
}
 

	
 
ScopeResolver::ScopeResolver(ResolverObject *ro)
 
{
 
	this->ro = ro;
 
}
 

	
 
ScopeResolver::~ScopeResolver() {}
 

	
 
/**
 
 * Get a few random bits. Default implementation has no random bits.
 
 * @return Random bits.
 
 */
 
/* virtual */ uint32 ScopeResolver::GetRandomBits() const
 
{
 
	return 0;
 
}
 

	
 
/**
 
 * Get the triggers. Base class returns \c 0 to prevent trouble.
 
 * @return The triggers.
 
 */
 
/* virtual */ uint32 ScopeResolver::GetTriggers() const
 
{
 
	return 0;
 
}
 

	
 
/**
 
 * Set the triggers. Base class implementation does nothing.
 
 * @param triggers Triggers to set.
 
 */
 
/* virtual */ void ScopeResolver::SetTriggers(int triggers) const {}
 

	
 
/**
 
 * Get a variable value. Default implementation has no available variables.
 
 * @param variable Variable to read
 
 * @param parameter Parameter for 60+x variables
 
 * @param[out] available Set to false, in case the variable does not exist.
 
 * @return Value
 
 */
 
/* virtual */ uint32 ScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
 
{
 
	DEBUG(grf, 1, "Unhandled scope variable 0x%X", variable);
 
	*available = false;
 
	return UINT_MAX;
 
}
 

	
 
/**
 
 * Store a value into the persistent storage area (PSA). Default implementation does nothing (for newgrf classes without storage).
 
 * @param pos Position to store into.
 
 * @param value Value to store.
 
 */
 
/* virtual */ void ScopeResolver::StorePSA(uint reg, int32 value) {}
 

	
 

	
 
TempScopeResolver::TempScopeResolver(ResolverObject *ro) : ScopeResolver(ro) {}
 

	
 
/* virtual */ uint32 TempScopeResolver::GetRandomBits() const
 
{
 
	return this->ro->GetRandomBits(this->ro);
 
}
 

	
 
/* virtual */ uint32 TempScopeResolver::GetTriggers() const
 
{
 
	return this->ro->GetTriggers(this->ro);
 
}
 

	
 
/* virtual */ void TempScopeResolver::SetTriggers(int triggers) const
 
{
 
	this->ro->SetTriggers(this->ro, triggers);
 
}
 

	
 
/* virtual */ uint32 TempScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
 
{
 
	return this->ro->GetVariable(this->ro, variable, parameter, available);
 
}
 

	
 
/* virtual */ void TempScopeResolver::StorePSA(uint reg, int32 value)
 
{
 
	if (this->ro->StorePSA != NULL) this->ro->StorePSA(this->ro, reg, value);
 
}
 

	
 
ResolverObject::ResolverObject() : temp_scope(this) {} // XXX Temporary
 

	
 
ResolverObject::ResolverObject(const GRFFile *grffile, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : temp_scope(this)
 
{
 
	this->callback = callback;
 
	this->callback_param1 = callback_param1;
 
	this->callback_param2 = callback_param2;
 
	this->ResetState();
 

	
 
	this->grffile = grffile;
 
}
 

	
 
ResolverObject::~ResolverObject() {}
 

	
 
/* virtual */ const SpriteGroup *ResolverObject::ResolveReal(const RealSpriteGroup *group) const
 
{
 
	return this->ResolveRealMethod(this, group);
 
}
 

	
 
/**
 
 * Get a specific ScopeResolver.
 
 * @param scope Scope to return.
 
 * @param relative Additional parameter for #VSG_SCOPE_RELATIVE.
 
 * @return ScopeResolver.
 
 */
 
/* virtual */ ScopeResolver *ResolverObject::GetScope(VarSpriteGroupScope scope, byte relative)
 
{
 
	return &this->temp_scope;
 
}
 

	
 
/**
 
 * Rotate val rot times to the right
 
 * @param val the value to rotate
 
 * @param rot the amount of times to rotate
 
 * @return the rotated value
 
 */
 
static uint32 RotateRight(uint32 val, uint32 rot)
 
{
 
	/* Do not rotate more than necessary */
 
	rot %= 32;
 

	
 
	return (val >> rot) | (val << (32 - rot));
 
}
 

	
 

	
 
/* Evaluate an adjustment for a variable of the given size.
 
 * U is the unsigned type and S is the signed type to use. */
 
template <typename U, typename S>
 
static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ResolverObject *object, U last_value, uint32 value)
 
{
 
	value >>= adjust->shift_num;
 
	value  &= adjust->and_mask;
 

	
 
	if (adjust->type != DSGA_TYPE_NONE) value += (S)adjust->add_val;
 

	
 
	switch (adjust->type) {
 
		case DSGA_TYPE_DIV:  value /= (S)adjust->divmod_val; break;
 
		case DSGA_TYPE_MOD:  value %= (U)adjust->divmod_val; break;
 
		case DSGA_TYPE_NONE: break;
 
	}
 

	
 
	switch (adjust->operation) {
 
		case DSGA_OP_ADD:  return last_value + value;
 
		case DSGA_OP_SUB:  return last_value - value;
 
		case DSGA_OP_SMIN: return min((S)last_value, (S)value);
 
		case DSGA_OP_SMAX: return max((S)last_value, (S)value);
 
		case DSGA_OP_UMIN: return min((U)last_value, (U)value);
 
		case DSGA_OP_UMAX: return max((U)last_value, (U)value);
 
		case DSGA_OP_SDIV: return value == 0 ? (S)last_value : (S)last_value / (S)value;
 
		case DSGA_OP_SMOD: return value == 0 ? (S)last_value : (S)last_value % (S)value;
 
		case DSGA_OP_UDIV: return value == 0 ? (U)last_value : (U)last_value / (U)value;
 
		case DSGA_OP_UMOD: return value == 0 ? (U)last_value : (U)last_value % (U)value;
 
		case DSGA_OP_MUL:  return last_value * value;
 
		case DSGA_OP_AND:  return last_value & value;
 
		case DSGA_OP_OR:   return last_value | value;
 
		case DSGA_OP_XOR:  return last_value ^ value;
 
		case DSGA_OP_STO:  _temp_store.StoreValue((U)value, (S)last_value); return last_value;
 
		case DSGA_OP_RST:  return value;
 
		case DSGA_OP_STOP: if (object->StorePSA != NULL) object->StorePSA(object, (U)value, (S)last_value); return last_value;
 
		case DSGA_OP_STOP: object->GetScope(object->scope)->StorePSA((U)value, (S)last_value); return last_value;
 
		case DSGA_OP_ROR:  return RotateRight(last_value, value);
 
		case DSGA_OP_SCMP: return ((S)last_value == (S)value) ? 1 : ((S)last_value < (S)value ? 0 : 2);
 
		case DSGA_OP_UCMP: return ((U)last_value == (U)value) ? 1 : ((U)last_value < (U)value ? 0 : 2);
 
		case DSGA_OP_SHL:  return (U)last_value << ((U)value & 0x1F); // mask 'value' to 5 bits, which should behave the same on all architectures.
 
		case DSGA_OP_SHR:  return (U)last_value >> ((U)value & 0x1F);
 
		case DSGA_OP_SAR:  return (S)last_value >> ((U)value & 0x1F);
 
		default:           return value;
 
	}
 
}
 

	
 

	
 
const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject *object) const
 
{
 
	uint32 last_value = 0;
 
	uint32 value = 0;
 
	uint i;
 

	
 
	object->scope = this->var_scope;
 

	
 
	for (i = 0; i < this->num_adjusts; i++) {
 
		DeterministicSpriteGroupAdjust *adjust = &this->adjusts[i];
 

	
 
		/* Try to get the variable. We shall assume it is available, unless told otherwise. */
 
		bool available = true;
 
		if (adjust->variable == 0x7E) {
 
			const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object);
 
			if (subgroup == NULL) {
 
				value = CALLBACK_FAILED;
 
			} else {
 
				value = subgroup->GetCallbackResult();
 
			}
 

	
 
			/* Reset values to current scope.
 
			 * Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
 
			object->scope = this->var_scope;
 
		} else if (adjust->variable == 0x7B) {
 
			value = GetVariable(object, adjust->parameter, last_value, &available);
 
			value = GetVariable(object, object->GetScope(this->var_scope), adjust->parameter, last_value, &available);
 
		} else {
 
			value = GetVariable(object, adjust->variable, adjust->parameter, &available);
 
			value = GetVariable(object, object->GetScope(this->var_scope), adjust->variable, adjust->parameter, &available);
 
		}
 

	
 
		if (!available) {
 
			/* Unsupported variable: skip further processing and return either
 
			 * the group from the first range or the default group. */
 
			return SpriteGroup::Resolve(this->num_ranges > 0 ? this->ranges[0].group : this->default_group, object);
 
		}
 

	
 
		switch (this->size) {
 
			case DSG_SIZE_BYTE:  value = EvalAdjustT<uint8,  int8> (adjust, object, last_value, value); break;
 
			case DSG_SIZE_WORD:  value = EvalAdjustT<uint16, int16>(adjust, object, last_value, value); break;
 
			case DSG_SIZE_DWORD: value = EvalAdjustT<uint32, int32>(adjust, object, last_value, value); break;
 
			default: NOT_REACHED();
 
		}
 
		last_value = value;
 
	}
 

	
 
	object->last_value = last_value;
 

	
 
	if (this->num_ranges == 0) {
 
		/* nvar == 0 is a special case -- we turn our value into a callback result */
 
		if (value != CALLBACK_FAILED) value = GB(value, 0, 15);
 
		static CallbackResultSpriteGroup nvarzero(0, true);
 
		nvarzero.result = value;
 
		return &nvarzero;
 
	}
 

	
 
	for (i = 0; i < this->num_ranges; i++) {
 
		if (this->ranges[i].low <= value && value <= this->ranges[i].high) {
 
			return SpriteGroup::Resolve(this->ranges[i].group, object);
 
		}
 
	}
 

	
 
	return SpriteGroup::Resolve(this->default_group, object);
 
}
 

	
 

	
 
const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject *object) const
 
{
 
	uint32 mask;
 
	byte index;
 

	
 
	object->scope = this->var_scope;
 
	object->count = this->count;
 

	
 
	ScopeResolver *scope = object->GetScope(this->var_scope, this->count);
 
	if (object->trigger != 0) {
 
		/* Handle triggers */
 
		/* Magic code that may or may not do the right things... */
 
		byte waiting_triggers = object->GetTriggers(object);
 
		byte waiting_triggers = scope->GetTriggers();
 
		byte match = this->triggers & (waiting_triggers | object->trigger);
 
		bool res = (this->cmp_mode == RSG_CMP_ANY) ? (match != 0) : (match == this->triggers);
 

	
 
		if (res) {
 
			waiting_triggers &= ~match;
 
			object->reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit;
 
		} else {
 
			waiting_triggers |= object->trigger;
 
		}
 

	
 
		object->SetTriggers(object, waiting_triggers);
 
		scope->SetTriggers(waiting_triggers);
 
	}
 

	
 
	mask  = (this->num_groups - 1) << this->lowest_randbit;
 
	index = (object->GetRandomBits(object) & mask) >> this->lowest_randbit;
 
	uint32 mask  = (this->num_groups - 1) << this->lowest_randbit;
 
	byte index = (scope->GetRandomBits() & mask) >> this->lowest_randbit;
 

	
 
	return SpriteGroup::Resolve(this->groups[index], object);
 
}
 

	
 

	
 
const SpriteGroup *RealSpriteGroup::Resolve(ResolverObject *object) const
 
{
 
	return object->ResolveReal(object, this);
 
	return object->ResolveReal(this);
 
}
 

	
 
/**
 
 * Process registers and the construction stage into the sprite layout.
 
 * The passed construction stage might get reset to zero, if it gets incorporated into the layout
 
 * during the preprocessing.
 
 * @param [in, out] stage Construction stage (0-3), or NULL if not applicable.
 
 * @return sprite layout to draw.
 
 */
 
const DrawTileSprites *TileLayoutSpriteGroup::ProcessRegisters(uint8 *stage) const
 
{
 
	if (!this->dts.NeedsPreprocessing()) {
 
		if (stage != NULL && this->dts.consistent_max_offset > 0) *stage = GetConstructionStageOffset(*stage, this->dts.consistent_max_offset);
 
		return &this->dts;
 
	}
 

	
 
	static DrawTileSprites result;
 
	uint8 actual_stage = stage != NULL ? *stage : 0;
 
	this->dts.PrepareLayout(0, 0, 0, actual_stage, false);
 
	this->dts.ProcessRegisters(0, 0, false);
 
	result.seq = this->dts.GetLayout(&result.ground);
 

	
 
	/* Stage has been processed by PrepareLayout(), set it to zero. */
 
	if (stage != NULL) *stage = 0;
 

	
 
	return &result;
 
}
src/newgrf_spritegroup.h
Show inline comments
 
@@ -256,159 +256,195 @@ struct CallbackResultSpriteGroup : Sprit
 
	uint16 result;
 
	uint16 GetCallbackResult() const { return this->result; }
 
};
 

	
 

	
 
/* A result sprite group returns the first SpriteID and the number of
 
 * sprites in the set */
 
struct ResultSpriteGroup : SpriteGroup {
 
	/**
 
	 * Creates a spritegroup representing a sprite number result.
 
	 * @param sprite The sprite number.
 
	 * @param num_sprites The number of sprites per set.
 
	 * @return A spritegroup representing the sprite number result.
 
	 */
 
	ResultSpriteGroup(SpriteID sprite, byte num_sprites) :
 
		SpriteGroup(SGT_RESULT),
 
		sprite(sprite),
 
		num_sprites(num_sprites)
 
	{
 
	}
 

	
 
	SpriteID sprite;
 
	byte num_sprites;
 
	SpriteID GetResult() const { return this->sprite; }
 
	byte GetNumResults() const { return this->num_sprites; }
 
};
 

	
 
/**
 
 * Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
 
 */
 
struct TileLayoutSpriteGroup : SpriteGroup {
 
	TileLayoutSpriteGroup() : SpriteGroup(SGT_TILELAYOUT) {}
 
	~TileLayoutSpriteGroup() {}
 

	
 
	NewGRFSpriteLayout dts;
 

	
 
	const DrawTileSprites *ProcessRegisters(uint8 *stage) const;
 
};
 

	
 
struct IndustryProductionSpriteGroup : SpriteGroup {
 
	IndustryProductionSpriteGroup() : SpriteGroup(SGT_INDUSTRY_PRODUCTION) {}
 

	
 
	uint8 version;
 
	int16 subtract_input[3];  // signed
 
	uint16 add_output[2];     // unsigned
 
	uint8 again;
 
};
 

	
 
struct ResolverObject;
 

	
 
struct ScopeResolver {
 
	ResolverObject *ro;
 

	
 
	ScopeResolver(ResolverObject *ro);
 
	virtual ~ScopeResolver();
 

	
 
	virtual uint32 GetRandomBits() const;
 
	virtual uint32 GetTriggers() const;
 
	virtual void SetTriggers(int triggers) const;
 

	
 
	virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
 
	virtual void StorePSA(uint reg, int32 value);
 
};
 

	
 
struct TempScopeResolver : public ScopeResolver {
 
	TempScopeResolver(ResolverObject *ro);
 

	
 
	virtual uint32 GetRandomBits() const;
 
	virtual uint32 GetTriggers() const;
 
	virtual void SetTriggers(int triggers) const;
 

	
 
	virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
 
	virtual void StorePSA(uint reg, int32 value);
 
};
 

	
 
struct ResolverObject {
 
	ResolverObject();
 
	ResolverObject(const GRFFile *grffile, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
 
	virtual ~ResolverObject();
 

	
 
	TempScopeResolver temp_scope; ///< Temporary scope resolver to refer back to the methods of #ResolverObject.
 

	
 
	CallbackID callback;
 
	uint32 callback_param1;
 
	uint32 callback_param2;
 

	
 
	byte trigger;
 

	
 
	uint32 last_value;          ///< Result of most recent DeterministicSpriteGroup (including procedure calls)
 
	uint32 reseed[VSG_END];     ///< Collects bits to rerandomise while triggering triggers.
 

	
 
	VarSpriteGroupScope scope;  ///< Scope of currently resolved DeterministicSpriteGroup resp. RandomizedSpriteGroup
 
	byte count;                 ///< Additional scope for RandomizedSpriteGroup
 

	
 
	const GRFFile *grffile;     ///< GRFFile the resolved SpriteGroup belongs to
 

	
 
	union {
 
		struct {
 
			const struct Vehicle *self;
 
			const struct Vehicle *parent;
 
			EngineID self_type;
 
			bool info_view;                ///< Indicates if the item is being drawn in an info window
 
		} vehicle;
 
		struct {
 
			TileIndex tile;
 
		} canal;
 
		struct {
 
			TileIndex tile;
 
			struct BaseStation *st;
 
			const struct StationSpec *statspec;
 
			CargoID cargo_type;
 
			Axis axis;                     ///< Station axis, used only for the slope check callback.
 
		} station;
 
		struct {
 
			TileIndex tile;
 
			Town *town;                    ///< Town of this house
 
			HouseID house_id;
 
			uint16 initial_random_bits;    ///< Random bits during construction checks
 
			bool not_yet_constructed;      ///< True for construction check
 
			uint32 watched_cargo_triggers; ///< Cargo types that triggered the watched cargo callback.
 
		} house;
 
		struct {
 
			TileIndex tile;
 
			Industry *ind;
 
			IndustryGfx gfx;
 
			IndustryType type;
 
		} industry;
 
		struct {
 
			const struct CargoSpec *cs;
 
		} cargo;
 
		struct {
 
			CargoID cargo_type;
 
			uint8 default_selection;
 
			uint8 src_industry;            ///< Source industry substitute type. 0xFF for "town", 0xFE for "unknown".
 
			uint8 dst_industry;            ///< Destination industry substitute type. 0xFF for "town", 0xFE for "unknown".
 
			uint8 distance;
 
			AIConstructionEvent event;
 
			uint8 count;
 
			uint8 station_size;
 
		} generic;
 
		struct {
 
			TileIndex tile;                ///< Tracktile. For track on a bridge this is the southern bridgehead.
 
			TileContext context;           ///< Are we resolving sprites for the upper halftile, or on a bridge?
 
		} routes;
 
		struct {
 
			struct Station *st;            ///< Station of the airport for which the callback is run, or NULL for build gui.
 
			byte airport_id;               ///< Type of airport for which the callback is run
 
			byte layout;                   ///< Layout of the airport to build.
 
			TileIndex tile;                ///< Tile for the callback, only valid for airporttile callbacks.
 
		} airport;
 
		struct {
 
			struct Object *o;              ///< The object the callback is ran for.
 
			TileIndex tile;                ///< The tile related to the object.
 
			uint8 view;                    ///< The view of the object.
 
		} object;
 
	} u;
 

	
 
	uint32 (*GetRandomBits)(const struct ResolverObject*);
 
	uint32 (*GetTriggers)(const struct ResolverObject*);
 
	void (*SetTriggers)(const struct ResolverObject*, int);
 
	uint32 (*GetVariable)(const struct ResolverObject *object, byte variable, uint32 parameter, bool *available);
 
	const SpriteGroup *(*ResolveReal)(const struct ResolverObject*, const RealSpriteGroup*);
 
	const SpriteGroup *(*ResolveRealMethod)(const struct ResolverObject*, const RealSpriteGroup*);
 
	void (*StorePSA)(struct ResolverObject*, uint, int32);
 

	
 
	virtual const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const;
 

	
 
	virtual ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0);
 

	
 
	/**
 
	 * Returns the OR-sum of all bits that need reseeding
 
	 * independent of the scope they were accessed with.
 
	 * @return OR-sum of the bits.
 
	 */
 
	uint32 GetReseedSum() const
 
	{
 
		uint32 sum = 0;
 
		for (VarSpriteGroupScope vsg = VSG_BEGIN; vsg < VSG_END; vsg++) {
 
			sum |= this->reseed[vsg];
 
		}
 
		return sum;
 
	}
 

	
 
	/**
 
	 * Resets the dynamic state of the resolver object.
 
	 * To be called before resolving an Action-1-2-3 chain.
 
	 */
 
	void ResetState()
 
	{
 
		this->last_value = 0;
 
		this->trigger    = 0;
 
		memset(this->reseed, 0, sizeof(this->reseed));
 
	}
 
};
 

	
 
#endif /* NEWGRF_SPRITEGROUP_H */
src/newgrf_station.cpp
Show inline comments
 
@@ -505,97 +505,97 @@ static const SpriteGroup *StationResolve
 
			}
 
			break;
 

	
 
		default:
 
			cargo = st->goods[cargo_type].cargo.Count();
 
			break;
 
	}
 

	
 
	if (HasBit(statspec->flags, SSF_DIV_BY_STATION_SIZE)) cargo /= (st->train_station.w + st->train_station.h);
 
	cargo = min(0xfff, cargo);
 

	
 
	if (cargo > statspec->cargo_threshold) {
 
		if (group->num_loading > 0) {
 
			set = ((cargo - statspec->cargo_threshold) * group->num_loading) / (4096 - statspec->cargo_threshold);
 
			return group->loading[set];
 
		}
 
	} else {
 
		if (group->num_loaded > 0) {
 
			set = (cargo * group->num_loaded) / (statspec->cargo_threshold + 1);
 
			return group->loaded[set];
 
		}
 
	}
 

	
 
	return group->loading[0];
 
}
 

	
 

	
 
/**
 
 * Store a value into the persistent storage of the object's parent.
 
 * @param object Object that we want to query.
 
 * @param pos Position in the persistent storage to use.
 
 * @param value Value to store.
 
 */
 
void StationStorePSA(ResolverObject *object, uint pos, int32 value)
 
{
 
	/* Stations have no persistent storage. */
 
	BaseStation *st = object->u.station.st;
 
	if (object->scope != VSG_SCOPE_PARENT || st == NULL) return;
 

	
 
	TownStorePSA(st->town, object->grffile, pos, value);
 
}
 

	
 
static void NewStationResolver(ResolverObject *res, const StationSpec *statspec, BaseStation *st, TileIndex tile)
 
{
 
	res->GetRandomBits = StationGetRandomBits;
 
	res->GetTriggers   = StationGetTriggers;
 
	res->SetTriggers   = StationSetTriggers;
 
	res->GetVariable   = StationGetVariable;
 
	res->ResolveReal   = StationResolveReal;
 
	res->ResolveRealMethod = StationResolveReal;
 
	res->StorePSA      = StationStorePSA;
 

	
 
	res->u.station.st       = st;
 
	res->u.station.statspec = statspec;
 
	res->u.station.tile     = tile;
 
	res->u.station.axis     = INVALID_AXIS;
 

	
 
	res->callback        = CBID_NO_CALLBACK;
 
	res->callback_param1 = 0;
 
	res->callback_param2 = 0;
 
	res->ResetState();
 

	
 
	res->grffile         = (statspec != NULL ? statspec->grf_prop.grffile : NULL);
 

	
 
	/* Invalidate all cached vars */
 
	_svc.valid = 0;
 
}
 

	
 
static const SpriteGroup *ResolveStation(ResolverObject *object)
 
{
 
	const SpriteGroup *group;
 
	CargoID ctype = CT_DEFAULT_NA;
 

	
 
	if (object->u.station.st == NULL) {
 
		/* No station, so we are in a purchase list */
 
		ctype = CT_PURCHASE;
 
	} else if (Station::IsExpected(object->u.station.st)) {
 
		const Station *st = Station::From(object->u.station.st);
 
		/* Pick the first cargo that we have waiting */
 
		const CargoSpec *cs;
 
		FOR_ALL_CARGOSPECS(cs) {
 
			if (object->u.station.statspec->grf_prop.spritegroup[cs->Index()] != NULL &&
 
					!st->goods[cs->Index()].cargo.Empty()) {
 
				ctype = cs->Index();
 
				break;
 
			}
 
		}
 
	}
 

	
 
	group = object->u.station.statspec->grf_prop.spritegroup[ctype];
 
	if (group == NULL) {
 
		ctype = CT_DEFAULT;
 
		group = object->u.station.statspec->grf_prop.spritegroup[ctype];
 
	}
 

	
 
	if (group == NULL) return NULL;
 

	
 
	/* Remember the cargo type we've picked */
0 comments (0 inline, 0 general)