Add several NewGRF variables to vehicle image callback whitelist

Add vehicle flags to control cached image invalidation

Various refactorings
pull/185/head
Jonathan G Rennison 4 years ago
parent c82d372d54
commit 810bfd276e

@ -235,6 +235,7 @@ add_files(
newgrf_airporttiles.h
newgrf_animation_base.h
newgrf_animation_type.h
newgrf_cache_check.h
newgrf_callbacks.h
newgrf_canal.cpp
newgrf_canal.h

@ -67,6 +67,7 @@ int GetAircraftFlightLevel(T *v, bool takeoff = false);
struct AircraftCache {
uint32 cached_max_range_sqr; ///< Cached squared maximum range.
uint16 cached_max_range; ///< Cached maximum range.
byte image_movement_state; ///< Cached image aircraft movement state
};
/**

@ -1276,6 +1276,7 @@ static void HandleAircraftSmoke(Aircraft *v, bool mode)
if (v->state != FLYING && v->state != LANDING && v->breakdown_type == BREAKDOWN_AIRCRAFT_SPEED) {
v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
v->breakdown_ctr = 0;
v->InvalidateImageCacheOfChain();
return;
}
@ -1334,7 +1335,7 @@ TileIndex Aircraft::GetOrderStationLocation(StationID station)
void Aircraft::MarkDirty()
{
this->colourmap = PAL_NONE;
this->cur_image_valid_dir = INVALID_DIR;
this->InvalidateImageCache();
this->UpdateViewport(true, false);
if (this->subtype == AIR_HELICOPTER) {
Aircraft *rotor = this->Next()->Next();
@ -2161,6 +2162,15 @@ bool Aircraft::Tick()
if (!AircraftEventHandler(this, i)) return false;
}
if (HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE)) {
extern byte MapAircraftMovementState(const Aircraft *v);
byte state = MapAircraftMovementState(this);
if (state != this->acache.image_movement_state) {
this->InvalidateImageCacheOfChain();
this->acache.image_movement_state = state;
}
}
return true;
}

@ -1045,7 +1045,10 @@ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1,
/* Company colour data is indirectly cached. */
for (Vehicle *v : Vehicle::Iterate()) {
if (v->owner == _current_company) v->InvalidateNewGRFCache();
if (v->owner == _current_company) {
v->InvalidateNewGRFCache();
v->InvalidateImageCache();
}
}
extern void UpdateObjectColours(const Company *c);

@ -204,7 +204,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z)
this->z_pos = z;
this->tile = TileVirtXY(x, y);
this->cur_image_valid_dir = INVALID_DIR;
this->InvalidateImageCache();
this->UpdateImage();
this->UpdatePositionAndViewport();
@ -218,7 +218,7 @@ void DisasterVehicle::UpdatePosition(int x, int y, int z)
safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
u->z_pos = GetSlopePixelZ(safe_x, safe_y);
u->direction = this->direction;
u->cur_image_valid_dir = INVALID_DIR;
u->InvalidateImageCache();
u->UpdateImage();
u->UpdatePositionAndViewport();

@ -466,6 +466,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
/* Owner changes, clear cache */
v->colourmap = PAL_NONE;
v->InvalidateNewGRFCache();
v->InvalidateImageCache();
if (v->IsEngineCountable()) {
GroupStatistics::CountEngine(v, 1);

@ -108,7 +108,7 @@ void GroundVehicle<T, Type>::CargoChanged()
weight += current_weight;
/* Slope steepness is in percent, result in N. */
u->gcache.cached_slope_resistance = current_weight * u->GetSlopeSteepness() * 100;
u->cur_image_valid_dir = INVALID_DIR;
u->InvalidateImageCache();
}
ClrBit(this->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST);

@ -398,6 +398,9 @@ struct GroundVehicle : public SpecializedVehicle<T, Type> {
if (this->cur_speed != this->gcache.last_speed) {
SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
this->gcache.last_speed = this->cur_speed;
if (HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE)) {
this->InvalidateImageCacheOfChain();
}
}
}

@ -278,6 +278,7 @@ void PropagateChildLivery(const Group *g)
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
u->InvalidateImageCache();
}
}
}
@ -544,6 +545,7 @@ static void AddVehicleToGroup(Vehicle *v, GroupID new_g)
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
u->InvalidateImageCache();
u->UpdateViewport(true);
}
break;
@ -794,6 +796,7 @@ void SetTrainGroupID(Train *v, GroupID new_g)
u->group_id = new_g;
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
u->InvalidateImageCache();
u->UpdateViewport(true);
}
@ -821,6 +824,7 @@ void UpdateTrainGroupID(Train *v)
u->group_id = new_g;
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
u->InvalidateImageCache();
}
/* Update the Replace Vehicle Windows */

@ -6354,6 +6354,19 @@ static void SkipAct5(ByteReader *buf)
*/
bool GetGlobalVariable(byte param, uint32 *value, const GRFFile *grffile)
{
if (_sprite_group_resolve_check_veh_check) {
switch (param) {
case 0x00:
case 0x02:
case 0x09:
case 0x0A:
case 0x20:
case 0x23:
_sprite_group_resolve_check_veh_check = false;
break;
}
}
switch (param) {
case 0x00: // current date
*value = max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0);

@ -38,7 +38,7 @@ struct AirportScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
void StorePSA(uint pos, int32 value) override;
};
@ -197,14 +197,14 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as)
}
}
/* virtual */ uint32 AirportScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 AirportScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
case 0x40: return this->layout;
}
if (this->st == nullptr) {
*available = false;
extra->available = false;
return UINT_MAX;
}
@ -216,7 +216,7 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as)
case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
}
return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
return this->st->GetNewGRFVariable(this->ro, variable, parameter, &(extra->available));
}
/* virtual */ const SpriteGroup *AirportResolverObject::ResolveReal(const RealSpriteGroup *group) const

@ -158,7 +158,7 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32
return 0xFF << 8 | ats->grf_prop.subst_id; // so just give him the substitute
}
/* virtual */ uint32 AirportTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 AirportTileScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
assert(this->st != nullptr);
@ -195,7 +195,7 @@ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32
DEBUG(grf, 1, "Unhandled airport tile variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -38,7 +38,7 @@ struct AirportTileScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
};
/** Resolver for tiles of an airport. */

@ -0,0 +1,15 @@
/*
* 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_cache_check.h NewGRF caching checks. */
#ifndef NEWGRF_CACHE_CHECK_H
#define NEWGRF_CACHE_CHECK_H
extern bool _sprite_group_resolve_check_veh_check;
#endif /* NEWGRF_CACHE_CHECK_H */

@ -30,7 +30,7 @@ struct CanalScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
};
/** Resolver object for canals. */
@ -61,7 +61,7 @@ struct CanalResolverObject : public ResolverObject {
return IsTileType(this->tile, MP_WATER) ? GetWaterTileRandomBits(this->tile) : 0;
}
/* virtual */ uint32 CanalScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 CanalScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
/* Height of tile */
@ -104,7 +104,7 @@ struct CanalResolverObject : public ResolverObject {
DEBUG(grf, 1, "Unhandled canal variable 0x%02X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -167,7 +167,7 @@ public:
* @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 = 0;
virtual uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const = 0;
/**
* Used to decide if the PSA needs a parameter or not.
@ -492,11 +492,11 @@ struct NewGRFInspectWindow : Window {
if (nif->variables != nullptr) {
this->DrawString(r, i++, "Variables:");
for (const NIVariable *niv = nif->variables; niv->name != nullptr; niv++) {
bool avail = true;
GetVariableExtra extra;
uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
uint value = nih->Resolve(index, niv->var, param, &avail);
uint value = nih->Resolve(index, niv->var, param, &extra);
if (!avail) continue;
if (!extra.available) continue;
if (HasVariableParameter(niv->var)) {
this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name);

@ -22,10 +22,13 @@
#include "company_base.h"
#include "newgrf_railtype.h"
#include "newgrf_roadtype.h"
#include "newgrf_cache_check.h"
#include "ship.h"
#include "safeguards.h"
bool _sprite_group_resolve_check_veh_check = false;
struct WagonOverride {
EngineID *train_id;
uint trains;
@ -162,7 +165,7 @@ enum TTDPAircraftMovementStates {
* Map OTTD aircraft movement states to TTDPatch style movement states
* (VarAction 2 Variable 0xE2)
*/
static byte MapAircraftMovementState(const Aircraft *v)
byte MapAircraftMovementState(const Aircraft *v)
{
const Station *st = GetTargetAirportIfValid(v);
if (st == nullptr) return AMS_TTDP_FLIGHT_TO_TOWER;
@ -343,6 +346,14 @@ static byte MapAircraftMovementAction(const Aircraft *v)
/* virtual */ uint32 VehicleScopeResolver::GetTriggers() const
{
if (this->v == nullptr) {
return 0;
} else {
if (_sprite_group_resolve_check_veh_check) {
SetBit(const_cast<Vehicle*>(this->v->First())->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER);
}
return this->v->waiting_triggers;
}
return this->v == nullptr ? 0 : this->v->waiting_triggers;
}
@ -444,8 +455,118 @@ static uint32 PositionHelper(const Vehicle *v, bool consecutive)
return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16;
}
static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, byte variable, uint32 parameter, bool *available)
static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, byte variable, uint32 parameter, GetVariableExtra *extra)
{
if (_sprite_group_resolve_check_veh_check) {
switch (variable) {
case 0xC:
case 0x10:
case 0x18:
case 0x1A:
case 0x1C:
case 0x25:
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x47:
case 0x48:
case 0x49:
case 0x4A:
case 0x4B:
case 0x4D:
case 0x60:
case 0x61:
case 0x7D:
case 0x7F:
case 0x80 + 0x0:
case 0x80 + 0x1:
case 0x80 + 0x4:
case 0x80 + 0x5:
case 0x80 + 0xA: // dubious
case 0x80 + 0xB: // dubious
case 0x80 + 0x39:
case 0x80 + 0x3A:
case 0x80 + 0x3B:
case 0x80 + 0x3C:
case 0x80 + 0x3D:
case 0x80 + 0x44:
case 0x80 + 0x45:
case 0x80 + 0x46:
case 0x80 + 0x47:
case 0x80 + 0x5A:
case 0x80 + 0x72:
case 0x80 + 0x7A:
case 0xFF:
break;
case 0x80 + 0x32:
if (extra->mask & (VS_HIDDEN | VS_TRAIN_SLOWING)) {
_sprite_group_resolve_check_veh_check = false;
}
break;
case 0x80 + 0x34:
case 0x80 + 0x35:
if (v->type == VEH_AIRCRAFT) {
_sprite_group_resolve_check_veh_check = false;
} else {
SetBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE);
}
break;
case 0x5F:
case 0x80 + 0x7B:
SetBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER);
break;
case 0x80 + 0x48:
// VRF_REVERSE_DIRECTION
if (v->type != VEH_TRAIN) {
_sprite_group_resolve_check_veh_check = false;
}
break;
case 0x80 + 0x62:
switch (v->type) {
case VEH_TRAIN:
case VEH_SHIP:
if (extra->mask & 0x7F) {
_sprite_group_resolve_check_veh_check = false;
}
break;
case VEH_ROAD:
break;
case VEH_AIRCRAFT:
if (v == v->First()) {
SetBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE);
} else {
_sprite_group_resolve_check_veh_check = false;
}
break;
default:
_sprite_group_resolve_check_veh_check = false;
break;
}
break;
case 0xFE:
// vehicle is unloading, VF_CARGO_UNLOADING may disappear without the vehicle being marked dirty
// the vehicle is always marked dirty when VF_CARGO_UNLOADING is set
if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING)) {
_sprite_group_resolve_check_veh_check = false;
}
break;
default:
_sprite_group_resolve_check_veh_check = false;
break;
}
}
/* Calculated vehicle parameters */
switch (variable) {
case 0x25: // Get engine GRF ID
@ -667,9 +788,12 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
if (parameter == 0x5F) {
/* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */
if (_sprite_group_resolve_check_veh_check) {
SetBit(u->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER);
}
return (u->random_bits << 8) | u->waiting_triggers;
} else {
return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available);
return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), extra);
}
}
/* Not available */
@ -891,11 +1015,11 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
DEBUG(grf, 1, "Unhandled vehicle variable 0x%X, type 0x%X", variable, (uint)v->type);
*available = false;
extra->available = false;
return UINT_MAX;
}
/* virtual */ uint32 VehicleScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 VehicleScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->v == nullptr) {
/* Vehicle does not exist, so we're in a purchase list */
@ -922,11 +1046,11 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object,
case 0xF2: return 0; // Cargo subtype
}
*available = false;
extra->available = false;
return UINT_MAX;
}
return VehicleGetVariable(const_cast<Vehicle*>(this->v), this, variable, parameter, available);
return VehicleGetVariable(const_cast<Vehicle*>(this->v), this, variable, parameter, extra);
}
@ -1206,6 +1330,9 @@ void TriggerVehicle(Vehicle *v, VehicleTrigger trigger)
v->InvalidateNewGRFCacheOfChain();
DoTriggerVehicle(v, trigger, 0, true);
if (HasBit(v->First()->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER)) {
v->First()->InvalidateImageCacheOfChain();
}
v->InvalidateNewGRFCacheOfChain();
}
@ -1325,8 +1452,8 @@ void FillNewGRFVehicleCache(const Vehicle *v)
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.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entries[i][0], 0, &stub);
GetVariableExtra extra;
ro.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entries[i][0], 0, &extra);
}
/* Make sure really all bits are set. */

@ -39,7 +39,7 @@ struct VehicleScopeResolver : public ScopeResolver {
void SetVehicle(const Vehicle *v) { this->v = v; }
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
uint32 GetTriggers() const override;
};

@ -42,7 +42,7 @@ struct GenericScopeResolver : public ScopeResolver {
{
}
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
private:
bool ai_callback; ///< Callback comes from the AI.
@ -121,7 +121,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g
_gcl[feature].push_front(GenericCallback(file, group));
}
/* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->ai_callback) {
switch (variable) {
@ -143,7 +143,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g
DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -322,7 +322,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
/**
* @note Used by the resolver to get values for feature 07 deterministic spritegroups.
*/
/* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
/* Construction stage. */
@ -438,7 +438,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}
@ -446,7 +446,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
/**
* @note Used by the resolver to get values for feature 07 deterministic spritegroups.
*/
/* virtual */ uint32 FakeHouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 FakeHouseScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
/* Construction stage. */
@ -500,7 +500,7 @@ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseI
DEBUG(grf, 1, "Unhandled house variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -50,7 +50,7 @@ struct HouseScopeResolver : public CommonHouseScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
uint32 GetTriggers() const override;
};
@ -70,7 +70,7 @@ struct FakeHouseScopeResolver : public CommonHouseScopeResolver {
: CommonHouseScopeResolver(ro, house_id)
{ }
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const;
};
/** Resolver object to be used for houses (feature 07 spritegroups). */

@ -155,7 +155,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
return count << 16 | GB(closest_dist, 0, 16);
}
/* virtual */ uint32 IndustriesScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 IndustriesScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->ro.callback == CBID_INDUSTRY_LOCATION) {
/* Variables available during construction check. */
@ -201,7 +201,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
if (this->industry == nullptr) {
DEBUG(grf, 1, "Unhandled variable 0x%X (no available industry) in callback 0x%x", variable, this->ro.callback);
*available = false;
extra->available = false;
return UINT_MAX;
}
@ -401,7 +401,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
DEBUG(grf, 1, "Unhandled industry variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -33,7 +33,7 @@ struct IndustriesScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
uint32 GetTriggers() const override;
void StorePSA(uint pos, int32 value) override;
};

@ -58,7 +58,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile)
return ((y & 0xF) << 20) | ((x & 0xF) << 16) | (y << 8) | x;
}
/* virtual */ uint32 IndustryTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 IndustryTileScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
/* Construction state of the tile: a value between 0 and 3 */
@ -95,7 +95,7 @@ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile)
DEBUG(grf, 1, "Unhandled industry tile variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -31,7 +31,7 @@ struct IndustryTileScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
uint32 GetTriggers() const override;
};

@ -230,7 +230,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid,
}
/** Used by the resolver to get values for feature 0F deterministic spritegroups. */
/* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
/* We get the town from the object, or we calculate the closest
* town if we need to when there's no object. */
@ -337,7 +337,7 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid,
unhandled:
DEBUG(grf, 1, "Unhandled object variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -116,7 +116,7 @@ struct ObjectScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
};
/** A resolver object to be used with feature 0F spritegroups. */

@ -22,7 +22,7 @@
return GB(tmp, 0, 2);
}
/* virtual */ uint32 RailTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 RailTypeScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->tile == INVALID_TILE) {
switch (variable) {
@ -54,7 +54,7 @@
DEBUG(grf, 1, "Unhandled rail type tile variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -32,7 +32,7 @@ struct RailTypeScopeResolver : public ScopeResolver {
}
uint32 GetRandomBits() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
};
/** Resolver object for rail types. */

@ -22,7 +22,7 @@
return GB(tmp, 0, 2);
}
/* virtual */ uint32 RoadTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 RoadTypeScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->tile == INVALID_TILE) {
switch (variable) {
@ -54,7 +54,7 @@
DEBUG(grf, 1, "Unhandled road type tile variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -23,7 +23,7 @@ struct RoadTypeScopeResolver : public ScopeResolver {
RoadTypeScopeResolver(ResolverObject &ro, const RoadTypeInfo *rti, TileIndex tile, TileContext context);
/* virtual */ uint32 GetRandomBits() const;
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
/* virtual */ uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const;
};
/** Resolver object for road types. */

@ -14,6 +14,8 @@
#include "newgrf_profiling.h"
#include "core/pool_func.hpp"
#include "vehicle_type.h"
#include "newgrf_cache_check.h"
#include "scope_info.h"
#include "safeguards.h"
@ -72,7 +74,7 @@ RandomizedSpriteGroup::~RandomizedSpriteGroup()
free(this->groups);
}
static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *scope, byte variable, uint32 parameter, bool *available)
static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *scope, byte variable, uint32 parameter, GetVariableExtra *extra)
{
uint32 value;
switch (variable) {
@ -93,7 +95,7 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc
/* First handle variables common with Action7/9/D */
if (variable < 0x40 && GetGlobalVariable(variable, &value, object.grffile)) return value;
/* Not a common variable, so evaluate the feature specific variables */
return scope->GetVariable(variable, parameter, available);
return scope->GetVariable(variable, parameter, extra);
}
}
@ -122,10 +124,10 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc
* @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
/* virtual */ uint32 ScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
DEBUG(grf, 1, "Unhandled scope variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}
@ -199,9 +201,6 @@ static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ScopeResolver
}
}
bool _sprite_group_resolve_check_veh_check = false;
VehicleType _sprite_group_resolve_check_veh_type;
static bool RangeHighComparator(const DeterministicSpriteGroupRange& range, uint32 value)
{
return range.high < value;
@ -219,9 +218,8 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
DeterministicSpriteGroupAdjust *adjust = &this->adjusts[i];
/* Try to get the variable. We shall assume it is available, unless told otherwise. */
bool available = true;
GetVariableExtra extra(adjust->and_mask << adjust->shift_num);
if (adjust->variable == 0x7E) {
_sprite_group_resolve_check_veh_check = false;
const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object, false);
if (subgroup == nullptr) {
value = CALLBACK_FAILED;
@ -232,59 +230,12 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con
/* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */
} else if (adjust->variable == 0x7B) {
_sprite_group_resolve_check_veh_check = false;
value = GetVariable(object, scope, adjust->parameter, last_value, &available);
value = GetVariable(object, scope, adjust->parameter, last_value, &extra);
} else {
if (_sprite_group_resolve_check_veh_check) {
switch (adjust->variable) {
// whitelist of variables which can be checked without requiring an immediate re-check on the next tick
case 0xC:
case 0x1A:
case 0x1C:
case 0x25:
case 0x40:
case 0x41:
case 0x42:
case 0x47:
case 0x49:
case 0x4B:
case 0x4D:
case 0x60:
case 0x7D:
case 0x7F:
case 0x80 + 0x0:
case 0x80 + 0x1:
case 0x80 + 0x4:
case 0x80 + 0x5:
case 0x80 + 0x39:
case 0x80 + 0x3A:
case 0x80 + 0x3B:
case 0x80 + 0x3C:
case 0x80 + 0x3D:
case 0x80 + 0x44:
case 0x80 + 0x45:
case 0x80 + 0x46:
case 0x80 + 0x47:
case 0x80 + 0x5A:
case 0x80 + 0x72:
case 0x80 + 0x7A:
break;
case 0x80 + 0x62:
// RoadVehicle::state
if (_sprite_group_resolve_check_veh_type != VEH_ROAD) {
_sprite_group_resolve_check_veh_check = false;
}
break;
default:
_sprite_group_resolve_check_veh_check = false;
break;
}
}
value = GetVariable(object, scope, adjust->variable, adjust->parameter, &available);
value = GetVariable(object, scope, adjust->variable, adjust->parameter, &extra);
}
if (!available) {
if (!extra.available) {
/* Unsupported variable: skip further processing and return either
* the group from the first range or the default group. */
return SpriteGroup::Resolve(this->error_group, object, false);

@ -287,6 +287,14 @@ struct IndustryProductionSpriteGroup : SpriteGroup {
};
struct GetVariableExtra {
bool available;
uint32 mask;
GetVariableExtra(uint32 mask_ = 0xFFFFFFFF)
: available(true), mask(mask_) {}
};
/**
* Interface to query and set values specific to a single #VarSpriteGroupScope (action 2 scope).
*
@ -302,7 +310,7 @@ struct ScopeResolver {
virtual uint32 GetRandomBits() const;
virtual uint32 GetTriggers() const;
virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
virtual uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const;
virtual void StorePSA(uint reg, int32 value);
};

@ -268,7 +268,7 @@ TownScopeResolver *StationResolverObject::GetTown()
return this->town_scope;
}
/* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
if (this->st == nullptr) {
/* Station does not exist, so we're in a purchase list or the land slope check callback. */
@ -296,7 +296,7 @@ TownScopeResolver *StationResolverObject::GetTown()
case 0xFA: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Build date, clamped to a 16 bit value
}
*available = false;
extra->available = false;
return UINT_MAX;
}
@ -386,7 +386,7 @@ TownScopeResolver *StationResolverObject::GetTown()
case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
}
return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
return this->st->GetNewGRFVariable(this->ro, variable, parameter, &(extra->available));
}
uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const

@ -45,7 +45,7 @@ struct StationScopeResolver : public ScopeResolver {
uint32 GetRandomBits() const override;
uint32 GetTriggers() const override;
uint32 GetVariable(byte variable, uint32 parameter, bool *available) const override;
uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const override;
};
/** Station resolver. */

@ -14,7 +14,7 @@
#include "safeguards.h"
/* virtual */ uint32 TownScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 TownScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
/* Larger towns */
@ -113,7 +113,7 @@
DEBUG(grf, 1, "Unhandled town variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}
@ -148,7 +148,7 @@
t->psa_list.push_back(psa);
}
/* virtual */ uint32 FakeTownScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const
/* virtual */ uint32 FakeTownScopeResolver::GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const
{
switch (variable) {
/* Town index */
@ -168,7 +168,7 @@
DEBUG(grf, 1, "Unhandled town variable 0x%X", variable);
*available = false;
extra->available = false;
return UINT_MAX;
}

@ -34,7 +34,7 @@ struct TownScopeResolver : public ScopeResolver {
{
}
virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
virtual uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const;
virtual void StorePSA(uint reg, int32 value);
};
@ -53,7 +53,7 @@ struct FakeTownScopeResolver : public ScopeResolver {
FakeTownScopeResolver(ResolverObject &ro) : ScopeResolver(ro)
{ }
virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const;
virtual uint32 GetVariable(byte variable, uint32 parameter, GetVariableExtra *extra) const;
};
/** Resolver of town properties. */

@ -2362,7 +2362,7 @@ static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int
RoadVehicle *rv = RoadVehicle::From(v);
if (rv->frame == RVC_DEPOT_STOP_FRAME &&
_roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) {
rv->cur_image_valid_dir = INVALID_DIR;
rv->InvalidateImageCache();
rv->state = RVSB_IN_DEPOT;
rv->vehstatus |= VS_HIDDEN;
rv->direction = ReverseDir(rv->direction);

@ -415,7 +415,7 @@ void RoadVehicle::MarkDirty()
{
for (RoadVehicle *v = this; v != nullptr; v = v->Next()) {
v->colourmap = PAL_NONE;
v->cur_image_valid_dir = INVALID_DIR;
v->InvalidateImageCache();
v->UpdateViewport(true, false);
}
this->CargoChanged();
@ -1119,7 +1119,7 @@ static bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
}
v->vehstatus &= ~VS_HIDDEN;
v->cur_image_valid_dir = INVALID_DIR;
v->InvalidateImageCache();
v->state = tdir;
v->frame = RVC_DEPOT_START_FRAME;
v->UpdateIsDrawn();
@ -1437,7 +1437,7 @@ again:
}
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
v->cur_image_valid_dir = INVALID_DIR;
v->InvalidateImageCache();
TileIndex old_tile = v->tile;
v->tile = tile;
@ -1513,7 +1513,7 @@ again:
return false;
}
v->cur_image_valid_dir = INVALID_DIR;
v->InvalidateImageCache();
v->state = dir;
v->frame = turn_around_start_frame;

@ -277,7 +277,7 @@ Trackdir Ship::GetVehicleTrackdir() const
void Ship::MarkDirty()
{
this->colourmap = PAL_NONE;
this->cur_image_valid_dir = INVALID_DIR;
this->InvalidateImageCache();
this->UpdateViewport(true, false);
this->UpdateCache();
}

@ -78,11 +78,11 @@ class NIHVehicle : public NIHelper {
void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); }
uint32 GetGRFID(uint index) const override { return Vehicle::Get(index)->GetGRFID(); }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
Vehicle *v = Vehicle::Get(index);
VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
/* virtual */ void ExtraInfo(uint index, std::function<void(const char *)> print) const override
@ -170,6 +170,9 @@ class NIHVehicle : public NIHelper {
e->duration_phase_1 + e->duration_phase_2 + e->duration_phase_3);
print(buffer);
}
seprintf(buffer, lastof(buffer), " Current image cacheable: %s", v->cur_image_valid_dir != INVALID_DIR ? "yes" : "no");
print(buffer);
}
};
@ -229,10 +232,10 @@ class NIHStation : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
StationResolverObject ro(GetStationSpec(index), Station::GetByTile(index), index, INVALID_RAILTYPE);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
};
@ -294,10 +297,10 @@ class NIHHouse : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); }
uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? HouseSpec::Get(GetHouseType(index))->grf_prop.grffile->grfid : 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
HouseResolverObject ro(GetHouseType(index), index, Town::GetByTile(index));
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
void ExtraInfo(uint index, std::function<void(const char *)> print) const override
@ -359,10 +362,10 @@ class NIHIndustryTile : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); }
uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile->grfid : 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
IndustryTileResolverObject ro(GetIndustryGfx(index), index, Industry::GetByTile(index));
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
};
@ -458,11 +461,11 @@ class NIHIndustry : public NIHelper {
void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); }
uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile->grfid : 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
Industry *i = Industry::Get(index);
IndustriesResolverObject ro(i->location.tile, i, i->type);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); }
@ -546,10 +549,10 @@ class NIHObject : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); }
uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
ObjectResolverObject ro(ObjectSpec::GetByTile(index), Object::GetByTile(index), index);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
};
@ -580,12 +583,12 @@ class NIHRailType : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); }
uint32 GetGRFID(uint index) const override { return 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
/* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype.
* However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */
RailTypeResolverObject ro(nullptr, index, TCX_NORMAL, RTSG_END);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
void ExtraInfo(uint index, std::function<void(const char *)> print) const override
@ -644,10 +647,10 @@ class NIHAirportTile : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); }
uint32 GetGRFID(uint index) const override { return (this->IsInspectable(index)) ? AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile->grfid : 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
AirportTileResolverObject ro(AirportTileSpec::GetByTile(index), index, Station::GetByTile(index));
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
};
@ -684,10 +687,10 @@ class NIHTown : public NIHelper {
bool PSAWithParameter() const override { return true; }
uint GetPSASize(uint index, uint32 grfid) const override { return cpp_lengthof(PersistentStorage, storage); }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
TownResolverObject ro(nullptr, Town::Get(index), true);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const override
@ -738,7 +741,7 @@ class NIHStationStruct : public NIHelper {
void SetStringParameters(uint index) const override { this->SetSimpleStringParameters(STR_STATION_NAME, index); }
uint32 GetGRFID(uint index) const override { return 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
return 0;
}
@ -803,12 +806,12 @@ class NIHRoadType : public NIHelper {
void SetStringParameters(uint index) const override { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); }
uint32 GetGRFID(uint index) const override { return 0; }
uint Resolve(uint index, uint var, uint param, bool *avail) const override
uint Resolve(uint index, uint var, uint param, GetVariableExtra *extra) const override
{
/* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype.
* However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */
RoadTypeResolverObject ro(nullptr, index, TCX_NORMAL, ROTSG_END);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail);
return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, extra);
}
};

@ -1832,7 +1832,7 @@ static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2)
*/
static void UpdateStatusAfterSwap(Train *v)
{
v->cur_image_valid_dir = INVALID_DIR;
v->InvalidateImageCache();
/* Reverse the direction. */
if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
@ -3418,7 +3418,7 @@ void Train::MarkDirty()
Train *v = this;
do {
v->colourmap = PAL_NONE;
v->cur_image_valid_dir = INVALID_DIR;
v->InvalidateImageCache();
v->UpdateViewport(true, false);
} while ((v = v->Next()) != nullptr);

@ -2695,7 +2695,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
assert_msg(frame == rv->frame + 1 || rv->frame == _tunnel_turnaround_pre_visibility_frame[dir],
"frame: %u, rv->frame: %u, dir: %u, _tunnel_turnaround_pre_visibility_frame[dir]: %u", frame, rv->frame, dir, _tunnel_turnaround_pre_visibility_frame[dir]);
rv->tile = tile;
rv->cur_image_valid_dir = INVALID_DIR;
rv->InvalidateImageCache();
rv->state = RVSB_WORMHOLE;
if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(rv->gv_flags, GVF_CHUNNEL_BIT);
rv->vehstatus |= VS_HIDDEN;
@ -2710,7 +2710,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
if (dir == ReverseDiagDir(vdir) && frame == (int) (_tunnel_visibility_frame[dir] - 1) && z == 0) {
if (rv->tile != tile && GetOtherTunnelEnd(rv->tile) != tile) return VETSB_CONTINUE; // In chunnel
rv->tile = tile;
rv->cur_image_valid_dir = INVALID_DIR;
rv->InvalidateImageCache();
rv->state = DiagDirToDiagTrackdir(vdir);
rv->frame = TILE_SIZE - (frame + 1);
rv->vehstatus &= ~VS_HIDDEN;
@ -2753,7 +2753,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
if (HasRoadTypeTram(tile) && HasBit(rv->compatible_roadtypes, GetRoadTypeTram(tile))) bits |= GetCustomBridgeHeadRoadBits(tile, RTT_TRAM);
if (!(bits & DiagDirToRoadBits(GetTunnelBridgeDirection(tile)))) return VETSB_CONTINUE;
}
rv->cur_image_valid_dir = INVALID_DIR;
rv->InvalidateImageCache();
rv->state = RVSB_WORMHOLE;
/* There are no slopes inside bridges / tunnels. */
ClrBit(rv->gv_flags, GVF_GOINGUP_BIT);
@ -2790,7 +2790,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
v->tile = tile;
RoadVehicle *rv = RoadVehicle::From(v);
if (rv->state == RVSB_WORMHOLE) {
rv->cur_image_valid_dir = INVALID_DIR;
rv->InvalidateImageCache();
rv->state = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
rv->frame = 0;
return VETSB_ENTERED_WORMHOLE;

@ -340,6 +340,7 @@ uint Vehicle::Crash(bool flooded)
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount();
v->vehstatus |= VS_CRASHED;
v->MarkAllViewportsDirty();
v->InvalidateImageCache();
}
this->ClearSeparation();
@ -3757,6 +3758,8 @@ char *Vehicle::DumpVehicleFlags(char *b, const char *last, bool include_tile) co
dump('l', HasBit(this->vcache.cached_veh_flags, VCF_LAST_VISUAL_EFFECT));
dump('z', HasBit(this->vcache.cached_veh_flags, VCF_GV_ZERO_SLOPE_RESIST));
dump('d', HasBit(this->vcache.cached_veh_flags, VCF_IS_DRAWN));
dump('t', HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER));
dump('s', HasBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE));
if (this->IsGroundVehicle()) {
uint16 gv_flags = this->GetGroundVehicleFlags();
b += seprintf(b, last, ", gvf:");

@ -22,6 +22,7 @@
#include "group_type.h"
#include "timetable.h"
#include "base_consist.h"
#include "newgrf_cache_check.h"
#include "network/network.h"
#include <list>
#include <map>
@ -137,6 +138,8 @@ enum VehicleCacheFlags {
VCF_LAST_VISUAL_EFFECT = 0, ///< Last vehicle in the consist with a visual effect.
VCF_GV_ZERO_SLOPE_RESIST = 1, ///< GroundVehicle: Consist has zero slope resistance (valid only for the first engine), may be false negative.
VCF_IS_DRAWN = 2, ///< Vehicle is currently drawn
VCF_REDRAW_ON_TRIGGER = 3, ///< Clear cur_image_valid_dir on changes to waiting_triggers (valid only for the first engine)
VCF_REDRAW_ON_SPEED_CHANGE = 4, ///< Clear cur_image_valid_dir on changes to cur_speed (ground vehicles) or aircraft movement state (aircraft) (valid only for the first engine)
};
/** Cached often queried values common to all vehicles. */
@ -502,6 +505,28 @@ public:
}
}
/**
* Invalidates cached image
* @see InvalidateNewGRFCacheOfChain
*/
inline void InvalidateImageCache()
{
this->cur_image_valid_dir = INVALID_DIR;
}
/**
* Invalidates cached image of all vehicles in the chain (after the current vehicle)
* @see InvalidateImageCache
*/
inline void InvalidateImageCacheOfChain()
{
ClrBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_SPEED_CHANGE);
ClrBit(this->vcache.cached_veh_flags, VCF_REDRAW_ON_TRIGGER);
for (Vehicle *u = this; u != nullptr; u = u->Next()) {
u->InvalidateImageCache();
}
}
/**
* Check if the vehicle is a ground vehicle.
* @return True iff the vehicle is a train or a road vehicle.
@ -1242,16 +1267,12 @@ struct SpecializedVehicle : public Vehicle {
/* Skip updating sprites on dedicated servers without screen */
if (_network_dedicated) return;
extern bool _sprite_group_resolve_check_veh_check;
extern VehicleType _sprite_group_resolve_check_veh_type;
/* Explicitly choose method to call to prevent vtable dereference -
* it gives ~3% runtime improvements in games with many vehicles */
if (update_delta) ((T *)this)->T::UpdateDeltaXY();
const Direction current_direction = ((T *)this)->GetMapImageDirection();
if (this->cur_image_valid_dir != current_direction) {
_sprite_group_resolve_check_veh_check = true;
_sprite_group_resolve_check_veh_type = EXPECTED_TYPE;
VehicleSpriteSeq seq;
((T *)this)->T::GetImage(current_direction, EIT_ON_MAP, &seq);
this->cur_image_valid_dir = _sprite_group_resolve_check_veh_check ? current_direction : INVALID_DIR;

Loading…
Cancel
Save