diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 300f246a4b..bbdebc94ca 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -325,7 +325,7 @@ static uint8_t MapAircraftMovementAction(const Aircraft *v) if (this->self_scope.v != nullptr && (relative != this->cached_relative_count || count == 0)) { /* Note: This caching only works as long as the VSG_SCOPE_RELATIVE cannot be used in * VarAct2 with procedure calls. */ - if (count == 0) count = GetRegister(0x100); + if (count == 0) count = this->GetRegister(0x100); const Vehicle *v = nullptr; switch (GB(relative, 6, 2)) { @@ -621,14 +621,14 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec if (object->ro.callback == CBID_NO_CALLBACK || object->ro.callback == CBID_RANDOM_TRIGGER || object->ro.callback == CBID_TRAIN_ALLOW_WAGON_ATTACH || object->ro.callback == CBID_VEHICLE_START_STOP_CHECK || object->ro.callback == CBID_VEHICLE_32DAY_CALLBACK || object->ro.callback == CBID_VEHICLE_COLOUR_MAPPING || object->ro.callback == CBID_VEHICLE_SPAWN_VISUAL_EFFECT) { - Vehicle *u = v->Move(GetRegister(0x10F)); + Vehicle *u = v->Move(object->ro.GetRegister(0x10F)); if (u == nullptr) return 0; // available, but zero if (parameter == 0x5F) { /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */ return (u->random_bits << 8) | u->waiting_random_triggers.base(); } else { - return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available); + return VehicleGetVariable(u, object, parameter, object->ro.GetRegister(0x10E), available); } } /* Not available */ @@ -1102,7 +1102,7 @@ static void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction d object.ResetState(); object.callback_param1 = image_type | (stack << 8); const auto *group = object.Resolve(); - int32_t reg100 = sprite_stack ? GetRegister(0x100) : 0; + int32_t reg100 = sprite_stack ? object.GetRegister(0x100) : 0; if (group != nullptr && group->num_sprites != 0) { result->seq[result->count].sprite = group->sprite + (direction % group->num_sprites); result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring @@ -1145,7 +1145,7 @@ static void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, En object.ResetState(); object.callback_param1 = image_type | (stack << 8); const auto *group = object.Resolve(); - int32_t reg100 = sprite_stack ? GetRegister(0x100) : 0; + int32_t reg100 = sprite_stack ? object.GetRegister(0x100) : 0; if (group != nullptr && group->num_sprites != 0) { result->seq[result->count].sprite = group->sprite + (rotor_pos % group->num_sprites); result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 8376ca6a6e..0c2769df7b 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -389,8 +389,8 @@ static uint32_t GetDistanceFromNearbyHouse(uint8_t parameter, TileIndex start_ti if (!IsValidCargoType(cargo_type)) return 0; /* Extract tile offset. */ - int8_t x_offs = GB(GetRegister(0x100), 0, 8); - int8_t y_offs = GB(GetRegister(0x100), 8, 8); + int8_t x_offs = GB(this->ro.GetRegister(0x100), 0, 8); + int8_t y_offs = GB(this->ro.GetRegister(0x100), 8, 8); TileIndex testtile = Map::WrapToMap(this->tile + TileDiffXY(x_offs, y_offs)); StationFinder stations(TileArea(testtile, 1, 1)); diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index d3d3f085f0..cf8876dd25 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -107,15 +107,16 @@ static uint32_t GetClosestIndustry(TileIndex tile, IndustryType type, const Indu * Implementation of both var 67 and 68 * since the mechanism is almost the same, it is easier to regroup them on the same * function. + * @param object ResolverObject owning the temporary storage. * @param param_set_id parameter given to the callback, which is the set id, or the local id, in our terminology * @param layout_filter on what layout do we filter? * @param town_filter Do we filter on the same town as the current industry? * @param current Industry for which the inquiry is made * @return the formatted answer to the callback : rr(reserved) cc(count) dddd(manhattan distance of closest sister) */ -static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_set_id, uint8_t layout_filter, bool town_filter, const Industry *current) +static uint32_t GetCountAndDistanceOfClosestInstance(const ResolverObject &object, uint8_t param_set_id, uint8_t layout_filter, bool town_filter, const Industry *current) { - uint32_t grf_id = static_cast(GetRegister(0x100)); ///< Get the GRFID of the definition to look for in register 100h + uint32_t grf_id = static_cast(object.GetRegister(0x100)); ///< Get the GRFID of the definition to look for in register 100h IndustryType industry_type; uint32_t closest_dist = UINT32_MAX; uint8_t count = 0; @@ -311,11 +312,11 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_set_id, uint8 uint8_t layout_filter = 0; bool town_filter = false; if (variable == 0x68) { - int32_t reg = GetRegister(0x101); + int32_t reg = this->ro.GetRegister(0x101); layout_filter = GB(reg, 0, 8); town_filter = HasBit(reg, 8); } - return GetCountAndDistanceOfClosestInstance(parameter, layout_filter, town_filter, this->industry); + return GetCountAndDistanceOfClosestInstance(this->ro, parameter, layout_filter, town_filter, this->industry); } case 0x69: @@ -596,11 +597,6 @@ uint32_t GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityC return default_prob; } -static int32_t DerefIndProd(int field, bool use_register) -{ - return use_register ? GetRegister(field) : field; -} - /** * Get the industry production callback and apply it to the industry. * @param ind the industry this callback has to be called for @@ -615,6 +611,10 @@ void IndustryProductionCallback(Industry *ind, int reason) if (spec->behaviour.Test(IndustryBehaviour::ProdMultiHandling)) multiplier = ind->prod_level; object.callback_param2 = reason; + auto deref_ind_prod = [&object](int field, bool use_register) -> int32_t { + return use_register ? object.GetRegister(field) : field; + }; + for (uint loop = 0;; loop++) { /* limit the number of calls to break infinite loops. * 'loop' is provided as 16 bits to the newgrf, so abort when those are exceeded. */ @@ -648,27 +648,27 @@ void IndustryProductionCallback(Industry *ind, int reason) /* Callback parameters map directly to industry cargo slot indices */ for (uint i = 0; i < group->num_input && i < ind->accepted.size(); i++) { if (!IsValidCargoType(ind->accepted[i].cargo)) continue; - ind->accepted[i].waiting = ClampTo(ind->accepted[i].waiting - DerefIndProd(group->subtract_input[i], deref) * multiplier); + ind->accepted[i].waiting = ClampTo(ind->accepted[i].waiting - deref_ind_prod(group->subtract_input[i], deref) * multiplier); } for (uint i = 0; i < group->num_output && i < ind->produced.size(); i++) { if (!IsValidCargoType(ind->produced[i].cargo)) continue; - ind->produced[i].waiting = ClampTo(ind->produced[i].waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier); + ind->produced[i].waiting = ClampTo(ind->produced[i].waiting + std::max(deref_ind_prod(group->add_output[i], deref), 0) * multiplier); } } else { /* Callback receives list of cargos to apply for, which need to have their cargo slots in industry looked up */ for (uint i = 0; i < group->num_input; i++) { auto it = ind->GetCargoAccepted(group->cargo_input[i]); if (it == std::end(ind->accepted)) continue; - it->waiting = ClampTo(it->waiting - DerefIndProd(group->subtract_input[i], deref) * multiplier); + it->waiting = ClampTo(it->waiting - deref_ind_prod(group->subtract_input[i], deref) * multiplier); } for (uint i = 0; i < group->num_output; i++) { auto it = ind->GetCargoProduced(group->cargo_output[i]); if (it == std::end(ind->produced)) continue; - it->waiting = ClampTo(it->waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier); + it->waiting = ClampTo(it->waiting + std::max(deref_ind_prod(group->add_output[i], deref), 0) * multiplier); } } - int32_t again = DerefIndProd(group->again, deref); + int32_t again = deref_ind_prod(group->again, deref); if (again == 0) break; SB(object.callback_param2, 24, 8, again); diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index 397cd4db3c..e7cb9d31d5 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -225,15 +225,16 @@ static uint32_t GetClosestObject(TileIndex tile, ObjectType type, const Object * /** * Implementation of var 65 + * @param object ResolverObject owning the temporary storage. * @param local_id Parameter given to the callback, which is the set id, or the local id, in our terminology. * @param grfid The object's GRFID. * @param tile The tile to look from. * @param current Object for which the inquiry is made * @return The formatted answer to the callback : rr(reserved) cc(count) dddd(manhattan distance of closest sister) */ -static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t local_id, uint32_t grfid, TileIndex tile, const Object *current) +static uint32_t GetCountAndDistanceOfClosestInstance(const ResolverObject &object, uint8_t local_id, uint32_t grfid, TileIndex tile, const Object *current) { - uint32_t grf_id = static_cast(GetRegister(0x100)); // Get the GRFID of the definition to look for in register 100h + uint32_t grf_id = static_cast(object.GetRegister(0x100)); // Get the GRFID of the definition to look for in register 100h uint32_t idx; /* Determine what will be the object type to look for */ @@ -361,7 +362,7 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t local_id, uint32_t } /* Count of object, distance of closest instance */ - case 0x64: return GetCountAndDistanceOfClosestInstance(parameter, this->ro.grffile->grfid, this->tile, this->obj); + case 0x64: return GetCountAndDistanceOfClosestInstance(this->ro, parameter, this->ro.grffile->grfid, this->tile, this->obj); case 0x7A: return GetBadgeVariableResult(*this->ro.grffile, this->spec->badges, parameter); } diff --git a/src/newgrf_roadstop.cpp b/src/newgrf_roadstop.cpp index 057c43ae3e..0bdee27277 100644 --- a/src/newgrf_roadstop.cpp +++ b/src/newgrf_roadstop.cpp @@ -303,7 +303,7 @@ void DrawRoadStopTile(int x, int y, RoadType roadtype, const RoadStopSpec *spec, RoadStopDrawModes draw_mode; if (spec->flags.Test(RoadStopSpecFlag::DrawModeRegister)) { - draw_mode = static_cast(GetRegister(0x100)); + draw_mode = static_cast(object.GetRegister(0x100)); } else { draw_mode = spec->draw_mode; } diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 63347e84c8..05c5b0f168 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -64,7 +64,7 @@ static inline uint32_t GetVariable(const ResolverObject &object, ScopeResolver * case 0x5F: return (scope->GetRandomBits() << 8) | scope->GetRandomTriggers(); - case 0x7D: return _temp_store.GetValue(parameter); + case 0x7D: return object.GetRegister(parameter); case 0x7F: if (object.grffile == nullptr) return 0; @@ -140,7 +140,7 @@ static inline uint32_t GetVariable(const ResolverObject &object, ScopeResolver * /* Evaluate an adjustment for a variable of the given size. * U is the unsigned type and S is the signed type to use. */ template -static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver *scope, U last_value, uint32_t value) +static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ResolverObject &object, ScopeResolver *scope, U last_value, uint32_t value) { value >>= adjust.shift_num; value &= adjust.and_mask; @@ -166,7 +166,7 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver 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_STO: object.SetRegister((U)value, (S)last_value); return last_value; case DSGA_OP_RST: return value; case DSGA_OP_STOP: scope->StorePSA((U)value, (S)last_value); return last_value; case DSGA_OP_ROR: return std::rotr((U)last_value, (U)value & 0x1F); // mask 'value' to 5 bits, which should behave the same on all architectures. @@ -214,9 +214,9 @@ static bool RangeHighComparator(const DeterministicSpriteGroupRange &range, uint } switch (this->size) { - case DSG_SIZE_BYTE: value = EvalAdjustT (adjust, scope, last_value, value); break; - case DSG_SIZE_WORD: value = EvalAdjustT(adjust, scope, last_value, value); break; - case DSG_SIZE_DWORD: value = EvalAdjustT(adjust, scope, last_value, value); break; + case DSG_SIZE_BYTE: value = EvalAdjustT (adjust, object, scope, last_value, value); break; + case DSG_SIZE_WORD: value = EvalAdjustT(adjust, object, scope, last_value, value); break; + case DSG_SIZE_DWORD: value = EvalAdjustT(adjust, object, scope, last_value, value); break; default: NOT_REACHED(); } last_value = value; diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index ae736aa2db..b0d1ef1136 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -327,6 +327,30 @@ struct ResolverObject { ScopeResolver default_scope; ///< Default implementation of the grf scope. + /** + * Gets the value of a so-called newgrf "register". + * @param i index of the register + * @return the value of the register + * @pre i < 0x110 + */ + inline int32_t GetRegister(uint i) const + { + extern TemporaryStorageArray _temp_store; + return _temp_store.GetValue(i); + } + + /** + * Sets the value of a so-called newgrf "register". + * @param i index of the register + * @param value the value of the register + * @pre i < 0x110 + */ + inline void SetRegister(uint i, int32_t value) + { + extern TemporaryStorageArray _temp_store; + _temp_store.StoreValue(i, value); + } + CallbackID callback{}; ///< Callback being resolved. uint32_t callback_param1 = 0; ///< First parameter (var 10) of the callback. uint32_t callback_param2 = 0; ///< Second parameter (var 18) of the callback. diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index bdae414ab3..0a27ba428a 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -655,7 +655,7 @@ SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseS const auto *group = object.Resolve(); /* Note: SpriteGroup::Resolve zeroes all registers, so register 0x100 is initialised to 0. (compatibility) */ - uint32_t offset = static_cast(GetRegister(0x100)); + uint32_t offset = static_cast(object.GetRegister(0x100)); if (group == nullptr || group->num_sprites <= offset) return 0; return group->sprite + offset; diff --git a/src/newgrf_town.cpp b/src/newgrf_town.cpp index eb0dc8a597..64ed6a800e 100644 --- a/src/newgrf_town.cpp +++ b/src/newgrf_town.cpp @@ -36,7 +36,7 @@ /* Get a variable from the persistent storage */ case 0x7C: { /* Check the persistent storage for the GrfID stored in register 100h. */ - uint32_t grfid = static_cast(GetRegister(0x100)); + uint32_t grfid = static_cast(this->ro.GetRegister(0x100)); if (grfid == 0xFFFFFFFF) { if (this->ro.grffile == nullptr) return 0; grfid = this->ro.grffile->grfid; @@ -132,7 +132,7 @@ if (this->ro.grffile == nullptr) return; /* Check the persistent storage for the GrfID stored in register 100h. */ - uint32_t grfid = static_cast(GetRegister(0x100)); + uint32_t grfid = static_cast(this->ro.GetRegister(0x100)); /* A NewGRF can only write in the persistent storage associated to its own GRFID. */ if (grfid == 0xFFFFFFFF) grfid = this->ro.grffile->grfid;