(svn r24683) -Codechange: Add resolver classes for objects.

This commit is contained in:
alberth 2012-11-10 20:40:46 +00:00
parent d7b62da87b
commit a9b8b22daf
4 changed files with 111 additions and 105 deletions

View File

@ -16,8 +16,6 @@
#include "newgrf_class_func.h"
#include "newgrf_object.h"
#include "newgrf_sound.h"
#include "newgrf_spritegroup.h"
#include "newgrf_town.h"
#include "object_base.h"
#include "object_map.h"
#include "tile_cmd.h"
@ -118,23 +116,19 @@ bool NewGRFClass<Tspec, Tid, Tmax>::IsUIAvailable(uint index) const
INSTANTIATE_NEWGRF_CLASS_METHODS(ObjectClass, ObjectSpec, ObjectClassID, OBJECT_CLASS_MAX)
static uint32 ObjectGetRandomBits(const ResolverObject *object)
ObjectScopeResolver::ObjectScopeResolver(ResolverObject *ro, Object *obj, TileIndex tile, uint8 view)
: ScopeResolver(ro)
{
TileIndex t = object->u.object.tile;
return IsValidTile(t) && IsTileType(t, MP_OBJECT) ? GetObjectRandomBits(t) : 0;
this->obj = obj;
this->tile = tile;
this->view = view;
}
static uint32 ObjectGetTriggers(const ResolverObject *object)
/* virtual */ uint32 ObjectScopeResolver::GetRandomBits() const
{
return 0;
return IsValidTile(this->tile) && IsTileType(this->tile, MP_OBJECT) ? GetObjectRandomBits(this->tile) : 0;
}
static void ObjectSetTriggers(const ResolverObject *object, int triggers)
{
}
/**
* Make an analysis of a tile and get the object type.
* @param tile TileIndex of the tile to query
@ -232,21 +226,13 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid,
}
/** Used by the resolver to get values for feature 0F deterministic spritegroups. */
static uint32 ObjectGetVariable(const ResolverObject *object, byte variable, uint32 parameter, bool *available)
/* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
{
const Object *o = object->u.object.o;
TileIndex tile = object->u.object.tile;
if (object->scope == VSG_SCOPE_PARENT) {
/* Pass the request on to the town of the object */
return TownGetVariable(variable, parameter, available, (o == NULL) ? ClosestTownFromTile(tile, UINT_MAX) : o->town, object->grffile);
}
/* We get the town from the object, or we calculate the closest
* town if we need to when there's no object. */
const Town *t = NULL;
if (o == NULL) {
if (this->obj == NULL) {
switch (variable) {
/* Allow these when there's no object. */
case 0x41:
@ -259,8 +245,8 @@ static uint32 ObjectGetVariable(const ResolverObject *object, byte variable, uin
/* Allow these, but find the closest town. */
case 0x45:
case 0x46:
if (!IsValidTile(tile)) goto unhandled;
t = ClosestTownFromTile(tile, UINT_MAX);
if (!IsValidTile(this->tile)) goto unhandled;
t = ClosestTownFromTile(this->tile, UINT_MAX);
break;
/* Construction date */
@ -270,7 +256,7 @@ static uint32 ObjectGetVariable(const ResolverObject *object, byte variable, uin
case 0x44: return _current_company;
/* Object view */
case 0x48: return object->u.object.view;
case 0x48: return this->view;
/*
* Disallow the rest:
@ -284,62 +270,64 @@ static uint32 ObjectGetVariable(const ResolverObject *object, byte variable, uin
}
/* If there's an invalid tile, then we don't have enough information at all. */
if (!IsValidTile(tile)) goto unhandled;
if (!IsValidTile(this->tile)) goto unhandled;
} else {
t = o->town;
t = this->obj->town;
}
switch (variable) {
/* Relative position. */
case 0x40: {
uint offset = tile - o->location.tile;
uint offset = this->tile - this->obj->location.tile;
uint offset_x = TileX(offset);
uint offset_y = TileY(offset);
return offset_y << 20 | offset_x << 16 | offset_y << 8 | offset_x;
}
/* Tile information. */
case 0x41: return GetTileSlope(tile) << 8 | GetTerrainType(tile);
case 0x41: return GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile);
/* Construction date */
case 0x42: return o->build_date;
case 0x42: return this->obj->build_date;
/* Animation counter */
case 0x43: return GetAnimationFrame(tile);
case 0x43: return GetAnimationFrame(this->tile);
/* Object founder information */
case 0x44: return GetTileOwner(tile);
case 0x44: return GetTileOwner(this->tile);
/* Get town zone and Manhattan distance of closest town */
case 0x45: return GetTownRadiusGroup(t, tile) << 16 | min(DistanceManhattan(tile, t->xy), 0xFFFF);
case 0x45: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceManhattan(this->tile, t->xy), 0xFFFF);
/* Get square of Euclidian distance of closes town */
case 0x46: return GetTownRadiusGroup(t, tile) << 16 | min(DistanceSquare(tile, t->xy), 0xFFFF);
case 0x46: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceSquare(this->tile, t->xy), 0xFFFF);
/* Object colour */
case 0x47: return o->colour;
case 0x47: return this->obj->colour;
/* Object view */
case 0x48: return o->view;
case 0x48: return this->obj->view;
/* Get object ID at offset param */
case 0x60: return GetObjectIDAtOffset(GetNearbyTile(parameter, tile), object->grffile->grfid);
case 0x60: return GetObjectIDAtOffset(GetNearbyTile(parameter, this->tile), this->ro->grffile->grfid);
/* Get random tile bits at offset param */
case 0x61:
tile = GetNearbyTile(parameter, tile);
return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == o) ? GetObjectRandomBits(tile) : 0;
case 0x61: {
TileIndex tile = GetNearbyTile(parameter, this->tile);
return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetObjectRandomBits(tile) : 0;
}
/* Land info of nearby tiles */
case 0x62: return GetNearbyObjectTileInformation(parameter, tile, o == NULL ? INVALID_OBJECT : o->index, object->grffile->grf_version >= 8);
case 0x62: return GetNearbyObjectTileInformation(parameter, this->tile, this->obj == NULL ? INVALID_OBJECT : this->obj->index, this->ro->grffile->grf_version >= 8);
/* Animation counter of nearby tile */
case 0x63:
tile = GetNearbyTile(parameter, tile);
return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == o) ? GetAnimationFrame(tile) : 0;
case 0x63: {
TileIndex tile = GetNearbyTile(parameter, this->tile);
return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetAnimationFrame(tile) : 0;
}
/* Count of object, distance of closest instance */
case 0x64: return GetCountAndDistanceOfClosestInstance(parameter, object->grffile->grfid, tile, o);
case 0x64: return GetCountAndDistanceOfClosestInstance(parameter, this->ro->grffile->grfid, this->tile, this->obj);
}
unhandled:
@ -349,7 +337,7 @@ unhandled:
return UINT_MAX;
}
static const SpriteGroup *ObjectResolveReal(const ResolverObject *object, const RealSpriteGroup *group)
/* virtual */ const SpriteGroup *ObjectResolverObject::ResolveReal(const RealSpriteGroup *group) const
{
/* Objects do not have 'real' groups */
return NULL;
@ -373,44 +361,36 @@ static const SpriteGroup *GetObjectSpriteGroup(const ObjectSpec *spec, const Obj
}
/**
* 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)
ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, TileIndex tile, uint8 view,
CallbackID callback, uint32 param1, uint32 param2)
: ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(this, obj, tile, view)
{
/* Objects have no persistent storage. */
Object *o = object->u.object.o;
if (object->scope != VSG_SCOPE_PARENT || o == NULL) return;
this->town_scope = NULL;
}
/* Pass the request on to the town of the object */
TownStorePSA(o->town, object->grffile, pos, value);
ObjectResolverObject::~ObjectResolverObject()
{
delete this->town_scope;
}
/**
* Returns a resolver object to be used with feature 0F spritegroups.
* Get the town resolver scope that belongs to this object resolver.
* On the first call, the town scope is created (if possible).
* @return Town scope, if available.
*/
static void NewObjectResolver(ResolverObject *res, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0)
TownScopeResolver *ObjectResolverObject::GetTown()
{
res->GetRandomBits = ObjectGetRandomBits;
res->GetTriggers = ObjectGetTriggers;
res->SetTriggers = ObjectSetTriggers;
res->GetVariable = ObjectGetVariable;
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;
if (this->town_scope == NULL) {
Town *t;
if (this->object_scope.obj != NULL) {
t = this->object_scope.obj->town;
} else {
t = ClosestTownFromTile(this->object_scope.tile, UINT_MAX);
}
if (t == NULL) return NULL;
this->town_scope = new TownScopeResolver(this, t, this->object_scope.obj == NULL);
}
return this->town_scope;
}
/**
@ -426,12 +406,7 @@ static void NewObjectResolver(ResolverObject *res, const ObjectSpec *spec, Objec
*/
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;
ObjectResolverObject object(spec, o, tile, view, callback, param1, param2);
const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, o), &object);
if (group == NULL) return CALLBACK_FAILED;
@ -472,9 +447,8 @@ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *grou
*/
void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec)
{
ResolverObject object;
Object *o = Object::GetByTile(ti->tile);
NewObjectResolver(&object, spec, o, ti->tile);
ObjectResolverObject object(spec, o, ti->tile);
const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, o), &object);
if (group == NULL || group->type != SGT_TILELAYOUT) return;
@ -491,9 +465,7 @@ void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec)
*/
void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view)
{
ResolverObject object;
NewObjectResolver(&object, spec, NULL, INVALID_TILE, view);
ObjectResolverObject object(spec, NULL, INVALID_TILE, view);
const SpriteGroup *group = SpriteGroup::Resolve(GetObjectSpriteGroup(spec, NULL), &object);
if (group == NULL || group->type != SGT_TILELAYOUT) return;
@ -588,13 +560,3 @@ void TriggerObjectAnimation(Object *o, ObjectAnimationTrigger trigger, const Obj
TriggerObjectTileAnimation(o, tile, trigger, spec);
}
}
/**
* Resolve an object's spec and such so we can get a variable.
* @param ro The resolver object to fill.
* @param index The object tile to get the data from.
*/
void GetObjectResolver(ResolverObject *ro, uint index)
{
NewObjectResolver(ro, ObjectSpec::GetByTile(index), Object::GetByTile(index), index);
}

View File

@ -13,6 +13,8 @@
#define NEWGRF_OBJECT_H
#include "newgrf_callbacks.h"
#include "newgrf_spritegroup.h"
#include "newgrf_town.h"
#include "economy_func.h"
#include "date_type.h"
#include "object_type.h"
@ -90,6 +92,48 @@ struct ObjectSpec {
static const ObjectSpec *GetByTile(TileIndex tile);
};
struct ObjectScopeResolver : public ScopeResolver {
struct Object *obj; ///< The object the callback is ran for.
TileIndex tile; ///< The tile related to the object.
uint8 view; ///< The view of the object.
ObjectScopeResolver(ResolverObject *ro, Object *obj, TileIndex tile, uint8 view = 0);
/* virtual */ uint32 GetRandomBits() const;
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
};
/** A resolver object to be used with feature 0F spritegroups. */
struct ObjectResolverObject : public ResolverObject {
ObjectScopeResolver object_scope;
TownScopeResolver *town_scope;
ObjectResolverObject(const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0,
CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0);
~ObjectResolverObject();
/* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0)
{
switch (scope) {
case VSG_SCOPE_SELF:
return &this->object_scope;
case VSG_SCOPE_PARENT: {
TownScopeResolver *tsr = this->GetTown();
if (tsr != NULL) return tsr;
/* FALL-THROUGH */
}
default: return &this->default_scope; // XXX return &ResolverObject::GetScope(scope, relative);
}
}
const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const;
private:
TownScopeResolver *GetTown();
};
/** Struct containing information relating to station classes. */
typedef NewGRFClass<ObjectSpec, ObjectClassID, OBJECT_CLASS_MAX> ObjectClass;

View File

@ -390,11 +390,6 @@ struct ResolverObject {
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*);

View File

@ -361,7 +361,12 @@ class NIHObject : public NIHelper {
const void *GetSpec(uint index) const { return ObjectSpec::GetByTile(index); }
void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); }
uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; }
void Resolve(ResolverObject *ro, uint32 index) const { extern void GetObjectResolver(ResolverObject *ro, uint index); GetObjectResolver(ro, index); }
/* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const
{
ObjectResolverObject ro(ObjectSpec::GetByTile(index), Object::GetByTile(index), index);
return ro.GetScope(ro.scope)->GetVariable(var, param, avail);
}
};
static const NIFeature _nif_object = {