diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -10,6 +10,7 @@ /** @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" @@ -36,7 +37,7 @@ RandomizedSpriteGroup::~RandomizedSprite TemporaryStorageArray _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; @@ -49,7 +50,7 @@ static inline uint32 GetVariable(const R 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); @@ -58,10 +59,119 @@ static inline uint32 GetVariable(const R 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 @@ -111,7 +221,7 @@ static U EvalAdjustT(const Deterministic 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); @@ -148,9 +258,9 @@ const SpriteGroup *DeterministicSpriteGr * 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) { @@ -190,16 +300,14 @@ const SpriteGroup *DeterministicSpriteGr 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); @@ -210,11 +318,11 @@ const SpriteGroup *RandomizedSpriteGroup 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); } @@ -222,7 +330,7 @@ const SpriteGroup *RandomizedSpriteGroup const SpriteGroup *RealSpriteGroup::Resolve(ResolverObject *object) const { - return object->ResolveReal(object, this); + return object->ResolveReal(this); } /**