(svn r24684) -Codechange: Add resolver classes for stations.

replace/41b28d7194a279bdc17475d4fbe2ea6ec885a466
alberth 12 years ago
parent a9b8b22daf
commit c417efc962

@ -357,13 +357,6 @@ struct ResolverObject {
EngineID self_type;
bool info_view; ///< Indicates if the item is being drawn in an info window
} vehicle;
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;
Industry *ind;

@ -221,24 +221,21 @@ static uint32 GetRailContinuationInfo(TileIndex tile)
/* Station Resolver Functions */
static uint32 StationGetRandomBits(const ResolverObject *object)
/* virtual */ uint32 StationScopeResolver::GetRandomBits() const
{
const BaseStation *st = object->u.station.st;
const TileIndex tile = object->u.station.tile;
return (st == NULL ? 0 : st->random_bits) | (tile == INVALID_TILE ? 0 : GetStationTileRandomBits(tile) << 16);
return (this->st == NULL ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16);
}
static uint32 StationGetTriggers(const ResolverObject *object)
/* virtual */ uint32 StationScopeResolver::GetTriggers() const
{
const BaseStation *st = object->u.station.st;
return st == NULL ? 0 : st->waiting_triggers;
return this->st == NULL ? 0 : this->st->waiting_triggers;
}
static void StationSetTriggers(const ResolverObject *object, int triggers)
/* virtual */ void StationScopeResolver::SetTriggers(int triggers) const
{
BaseStation *st = const_cast<BaseStation *>(object->u.station.st);
BaseStation *st = const_cast<BaseStation *>(this->st);
assert(st != NULL);
st->waiting_triggers = triggers;
}
@ -258,28 +255,29 @@ static struct {
uint8 valid; ///< Bits indicating what variable is valid (for each bit, \c 0 is invalid, \c 1 is valid).
} _svc;
static uint32 StationGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
{
const BaseStation *st = object->u.station.st;
TileIndex tile = object->u.station.tile;
if (object->scope == VSG_SCOPE_PARENT) {
/* Pass the request on to the town of the station */
Town *t;
if (st != NULL) {
t = st->town;
} else if (tile != INVALID_TILE) {
t = ClosestTownFromTile(tile, UINT_MAX);
} else {
*available = false;
return UINT_MAX;
/**
* Get the town scope associated with a station, if it exists.
* On the first call, the town scope is created (if possible).
* @return Town scope, if available.
*/
TownScopeResolver *StationResolverObject::GetTown()
{
if (this->town_scope == NULL) {
Town *t = NULL;
if (this->station_scope.st != NULL) {
t = this->station_scope.st->town;
} else if (this->station_scope.tile != INVALID_TILE) {
t = ClosestTownFromTile(this->station_scope.tile, UINT_MAX);
}
return TownGetVariable(variable, parameter, available, t, object->grffile);
if (t == NULL) return NULL;
this->town_scope = new TownScopeResolver(this, t, this->station_scope.st == NULL);
}
return this->town_scope;
}
if (st == NULL) {
/* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
{
if (this->st == NULL) {
/* Station does not exist, so we're in a purchase list or the land slope check callback. */
switch (variable) {
case 0x40:
@ -291,13 +289,14 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, ui
case 0x43: return GetCompanyInfo(_current_company); // Station owner
case 0x44: return 2; // PBS status
case 0x67: // Land info of nearby tile
if (object->u.station.axis != INVALID_AXIS && tile != INVALID_TILE) {
if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, object->u.station.axis); // only perform if it is required
if (this->axis != INVALID_AXIS && this->tile != INVALID_TILE) {
TileIndex tile = this->tile;
if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, this->axis); // only perform if it is required
Slope tileh = GetTileSlope(tile);
bool swap = (object->u.station.axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
bool swap = (this->axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
return GetNearbyTileInformation(tile, object->grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
return GetNearbyTileInformation(tile, this->ro->grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
}
break;
@ -311,60 +310,62 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, ui
switch (variable) {
/* Calculated station variables */
case 0x40:
if (!HasBit(_svc.valid, 0)) { _svc.v40 = GetPlatformInfoHelper(tile, false, false, false); SetBit(_svc.valid, 0); }
if (!HasBit(_svc.valid, 0)) { _svc.v40 = GetPlatformInfoHelper(this->tile, false, false, false); SetBit(_svc.valid, 0); }
return _svc.v40;
case 0x41:
if (!HasBit(_svc.valid, 1)) { _svc.v41 = GetPlatformInfoHelper(tile, true, false, false); SetBit(_svc.valid, 1); }
if (!HasBit(_svc.valid, 1)) { _svc.v41 = GetPlatformInfoHelper(this->tile, true, false, false); SetBit(_svc.valid, 1); }
return _svc.v41;
case 0x42: return GetTerrainType(tile) | (GetReverseRailTypeTranslation(GetRailType(tile), object->u.station.statspec->grf_prop.grffile) << 8);
case 0x43: return GetCompanyInfo(st->owner); // Station owner
case 0x44: return HasStationReservation(tile) ? 7 : 4; // PBS status
case 0x42: return GetTerrainType(this->tile) | (GetReverseRailTypeTranslation(GetRailType(this->tile), this->statspec->grf_prop.grffile) << 8);
case 0x43: return GetCompanyInfo(this->st->owner); // Station owner
case 0x44: return HasStationReservation(this->tile) ? 7 : 4; // PBS status
case 0x45:
if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(tile); SetBit(_svc.valid, 2); }
if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(this->tile); SetBit(_svc.valid, 2); }
return _svc.v45;
case 0x46:
if (!HasBit(_svc.valid, 3)) { _svc.v46 = GetPlatformInfoHelper(tile, false, false, true); SetBit(_svc.valid, 3); }
if (!HasBit(_svc.valid, 3)) { _svc.v46 = GetPlatformInfoHelper(this->tile, false, false, true); SetBit(_svc.valid, 3); }
return _svc.v46;
case 0x47:
if (!HasBit(_svc.valid, 4)) { _svc.v47 = GetPlatformInfoHelper(tile, true, false, true); SetBit(_svc.valid, 4); }
if (!HasBit(_svc.valid, 4)) { _svc.v47 = GetPlatformInfoHelper(this->tile, true, false, true); SetBit(_svc.valid, 4); }
return _svc.v47;
case 0x49:
if (!HasBit(_svc.valid, 5)) { _svc.v49 = GetPlatformInfoHelper(tile, false, true, false); SetBit(_svc.valid, 5); }
if (!HasBit(_svc.valid, 5)) { _svc.v49 = GetPlatformInfoHelper(this->tile, false, true, false); SetBit(_svc.valid, 5); }
return _svc.v49;
case 0x4A: // Animation frame of tile
return GetAnimationFrame(tile);
return GetAnimationFrame(this->tile);
/* Variables which use the parameter */
/* Variables 0x60 to 0x65 and 0x69 are handled separately below */
case 0x66: // Animation frame of nearby tile
case 0x66: { // Animation frame of nearby tile
TileIndex tile = this->tile;
if (parameter != 0) tile = GetNearbyTile(parameter, tile);
return st->TileBelongsToRailStation(tile) ? GetAnimationFrame(tile) : UINT_MAX;
return this->st->TileBelongsToRailStation(tile) ? GetAnimationFrame(tile) : UINT_MAX;
}
case 0x67: { // Land info of nearby tile
Axis axis = GetRailStationAxis(tile);
Axis axis = GetRailStationAxis(this->tile);
TileIndex tile = this->tile;
if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required
Slope tileh = GetTileSlope(tile);
bool swap = (axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E));
return GetNearbyTileInformation(tile, object->grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
return GetNearbyTileInformation(tile, this->ro->grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0);
}
case 0x68: { // Station info of nearby tiles
TileIndex nearby_tile = GetNearbyTile(parameter, tile);
TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
uint32 grfid = st->speclist[GetCustomStationSpecIndex(tile)].grfid;
bool perpendicular = GetRailStationAxis(tile) != GetRailStationAxis(nearby_tile);
bool same_station = st->TileBelongsToRailStation(nearby_tile);
uint32 grfid = this->st->speclist[GetCustomStationSpecIndex(this->tile)].grfid;
bool perpendicular = GetRailStationAxis(this->tile) != GetRailStationAxis(nearby_tile);
bool same_station = this->st->TileBelongsToRailStation(nearby_tile);
uint32 res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10;
if (IsCustomStationSpecIndex(nearby_tile)) {
@ -376,13 +377,13 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, ui
/* General station variables */
case 0x82: return 50;
case 0x84: return st->string_id;
case 0x84: return this->st->string_id;
case 0x86: return 0;
case 0xF0: return st->facilities;
case 0xFA: return Clamp(st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
case 0xF0: return this->st->facilities;
case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
}
return st->GetNewGRFVariable(object, variable, parameter, available);
return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
}
uint32 Station::GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const
@ -477,22 +478,16 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject *object, byte variable,
return UINT_MAX;
}
static const SpriteGroup *StationResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
/* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup *group) const
{
const BaseStation *bst = object->u.station.st;
const StationSpec *statspec = object->u.station.statspec;
uint set;
uint cargo = 0;
CargoID cargo_type = object->u.station.cargo_type;
if (bst == NULL || statspec->cls_id == STAT_CLASS_WAYP) {
if (this->station_scope.st == NULL || this->station_scope.statspec->cls_id == STAT_CLASS_WAYP) {
return group->loading[0];
}
const Station *st = Station::From(bst);
uint cargo = 0;
const Station *st = Station::From(this->station_scope.st);
switch (cargo_type) {
switch (this->station_scope.cargo_type) {
case CT_INVALID:
case CT_DEFAULT_NA:
case CT_PURCHASE:
@ -500,27 +495,27 @@ static const SpriteGroup *StationResolveReal(const ResolverObject *object, const
break;
case CT_DEFAULT:
for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
cargo += st->goods[cargo_type].cargo.Count();
}
break;
default:
cargo = st->goods[cargo_type].cargo.Count();
cargo = st->goods[this->station_scope.cargo_type].cargo.Count();
break;
}
if (HasBit(statspec->flags, SSF_DIV_BY_STATION_SIZE)) cargo /= (st->train_station.w + st->train_station.h);
if (HasBit(this->station_scope.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 (cargo > this->station_scope.statspec->cargo_threshold) {
if (group->num_loading > 0) {
set = ((cargo - statspec->cargo_threshold) * group->num_loading) / (4096 - statspec->cargo_threshold);
uint set = ((cargo - this->station_scope.statspec->cargo_threshold) * group->num_loading) / (4096 - this->station_scope.statspec->cargo_threshold);
return group->loading[set];
}
} else {
if (group->num_loaded > 0) {
set = (cargo * group->num_loaded) / (statspec->cargo_threshold + 1);
uint set = (cargo * group->num_loaded) / (this->station_scope.statspec->cargo_threshold + 1);
return group->loaded[set];
}
}
@ -528,61 +523,43 @@ static const SpriteGroup *StationResolveReal(const ResolverObject *object, const
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)
StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseStation *st, TileIndex tile,
CallbackID callback, uint32 callback_param1, uint32 callback_param2)
: ResolverObject((statspec != NULL ? statspec->grf_prop.grffile : NULL), callback, callback_param1, callback_param2),
station_scope(this, statspec, st, tile), town_scope(NULL)
{
/* 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);
/* Invalidate all cached vars */
_svc.valid = 0;
}
static void NewStationResolver(ResolverObject *res, const StationSpec *statspec, BaseStation *st, TileIndex tile)
StationResolverObject::~StationResolverObject()
{
res->GetRandomBits = StationGetRandomBits;
res->GetTriggers = StationGetTriggers;
res->SetTriggers = StationSetTriggers;
res->GetVariable = StationGetVariable;
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);
delete this->town_scope;
}
/* Invalidate all cached vars */
_svc.valid = 0;
StationScopeResolver::StationScopeResolver(ResolverObject *ro, const StationSpec *statspec, BaseStation *st, TileIndex tile)
: ScopeResolver(ro)
{
this->tile = tile;
this->st = st;
this->statspec = statspec;
this->cargo_type = CT_INVALID;
this->axis = INVALID_AXIS;
}
static const SpriteGroup *ResolveStation(ResolverObject *object)
static const SpriteGroup *ResolveStation(StationResolverObject *object)
{
const SpriteGroup *group;
CargoID ctype = CT_DEFAULT_NA;
if (object->u.station.st == NULL) {
if (object->station_scope.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);
} else if (Station::IsExpected(object->station_scope.st)) {
const Station *st = Station::From(object->station_scope.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 &&
if (object->station_scope.statspec->grf_prop.spritegroup[cs->Index()] != NULL &&
!st->goods[cs->Index()].cargo.Empty()) {
ctype = cs->Index();
break;
@ -590,16 +567,15 @@ static const SpriteGroup *ResolveStation(ResolverObject *object)
}
}
group = object->u.station.statspec->grf_prop.spritegroup[ctype];
const SpriteGroup *group = object->station_scope.statspec->grf_prop.spritegroup[ctype];
if (group == NULL) {
ctype = CT_DEFAULT;
group = object->u.station.statspec->grf_prop.spritegroup[ctype];
group = object->station_scope.statspec->grf_prop.spritegroup[ctype];
if (group == NULL) return NULL;
}
if (group == NULL) return NULL;
/* Remember the cargo type we've picked */
object->u.station.cargo_type = ctype;
object->station_scope.cargo_type = ctype;
return SpriteGroup::Resolve(group, object);
}
@ -614,13 +590,8 @@ static const SpriteGroup *ResolveStation(ResolverObject *object)
*/
SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32 var10)
{
const SpriteGroup *group;
ResolverObject object;
NewStationResolver(&object, statspec, st, tile);
object.callback_param1 = var10;
group = ResolveStation(&object);
StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, var10);
const SpriteGroup *group = ResolveStation(&object);
if (group == NULL || group->type != SGT_RESULT) return 0;
return group->GetResult() - 0x42D;
}
@ -636,15 +607,11 @@ SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st
*/
SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info)
{
const SpriteGroup *group;
ResolverObject object;
NewStationResolver(&object, statspec, st, tile);
object.callback_param1 = 2; // Indicate we are resolving the foundation sprites
object.callback_param2 = layout | (edge_info << 16);
/* callback_param1 == 2 means we are resolving the foundation sprites. */
StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, 2, layout | (edge_info << 16));
ClearRegister(0x100);
group = ResolveStation(&object);
const SpriteGroup *group = ResolveStation(&object);
if (group == NULL || group->type != SGT_RESULT) return 0;
return group->GetResult() + GetRegister(0x100);
}
@ -652,16 +619,8 @@ SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseS
uint16 GetStationCallback(CallbackID callback, uint32 param1, uint32 param2, const StationSpec *statspec, BaseStation *st, TileIndex tile)
{
const SpriteGroup *group;
ResolverObject object;
NewStationResolver(&object, statspec, st, tile);
object.callback = callback;
object.callback_param1 = param1;
object.callback_param2 = param2;
group = ResolveStation(&object);
StationResolverObject object(statspec, st, tile, callback, param1, param2);
const SpriteGroup *group = ResolveStation(&object);
if (group == NULL) return CALLBACK_FAILED;
return group->GetCallbackResult();
}
@ -681,13 +640,10 @@ CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_til
TileIndexDiff diff = cur_tile - north_tile;
Slope slope = GetTileSlope(cur_tile);
ResolverObject object;
NewStationResolver(&object, statspec, NULL, cur_tile);
object.callback = CBID_STATION_LAND_SLOPE_CHECK;
object.callback_param1 = slope << 4 | (slope ^ (axis == AXIS_Y && HasBit(slope, CORNER_W) != HasBit(slope, CORNER_E) ? SLOPE_EW : 0));
object.callback_param2 = numtracks << 24 | plat_len << 16 | (axis == AXIS_Y ? TileX(diff) << 8 | TileY(diff) : TileY(diff) << 8 | TileX(diff));
object.u.station.axis = axis;
StationResolverObject object(statspec, NULL, cur_tile, CBID_STATION_LAND_SLOPE_CHECK,
(slope << 4) | (slope ^ (axis == AXIS_Y && HasBit(slope, CORNER_W) != HasBit(slope, CORNER_E) ? SLOPE_EW : 0)),
(numtracks << 24) | (plat_len << 16) | (axis == AXIS_Y ? TileX(diff) << 8 | TileY(diff) : TileY(diff) << 8 | TileX(diff)));
object.station_scope.axis = axis;
const SpriteGroup *group = ResolveStation(&object);
uint16 cb_res = group != NULL ? group->GetCallbackResult() : CALLBACK_FAILED;
@ -993,12 +949,3 @@ void StationUpdateAnimTriggers(BaseStation *st)
}
}
/**
* Resolve a station's spec and such so we can get a variable.
* @param ro The resolver object to fill.
* @param index The station to get the data from.
*/
void GetStationResolver(ResolverObject *ro, uint index)
{
NewStationResolver(ro, GetStationSpec(index), Station::GetByTile(index), index);
}

@ -19,6 +19,54 @@
#include "cargo_type.h"
#include "station_type.h"
#include "rail_type.h"
#include "newgrf_spritegroup.h"
#include "newgrf_town.h"
struct StationScopeResolver : public ScopeResolver {
TileIndex tile;
struct BaseStation *st;
const struct StationSpec *statspec;
CargoID cargo_type;
Axis axis; ///< Station axis, used only for the slope check callback.
StationScopeResolver(ResolverObject *ro, const StationSpec *statspec, BaseStation *st, TileIndex tile);
/* virtual */ uint32 GetRandomBits() const;
/* virtual */ uint32 GetTriggers() const;
/* virtual */ void SetTriggers(int triggers) const;
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
};
struct StationResolverObject : public ResolverObject {
StationScopeResolver station_scope;
TownScopeResolver *town_scope;
StationResolverObject(const StationSpec *statspec, BaseStation *st, TileIndex tile,
CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0);
~StationResolverObject();
TownScopeResolver *GetTown();
/* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0)
{
switch (scope) {
case VSG_SCOPE_SELF:
return &this->station_scope;
case VSG_SCOPE_PARENT: {
TownScopeResolver *tsr = this->GetTown();
if (tsr != NULL) return tsr;
/* FALL-THROUGH */
}
default:
return &this->default_scope; // XXX ResolverObject::GetScope(scope, relative);
}
}
/* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const;
};
enum StationClassID {
STAT_CLASS_BEGIN = 0, ///< the lowest valid value

@ -126,7 +126,12 @@ class NIHStation : public NIHelper {
const void *GetSpec(uint index) const { return GetStationSpec(index); }
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; }
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetStationResolver(ResolverObject *ro, uint index); GetStationResolver(ro, index); }
/* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const
{
StationResolverObject ro(GetStationSpec(index), Station::GetByTile(index), index);
return ro.GetScope(ro.scope)->GetVariable(var, param, avail);
}
};
static const NIFeature _nif_station = {

Loading…
Cancel
Save