Changeset - r24570:4fa1d23595bf
[Not reviewed]
master
0 11 0
Matt Kimber - 4 years ago 2021-01-03 13:32:58
github@mattkimber.org.uk
Codechange: create MutableSpriteCache to remove the need to cast Vehicle to a mutable type in render methods
11 files changed with 74 insertions and 77 deletions:
0 comments (0 inline, 0 general)
src/aircraft_cmd.cpp
Show inline comments
 
@@ -332,26 +332,26 @@ CommandCost CmdBuildAircraft(TileIndex t
 
		v->pos = GetVehiclePosOnBuild(tile);
 

	
 
		v->state = HANGAR;
 
		v->previous_pos = v->pos;
 
		v->targetairport = GetStationIndex(tile);
 
		v->SetNext(u);
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft);
 

	
 
		v->date_of_last_service = _date;
 
		v->build_year = u->build_year = _cur_year;
 

	
 
		v->sprite_seq.Set(SPR_IMG_QUERY);
 
		u->sprite_seq.Set(SPR_IMG_QUERY);
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 

	
 
		v->random_bits = VehicleRandomBits();
 
		u->random_bits = VehicleRandomBits();
 

	
 
		v->vehicle_flags = 0;
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 
		v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
 

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		v->cargo_cap = e->DetermineCapacity(v, &u->cargo_cap);
 

	
 
@@ -365,25 +365,25 @@ CommandCost CmdBuildAircraft(TileIndex t
 
		/* Aircraft with 3 vehicles (chopper)? */
 
		if (v->subtype == AIR_HELICOPTER) {
 
			Aircraft *w = new Aircraft();
 
			w->engine_type = e->index;
 
			w->direction = DIR_N;
 
			w->owner = _current_company;
 
			w->x_pos = v->x_pos;
 
			w->y_pos = v->y_pos;
 
			w->z_pos = v->z_pos + ROTOR_Z_OFFSET;
 
			w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
 
			w->spritenum = 0xFF;
 
			w->subtype = AIR_ROTOR;
 
			w->sprite_seq.Set(SPR_ROTOR_STOPPED);
 
			w->sprite_cache.sprite_seq.Set(SPR_ROTOR_STOPPED);
 
			w->random_bits = VehicleRandomBits();
 
			/* Use rotor's air.state to store the rotor animation frame */
 
			w->state = HRS_ROTOR_STOPPED;
 
			w->UpdateDeltaXY();
 

	
 
			u->SetNext(w);
 
			w->UpdatePosition();
 
		}
 
	}
 

	
 
	return CommandCost();
 
}
 
@@ -488,68 +488,68 @@ static void HelicopterTickHandler(Aircra
 
		if (u->cur_speed >= 0x50) {
 
			u->cur_speed--;
 
		}
 
	}
 

	
 
	int tick = ++u->tick_counter;
 
	int spd = u->cur_speed >> 4;
 

	
 
	VehicleSpriteSeq seq;
 
	if (spd == 0) {
 
		u->state = HRS_ROTOR_STOPPED;
 
		GetRotorImage(v, EIT_ON_MAP, &seq);
 
		if (u->sprite_seq == seq) return;
 
		if (u->sprite_cache.sprite_seq == seq) return;
 
	} else if (tick >= spd) {
 
		u->tick_counter = 0;
 
		u->state++;
 
		if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1;
 
		GetRotorImage(v, EIT_ON_MAP, &seq);
 
	} else {
 
		return;
 
	}
 

	
 
	u->sprite_seq = seq;
 
	u->sprite_cache.sprite_seq = seq;
 

	
 
	u->UpdatePositionAndViewport();
 
}
 

	
 
/**
 
 * Set aircraft position.
 
 * @param v Aircraft to position.
 
 * @param x New X position.
 
 * @param y New y position.
 
 * @param z New z position.
 
 */
 
void SetAircraftPosition(Aircraft *v, int x, int y, int z)
 
{
 
	v->x_pos = x;
 
	v->y_pos = y;
 
	v->z_pos = z;
 

	
 
	v->UpdatePosition();
 
	v->UpdateViewport(true, false);
 
	if (v->subtype == AIR_HELICOPTER) {
 
		GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_seq);
 
		GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_cache.sprite_seq);
 
	}
 

	
 
	Aircraft *u = v->Next();
 

	
 
	int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE);
 
	int safe_y = Clamp(y - 1, 0, MapMaxY() * TILE_SIZE);
 
	u->x_pos = x;
 
	u->y_pos = y - ((v->z_pos - GetSlopePixelZ(safe_x, safe_y)) >> 3);
 

	
 
	safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
 
	u->z_pos = GetSlopePixelZ(safe_x, safe_y);
 
	u->sprite_seq.CopyWithoutPalette(v->sprite_seq); // the shadow is never coloured
 
	u->sprite_cache.sprite_seq.CopyWithoutPalette(v->sprite_cache.sprite_seq); // the shadow is never coloured
 

	
 
	u->UpdatePositionAndViewport();
 

	
 
	u = u->Next();
 
	if (u != nullptr) {
 
		u->x_pos = x;
 
		u->y_pos = y;
 
		u->z_pos = z + ROTOR_Z_OFFSET;
 

	
 
		u->UpdatePositionAndViewport();
 
	}
 
}
 
@@ -1269,25 +1269,25 @@ TileIndex Aircraft::GetOrderStationLocat
 
		AircraftNextAirportPos_and_Order(this);
 
	}
 

	
 
	/* Aircraft do not use dest-tile */
 
	return 0;
 
}
 

	
 
void Aircraft::MarkDirty()
 
{
 
	this->colourmap = PAL_NONE;
 
	this->UpdateViewport(true, false);
 
	if (this->subtype == AIR_HELICOPTER) {
 
		GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_seq);
 
		GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_cache.sprite_seq);
 
	}
 
}
 

	
 

	
 
uint Aircraft::Crash(bool flooded)
 
{
 
	uint pass = Vehicle::Crash(flooded) + 2; // pilots
 
	this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded
 

	
 
	return pass;
 
}
 

	
src/articulated_vehicles.cpp
Show inline comments
 
@@ -430,20 +430,20 @@ void AddArticulatedParts(Vehicle *first)
 
		v->tile = first->tile;
 
		v->x_pos = first->x_pos;
 
		v->y_pos = first->y_pos;
 
		v->z_pos = first->z_pos;
 
		v->date_of_last_service = first->date_of_last_service;
 
		v->build_year = first->build_year;
 
		v->vehstatus = first->vehstatus & ~VS_STOPPED;
 

	
 
		v->cargo_subtype = 0;
 
		v->max_age = 0;
 
		v->engine_type = engine_type;
 
		v->value = 0;
 
		v->sprite_seq.Set(SPR_IMG_QUERY);
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = VehicleRandomBits();
 

	
 
		if (flip_image) v->spritenum++;
 

	
 
		v->UpdatePosition();
 
	}
 
}
src/disaster_vehicle.cpp
Show inline comments
 
@@ -101,25 +101,25 @@ static const SpriteID * const _disaster_
 
	_disaster_images_2, _disaster_images_2,                     ///< small ufo and small ufo shadow
 
	_disaster_images_3, _disaster_images_3,                     ///< combat aircraft and shadow
 
	_disaster_images_8, _disaster_images_8, _disaster_images_9, ///< combat helicopter, shadow and rotor
 
	_disaster_images_6, _disaster_images_6,                     ///< big ufo and shadow
 
	_disaster_images_7, _disaster_images_7,                     ///< skyranger and shadow
 
	_disaster_images_4, _disaster_images_5,                     ///< small and big submarine sprites
 
};
 

	
 
void DisasterVehicle::UpdateImage()
 
{
 
	SpriteID img = this->image_override;
 
	if (img == 0) img = _disaster_images[this->subtype][this->direction];
 
	this->sprite_seq.Set(img);
 
	this->sprite_cache.sprite_seq.Set(img);
 
}
 

	
 
/**
 
 * Construct the disaster vehicle.
 
 * @param x         The X coordinate.
 
 * @param y         The Y coordinate.
 
 * @param direction The direction the vehicle is facing.
 
 * @param subtype   The sub type of vehicle.
 
 * @param big_ufo_destroyer_target The target for the UFO destroyer.
 
 */
 
DisasterVehicle::DisasterVehicle(int x, int y, Direction direction, DisasterSubType subtype, VehicleID big_ufo_destroyer_target) :
 
		SpecializedVehicleBase(), big_ufo_destroyer_target(big_ufo_destroyer_target)
 
@@ -489,25 +489,25 @@ static bool DisasterTick_Airplane(Disast
 
/** Helicopter handling. */
 
static bool DisasterTick_Helicopter(DisasterVehicle *v)
 
{
 
	return DisasterTick_Aircraft(v, SPR_AH_64A_FIRING, false, STR_NEWS_DISASTER_HELICOPTER_FACTORY, INDUSTRYBEH_CHOPPER_ATTACKS);
 
}
 

	
 
/** Helicopter rotor blades; keep these spinning */
 
static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v)
 
{
 
	v->tick_counter++;
 
	if (HasBit(v->tick_counter, 0)) return true;
 

	
 
	SpriteID &cur_image = v->sprite_seq.seq[0].sprite;
 
	SpriteID &cur_image = v->sprite_cache.sprite_seq.seq[0].sprite;
 
	if (++cur_image > SPR_ROTOR_MOVING_3) cur_image = SPR_ROTOR_MOVING_1;
 

	
 
	v->UpdatePositionAndViewport();
 

	
 
	return true;
 
}
 

	
 
/**
 
 * (Big) Ufo handling, v->current_order.dest states:
 
 * 0: Fly around to the middle of the map, then randomly for a while and home in on a piece of rail
 
 * 1: Land there and breakdown all trains in a radius of 12 tiles; and now we wait...
 
 *    because as soon as the Ufo lands, a fighter jet, a Skyranger, is called to clear up the mess
src/effectvehicle.cpp
Show inline comments
 
@@ -19,63 +19,63 @@
 

	
 
#include "safeguards.h"
 

	
 

	
 
/**
 
 * Increment the sprite unless it has reached the end of the animation.
 
 * @param v Vehicle to increment sprite of.
 
 * @param last Last sprite of animation.
 
 * @return true if the sprite was incremented, false if the end was reached.
 
 */
 
static bool IncrementSprite(EffectVehicle *v, SpriteID last)
 
{
 
	if (v->sprite_seq.seq[0].sprite != last) {
 
		v->sprite_seq.seq[0].sprite++;
 
	if (v->sprite_cache.sprite_seq.seq[0].sprite != last) {
 
		v->sprite_cache.sprite_seq.seq[0].sprite++;
 
		return true;
 
	} else {
 
		return false;
 
	}
 
}
 

	
 
static void ChimneySmokeInit(EffectVehicle *v)
 
{
 
	uint32 r = Random();
 
	v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3));
 
	v->sprite_cache.sprite_seq.Set(SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3));
 
	v->progress = GB(r, 16, 3);
 
}
 

	
 
static bool ChimneySmokeTick(EffectVehicle *v)
 
{
 
	if (v->progress > 0) {
 
		v->progress--;
 
	} else {
 
		TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
 
		if (!IsTileType(tile, MP_INDUSTRY)) {
 
			delete v;
 
			return false;
 
		}
 

	
 
		if (!IncrementSprite(v, SPR_CHIMNEY_SMOKE_7)) {
 
			v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0);
 
			v->sprite_cache.sprite_seq.Set(SPR_CHIMNEY_SMOKE_0);
 
		}
 
		v->progress = 7;
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	return true;
 
}
 

	
 
static void SteamSmokeInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_STEAM_SMOKE_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_STEAM_SMOKE_0);
 
	v->progress = 12;
 
}
 

	
 
static bool SteamSmokeTick(EffectVehicle *v)
 
{
 
	bool moved = false;
 

	
 
	v->progress++;
 

	
 
	if ((v->progress & 7) == 0) {
 
		v->z_pos++;
 
		moved = true;
 
@@ -87,72 +87,72 @@ static bool SteamSmokeTick(EffectVehicle
 
			return false;
 
		}
 
		moved = true;
 
	}
 

	
 
	if (moved) v->UpdatePositionAndViewport();
 

	
 
	return true;
 
}
 

	
 
static void DieselSmokeInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_DIESEL_SMOKE_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_DIESEL_SMOKE_0);
 
	v->progress = 0;
 
}
 

	
 
static bool DieselSmokeTick(EffectVehicle *v)
 
{
 
	v->progress++;
 

	
 
	if ((v->progress & 3) == 0) {
 
		v->z_pos++;
 
		v->UpdatePositionAndViewport();
 
	} else if ((v->progress & 7) == 1) {
 
		if (!IncrementSprite(v, SPR_DIESEL_SMOKE_5)) {
 
			delete v;
 
			return false;
 
		}
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	return true;
 
}
 

	
 
static void ElectricSparkInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_ELECTRIC_SPARK_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_ELECTRIC_SPARK_0);
 
	v->progress = 1;
 
}
 

	
 
static bool ElectricSparkTick(EffectVehicle *v)
 
{
 
	if (v->progress < 2) {
 
		v->progress++;
 
	} else {
 
		v->progress = 0;
 

	
 
		if (!IncrementSprite(v, SPR_ELECTRIC_SPARK_5)) {
 
			delete v;
 
			return false;
 
		}
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	return true;
 
}
 

	
 
static void SmokeInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_SMOKE_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_SMOKE_0);
 
	v->progress = 12;
 
}
 

	
 
static bool SmokeTick(EffectVehicle *v)
 
{
 
	bool moved = false;
 

	
 
	v->progress++;
 

	
 
	if ((v->progress & 3) == 0) {
 
		v->z_pos++;
 
		moved = true;
 
@@ -164,90 +164,90 @@ static bool SmokeTick(EffectVehicle *v)
 
			return false;
 
		}
 
		moved = true;
 
	}
 

	
 
	if (moved) v->UpdatePositionAndViewport();
 

	
 
	return true;
 
}
 

	
 
static void ExplosionLargeInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_EXPLOSION_LARGE_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_EXPLOSION_LARGE_0);
 
	v->progress = 0;
 
}
 

	
 
static bool ExplosionLargeTick(EffectVehicle *v)
 
{
 
	v->progress++;
 
	if ((v->progress & 3) == 0) {
 
		if (!IncrementSprite(v, SPR_EXPLOSION_LARGE_F)) {
 
			delete v;
 
			return false;
 
		}
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	return true;
 
}
 

	
 
static void BreakdownSmokeInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
 
	v->progress = 0;
 
}
 

	
 
static bool BreakdownSmokeTick(EffectVehicle *v)
 
{
 
	v->progress++;
 
	if ((v->progress & 7) == 0) {
 
		if (!IncrementSprite(v, SPR_BREAKDOWN_SMOKE_3)) {
 
			v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
 
			v->sprite_cache.sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
 
		}
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	v->animation_state--;
 
	if (v->animation_state == 0) {
 
		delete v;
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
static void ExplosionSmallInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_EXPLOSION_SMALL_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_EXPLOSION_SMALL_0);
 
	v->progress = 0;
 
}
 

	
 
static bool ExplosionSmallTick(EffectVehicle *v)
 
{
 
	v->progress++;
 
	if ((v->progress & 3) == 0) {
 
		if (!IncrementSprite(v, SPR_EXPLOSION_SMALL_B)) {
 
			delete v;
 
			return false;
 
		}
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	return true;
 
}
 

	
 
static void BulldozerInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_BULLDOZER_NE);
 
	v->sprite_cache.sprite_seq.Set(SPR_BULLDOZER_NE);
 
	v->progress = 0;
 
	v->animation_state = 0;
 
	v->animation_substate = 0;
 
}
 

	
 
struct BulldozerMovement {
 
	byte direction:2;
 
	byte image:2;
 
	byte duration:3;
 
};
 

	
 
static const BulldozerMovement _bulldozer_movement[] = {
 
@@ -280,47 +280,47 @@ static const struct {
 
	{ -1,  0 },
 
	{  0,  1 },
 
	{  1,  0 },
 
	{  0, -1 }
 
};
 

	
 
static bool BulldozerTick(EffectVehicle *v)
 
{
 
	v->progress++;
 
	if ((v->progress & 7) == 0) {
 
		const BulldozerMovement *b = &_bulldozer_movement[v->animation_state];
 

	
 
		v->sprite_seq.Set(SPR_BULLDOZER_NE + b->image);
 
		v->sprite_cache.sprite_seq.Set(SPR_BULLDOZER_NE + b->image);
 

	
 
		v->x_pos += _inc_by_dir[b->direction].x;
 
		v->y_pos += _inc_by_dir[b->direction].y;
 

	
 
		v->animation_substate++;
 
		if (v->animation_substate >= b->duration) {
 
			v->animation_substate = 0;
 
			v->animation_state++;
 
			if (v->animation_state == lengthof(_bulldozer_movement)) {
 
				delete v;
 
				return false;
 
			}
 
		}
 
		v->UpdatePositionAndViewport();
 
	}
 

	
 
	return true;
 
}
 

	
 
static void BubbleInit(EffectVehicle *v)
 
{
 
	v->sprite_seq.Set(SPR_BUBBLE_GENERATE_0);
 
	v->sprite_cache.sprite_seq.Set(SPR_BUBBLE_GENERATE_0);
 
	v->spritenum = 0;
 
	v->progress = 0;
 
}
 

	
 
struct BubbleMovement {
 
	int8 x:4;
 
	int8 y:4;
 
	int8 z:4;
 
	byte image:4;
 
};
 

	
 
#define MK(x, y, z, i) { x, y, z, i }
 
@@ -465,26 +465,26 @@ static const BubbleMovement * const _bub
 
	_bubble_burst,
 
	_bubble_absorb,
 
};
 

	
 
static bool BubbleTick(EffectVehicle *v)
 
{
 
	uint anim_state;
 

	
 
	v->progress++;
 
	if ((v->progress & 3) != 0) return true;
 

	
 
	if (v->spritenum == 0) {
 
		v->sprite_seq.seq[0].sprite++;
 
		if (v->sprite_seq.seq[0].sprite < SPR_BUBBLE_GENERATE_3) {
 
		v->sprite_cache.sprite_seq.seq[0].sprite++;
 
		if (v->sprite_cache.sprite_seq.seq[0].sprite < SPR_BUBBLE_GENERATE_3) {
 
			v->UpdatePositionAndViewport();
 
			return true;
 
		}
 
		if (v->animation_substate != 0) {
 
			v->spritenum = GB(Random(), 0, 2) + 1;
 
		} else {
 
			v->spritenum = 6;
 
		}
 
		anim_state = 0;
 
	} else {
 
		anim_state = v->animation_state + 1;
 
	}
 
@@ -511,25 +511,25 @@ static bool BubbleTick(EffectVehicle *v)
 
		if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_31_EXTRACT, v);
 

	
 
		tile = TileVirtXY(v->x_pos, v->y_pos);
 
		if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile);
 
	}
 

	
 
	v->animation_state = anim_state;
 
	b = &_bubble_movement[v->spritenum - 1][anim_state];
 

	
 
	v->x_pos += b->x;
 
	v->y_pos += b->y;
 
	v->z_pos += b->z;
 
	v->sprite_seq.Set(SPR_BUBBLE_0 + b->image);
 
	v->sprite_cache.sprite_seq.Set(SPR_BUBBLE_0 + b->image);
 

	
 
	v->UpdatePositionAndViewport();
 

	
 
	return true;
 
}
 

	
 

	
 
typedef void EffectInitProc(EffectVehicle *v);
 
typedef bool EffectTickProc(EffectVehicle *v);
 

	
 
/** Functions to initialise an effect vehicle after construction. */
 
static EffectInitProc * const _effect_init_procs[] = {
src/roadveh_cmd.cpp
Show inline comments
 
@@ -292,25 +292,25 @@ CommandCost CmdBuildRoadVehicle(TileInde
 
		v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->GetLifeLengthInDays();
 
		_new_vehicle_id = v->index;
 

	
 
		v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh);
 

	
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 

	
 
		v->sprite_seq.Set(SPR_IMG_QUERY);
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = VehicleRandomBits();
 
		v->SetFrontEngine();
 

	
 
		v->roadtype = rt;
 
		v->compatible_roadtypes = rti->powered_roadtypes;
 
		v->gcache.cached_veh_length = VEHICLE_LENGTH;
 

	
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 
		v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
 

	
 
		AddArticulatedParts(v);
 
		v->InvalidateNewGRFCacheOfChain();
src/saveload/oldloader_sl.cpp
Show inline comments
 
@@ -1144,25 +1144,25 @@ static const OldChunks vehicle_chunk[] =
 
	OCL_CNULL( OC_TTO, 1 ), ///< max_speed, now it is calculated.
 

	
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ),
 
	OCL_SVAR( OC_FILE_U8  | OC_VAR_I32, Vehicle, z_pos ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, direction ),
 
	OCL_NULL( 2 ),         ///< x_offs and y_offs, calculated automatically
 
	OCL_NULL( 2 ),         ///< x_extent and y_extent, calculated automatically
 
	OCL_NULL( 1 ),         ///< z_extent, calculated automatically
 

	
 
	OCL_SVAR(  OC_UINT8, Vehicle, owner ),
 
	OCL_SVAR(   OC_TILE, Vehicle, tile ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, sprite_seq.seq[0].sprite ),
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, sprite_cache.sprite_seq.seq[0].sprite ),
 

	
 
	OCL_NULL( 8 ),        ///< Vehicle sprite box, calculated automatically
 

	
 
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ),
 
	OCL_SVAR( OC_TTD | OC_UINT16, Vehicle, cur_speed ),
 
	OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Vehicle, cur_speed ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, subspeed ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, acceleration ),
 
	OCL_SVAR(  OC_UINT8, Vehicle, progress ),
 

	
 
	OCL_SVAR(  OC_UINT8, Vehicle, cargo_type ),
 
	OCL_SVAR( OC_TTD | OC_UINT16, Vehicle, cargo_cap ),
 
@@ -1237,36 +1237,36 @@ bool LoadOldVehicle(LoadgameState *ls, i
 
				case 0x20 /* VEH_TRAIN    */: v = new (_current_vehicle_id) Train();           break;
 
				case 0x21 /* VEH_ROAD     */: v = new (_current_vehicle_id) RoadVehicle();     break;
 
				case 0x22 /* VEH_SHIP     */: v = new (_current_vehicle_id) Ship();            break;
 
				case 0x23 /* VEH_AIRCRAFT */: v = new (_current_vehicle_id) Aircraft();        break;
 
				case 0x24 /* VEH_EFFECT   */: v = new (_current_vehicle_id) EffectVehicle();   break;
 
				case 0x26 /* VEH_DISASTER */: v = new (_current_vehicle_id) DisasterVehicle(); break;
 
			}
 

	
 
			if (!LoadChunk(ls, v, vehicle_chunk)) return false;
 
			if (v == nullptr) continue;
 
			v->refit_cap = v->cargo_cap;
 

	
 
			SpriteID sprite = v->sprite_seq.seq[0].sprite;
 
			SpriteID sprite = v->sprite_cache.sprite_seq.seq[0].sprite;
 
			/* no need to override other sprites */
 
			if (IsInsideMM(sprite, 1460, 1465)) {
 
				sprite += 580; // aircraft smoke puff
 
			} else if (IsInsideMM(sprite, 2096, 2115)) {
 
				sprite += 977; // special effects part 1
 
			} else if (IsInsideMM(sprite, 2396, 2436)) {
 
				sprite += 1305; // special effects part 2
 
			} else if (IsInsideMM(sprite, 2516, 2539)) {
 
				sprite += 1385; // rotor or disaster-related vehicles
 
			}
 
			v->sprite_seq.seq[0].sprite = sprite;
 
			v->sprite_cache.sprite_seq.seq[0].sprite = sprite;
 

	
 
			switch (v->type) {
 
				case VEH_TRAIN: {
 
					static const byte spriteset_rail[] = {
 
						  0,   2,   4,   4,   8,  10,  12,  14,  16,  18,  20,  22,  40,  42,  44,  46,
 
						 48,  52,  54,  66,  68,  70,  72,  74,  76,  78,  80,  82,  84,  86, 120, 122,
 
						124, 126, 128, 130, 132, 134, 136, 138, 140
 
					};
 
					if (v->spritenum / 2 >= lengthof(spriteset_rail)) return false;
 
					v->spritenum = spriteset_rail[v->spritenum / 2]; // adjust railway sprite set offset
 
					/* Should be the original values for monorail / rail, can't use RailType constants */
 
					Train::From(v)->railtype = static_cast<RailType>(type == 0x25 ? 1 : 0);
src/saveload/vehicle_sl.cpp
Show inline comments
 
@@ -436,39 +436,39 @@ void AfterLoadVehicles(bool part_of_load
 
			 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
 
			if ((v->vehstatus & VS_STOPPED) && (v->type != VEH_TRAIN || IsSavegameVersionBefore(SLV_2, 1))) {
 
				v->cur_speed = 0;
 
			}
 
		}
 
	}
 

	
 
	for (Vehicle *v : Vehicle::Iterate()) {
 
		switch (v->type) {
 
			case VEH_ROAD:
 
			case VEH_TRAIN:
 
			case VEH_SHIP:
 
				v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq);
 
				v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_cache.sprite_seq);
 
				break;
 

	
 
			case VEH_AIRCRAFT:
 
				if (Aircraft::From(v)->IsNormalAircraft()) {
 
					v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq);
 
					v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_cache.sprite_seq);
 

	
 
					/* The plane's shadow will have the same image as the plane, but no colour */
 
					Vehicle *shadow = v->Next();
 
					shadow->sprite_seq.CopyWithoutPalette(v->sprite_seq);
 
					shadow->sprite_cache.sprite_seq.CopyWithoutPalette(v->sprite_cache.sprite_seq);
 

	
 
					/* In the case of a helicopter we will update the rotor sprites */
 
					if (v->subtype == AIR_HELICOPTER) {
 
						Vehicle *rotor = shadow->Next();
 
						GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_seq);
 
						GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_cache.sprite_seq);
 
					}
 

	
 
					UpdateAircraftCache(Aircraft::From(v), true);
 
				}
 
				break;
 
			default: break;
 
		}
 

	
 
		v->UpdateDeltaXY();
 
		v->coord.left = INVALID_COORD;
 
		v->UpdatePosition();
 
		v->UpdateViewport(false);
 
@@ -799,25 +799,25 @@ const SaveLoad *GetVehicleDescription(Ve
 
		     SLE_VAR(Vehicle, subtype,               SLE_UINT8),
 

	
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
 
		 SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
 

	
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
 
		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_FILE_U8  | SLE_VAR_I32,   SL_MIN_VERSION, SLV_164),
 
		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_INT32,                  SLV_164, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
 
		     SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
 
		SLE_CONDNULL(5,                                                            SL_MIN_VERSION,  SLV_59),
 
		     SLE_VAR(Vehicle, progress,              SLE_UINT8),
 
		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
 

	
 
		     SLE_VAR(EffectVehicle, animation_state,    SLE_UINT16),
 
		     SLE_VAR(EffectVehicle, animation_substate, SLE_UINT8),
 

	
 
		 SLE_CONDVAR(Vehicle, spritenum,             SLE_UINT8,                    SLV_2, SL_MAX_VERSION),
 

	
 
		SLE_CONDNULL(15,                                                           SLV_2, SLV_144), // old reserved space
 

	
 
		     SLE_END()
 
@@ -839,25 +839,25 @@ const SaveLoad *GetVehicleDescription(Ve
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
 
		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
 
		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_FILE_U8  | SLE_VAR_I32,   SL_MIN_VERSION, SLV_164),
 
		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_INT32,                  SLV_164, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, direction,             SLE_UINT8),
 

	
 
		SLE_CONDNULL(5,                                                            SL_MIN_VERSION,  SLV_58),
 
		     SLE_VAR(Vehicle, owner,                 SLE_UINT8),
 
		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
 
		 SLE_CONDVAR(Vehicle, current_order.dest,    SLE_FILE_U8 | SLE_VAR_U16,    SL_MIN_VERSION,   SLV_5),
 
		 SLE_CONDVAR(Vehicle, current_order.dest,    SLE_UINT16,                   SLV_5, SL_MAX_VERSION),
 

	
 
		     SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
 
		     SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
 
		 SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
 
		 SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   SLV_31, SL_MAX_VERSION),
 
		     SLE_VAR(Vehicle, tick_counter,          SLE_UINT8),
 

	
 
		 SLE_CONDVAR(DisasterVehicle, image_override,            SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION, SLV_191),
 
		 SLE_CONDVAR(DisasterVehicle, image_override,            SLE_UINT32,                 SLV_191, SL_MAX_VERSION),
 
		 SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target,  SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION, SLV_191),
 
		 SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target,  SLE_UINT32,                 SLV_191, SL_MAX_VERSION),
 
		 SLE_CONDVAR(DisasterVehicle, flags,                     SLE_UINT8,                  SLV_194, SL_MAX_VERSION),
 

	
 
		SLE_CONDNULL(16,                                                           SLV_2, SLV_144), // old reserved space
 

	
src/ship_cmd.cpp
Show inline comments
 
@@ -855,25 +855,25 @@ CommandCost CmdBuildShip(TileIndex tile,
 
		v->engine_type = e->index;
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->GetLifeLengthInDays();
 
		_new_vehicle_id = v->index;
 

	
 
		v->state = TRACK_BIT_DEPOT;
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_ships);
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 
		v->sprite_seq.Set(SPR_IMG_QUERY);
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = VehicleRandomBits();
 

	
 
		v->UpdateCache();
 

	
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 
		v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
 

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		v->cargo_cap = e->DetermineCapacity(v);
 

	
 
		v->InvalidateNewGRFCacheOfChain();
src/train_cmd.cpp
Show inline comments
 
@@ -615,25 +615,25 @@ static CommandCost CmdBuildRailWagon(Til
 

	
 
		v->SetFreeWagon();
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 

	
 
		v->cargo_type = e->GetDefaultCargoType();
 
		v->cargo_cap = rvi->capacity;
 
		v->refit_cap = 0;
 

	
 
		v->railtype = rvi->railtype;
 

	
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 
		v->sprite_seq.Set(SPR_IMG_QUERY);
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = VehicleRandomBits();
 

	
 
		v->group_id = DEFAULT_GROUP;
 

	
 
		AddArticulatedParts(v);
 

	
 
		_new_vehicle_id = v->index;
 

	
 
		v->UpdatePosition();
 
		v->First()->ConsistChanged(CCF_ARRANGE);
 
		UpdateTrainGroupID(v->First());
 

	
 
@@ -681,25 +681,25 @@ static void AddRearEngineToMultiheadedTr
 
	u->z_pos = v->z_pos;
 
	u->track = TRACK_BIT_DEPOT;
 
	u->vehstatus = v->vehstatus & ~VS_STOPPED;
 
	u->spritenum = v->spritenum + 1;
 
	u->cargo_type = v->cargo_type;
 
	u->cargo_subtype = v->cargo_subtype;
 
	u->cargo_cap = v->cargo_cap;
 
	u->refit_cap = v->refit_cap;
 
	u->railtype = v->railtype;
 
	u->engine_type = v->engine_type;
 
	u->date_of_last_service = v->date_of_last_service;
 
	u->build_year = v->build_year;
 
	u->sprite_seq.Set(SPR_IMG_QUERY);
 
	u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
	u->random_bits = VehicleRandomBits();
 
	v->SetMultiheaded();
 
	u->SetMultiheaded();
 
	v->SetNext(u);
 
	u->UpdatePosition();
 

	
 
	/* Now we need to link the front and rear engines together */
 
	v->other_multiheaded_part = u;
 
	u->other_multiheaded_part = v;
 
}
 

	
 
/**
 
@@ -747,25 +747,25 @@ CommandCost CmdBuildRailVehicle(TileInde
 
		v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->railtype = rvi->railtype;
 
		_new_vehicle_id = v->index;
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 
		v->sprite_seq.Set(SPR_IMG_QUERY);
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = VehicleRandomBits();
 

	
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 
		v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
 

	
 
		v->group_id = DEFAULT_GROUP;
 

	
 
		v->SetFrontEngine();
 
		v->SetEngine();
 

	
 
		v->UpdatePosition();
 

	
src/vehicle.cpp
Show inline comments
 
@@ -1085,43 +1085,37 @@ static void DoDrawVehicle(const Vehicle 
 
	bool shadowed = (v->vehstatus & VS_SHADOW) != 0;
 

	
 
	if (v->type == VEH_EFFECT) {
 
		/* Check whether the vehicle shall be transparent/invisible due to GUI settings.
 
		 * However, transparent smoke and bubbles look weird, so always hide them. */
 
		TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption();
 
		if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
 
	}
 

	
 
	/*
 
	 * If the vehicle sprite was not updated despite further viewport changes, we need
 
	 * to update it before drawing.
 
	 *
 
	 * I'm not keen on casting to mutable - it's the approach JGR uses in JGRPP but I
 
	 * wonder if there's a cleaner option (even though we can only take the decision
 
	 * whether to update once we already know the vehicle is going to appear in a
 
	 * viewport)
 
	 */
 
	if (v->rstate.sprite_has_viewport_changes) {
 
		Vehicle* v_mutable = const_cast<Vehicle*>(v);
 
	if (v->sprite_cache.sprite_has_viewport_changes) {
 
		VehicleSpriteSeq seq;
 
		v_mutable->GetImage(v_mutable->direction, EIT_ON_MAP, &seq);
 
		v_mutable->sprite_seq = seq;
 
		v_mutable->rstate.sprite_has_viewport_changes = false;
 
		v->GetImage(v->direction, EIT_ON_MAP, &seq);
 
		v->sprite_cache.sprite_seq = seq;
 
		v->sprite_cache.sprite_has_viewport_changes = false;
 
	}
 

	
 
	StartSpriteCombine();
 
	for (uint i = 0; i < v->sprite_seq.count; ++i) {
 
		PaletteID pal2 = v->sprite_seq.seq[i].pal;
 
	for (uint i = 0; i < v->sprite_cache.sprite_seq.count; ++i) {
 
		PaletteID pal2 = v->sprite_cache.sprite_seq.seq[i].pal;
 
		if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal;
 
		AddSortableSpriteToDraw(v->sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
 
		AddSortableSpriteToDraw(v->sprite_cache.sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
 
			v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
 
	}
 
	EndSpriteCombine();
 
}
 

	
 
/**
 
 * Add the vehicle sprites that should be drawn at a part of the screen.
 
 * @param dpi Rectangle being drawn.
 
 */
 
void ViewportAddVehicles(DrawPixelInfo *dpi)
 
{
 
	/* The bounding rectangle */
 
@@ -1166,28 +1160,28 @@ void ViewportAddVehicles(DrawPixelInfo *
 
				}
 
				else {
 
					/*
 
					 * Indicate that this vehicle was considered for rendering in a viewport,
 
					 * and we therefore need to update sprites more frequently in case a callback
 
					 * will change the bounding box to one which will cause the sprite to be
 
					 * displayed.
 
					 *
 
					 * This reduces the chances of flicker when sprites enter the screen, if they
 
					 * are part of a newgrf vehicle set which changes bounding boxes within a
 
					 * single vehicle direction.
 
					 *
 
					 * TODO: is there a cleaner solution than casting to a mutable type?
 
					 * TODO: this will consider too many false positives, use the bounding box
 
					 * information or something which better narrows down the candidates.
 
					 */
 
					Vehicle* v_mutable = const_cast<Vehicle*>(v);
 
					v_mutable->rstate.is_viewport_candidate = true;
 
					v->sprite_cache.is_viewport_candidate = true;
 
				}
 

	
 
				v = v->hash_viewport_next;
 
			}
 

	
 
			if (x == xu) break;
 
		}
 

	
 
		if (y == yu) break;
 
	}
 
}
 

	
 
@@ -1596,25 +1590,25 @@ void Vehicle::UpdatePosition()
 
{
 
	UpdateVehicleTileHash(this, false);
 
}
 

	
 
/**
 
 * Update the vehicle on the viewport, updating the right hash and setting the
 
 *  new coordinates.
 
 * @param dirty Mark the (new and old) coordinates of the vehicle as dirty.
 
 */
 
void Vehicle::UpdateViewport(bool dirty)
 
{
 
	Rect new_coord;
 
	this->sprite_seq.GetBounds(&new_coord);
 
	this->sprite_cache.sprite_seq.GetBounds(&new_coord);
 

	
 
	Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
 
	new_coord.left   += pt.x;
 
	new_coord.top    += pt.y;
 
	new_coord.right  += pt.x + 2 * ZOOM_LVL_BASE;
 
	new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE;
 

	
 
	UpdateVehicleViewportHash(this, new_coord.left, new_coord.top);
 

	
 
	Rect old_coord = this->coord;
 
	this->coord = new_coord;
 

	
src/vehicle_base.h
Show inline comments
 
@@ -115,31 +115,24 @@ enum GroundVehicleSubtypeFlags {
 
	GVSF_FREE_WAGON       = 4, ///< First in a wagon chain (in depot) (not used for road vehicles).
 
	GVSF_MULTIHEADED      = 5, ///< Engine is multiheaded (not used for road vehicles).
 
};
 

	
 
/** Cached often queried values common to all vehicles. */
 
struct VehicleCache {
 
	uint16 cached_max_speed;        ///< Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
 
	uint16 cached_cargo_age_period; ///< Number of ticks before carried cargo is aged.
 

	
 
	byte cached_vis_effect;  ///< Visual effect to show (see #VisualEffect)
 
};
 

	
 
/** Values for controlling how a vehicle's sprites are refreshed */
 
struct VehicleSpriteRefreshState {
 
	Direction last_direction;         ///< Last direction we obtained sprites for
 
	bool is_viewport_candidate;       ///< The vehicle has been in the hash for a shown viewport recently
 
	bool sprite_has_viewport_changes; ///< There have been viewport changes since the sprite was last updated
 
};
 

	
 
/** Sprite sequence for a vehicle part. */
 
struct VehicleSpriteSeq {
 
	PalSpriteID seq[4];
 
	uint count;
 

	
 
	bool operator==(const VehicleSpriteSeq &other) const
 
	{
 
		return this->count == other.count && MemCmpT<PalSpriteID>(this->seq, other.seq, this->count) == 0;
 
	}
 

	
 
	bool operator!=(const VehicleSpriteSeq &other) const
 
	{
 
@@ -179,24 +172,35 @@ struct VehicleSpriteSeq {
 
	{
 
		this->count = src.count;
 
		for (uint i = 0; i < src.count; ++i) {
 
			this->seq[i].sprite = src.seq[i].sprite;
 
			this->seq[i].pal = 0;
 
		}
 
	}
 

	
 
	void GetBounds(Rect *bounds) const;
 
	void Draw(int x, int y, PaletteID default_pal, bool force_pal) const;
 
};
 

	
 
/**
 
 * Cache for vehicle sprites and values relating to whether they should be updated before drawing,
 
 * or calculating the viewport.
 
 */
 
struct MutableSpriteCache {
 
	Direction last_direction;                 ///< Last direction we obtained sprites for
 
	mutable bool is_viewport_candidate;       ///< The vehicle has been in the hash for a shown viewport recently
 
	mutable bool sprite_has_viewport_changes; ///< There have been viewport changes since the sprite was last updated
 
	mutable VehicleSpriteSeq sprite_seq;      ///< Vehicle appearance.
 
};
 

	
 
/** A vehicle pool for a little over 1 million vehicles. */
 
typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
 
extern VehiclePool _vehicle_pool;
 

	
 
/* Some declarations of functions, so we can make them friendly */
 
struct SaveLoad;
 
struct GroundVehicleCache;
 
extern const SaveLoad *GetVehicleDescription(VehicleType vt);
 
struct LoadgameState;
 
extern bool LoadOldVehicle(LoadgameState *ls, int num);
 
extern void FixOldVehicles();
 

	
 
@@ -273,25 +277,24 @@ public:
 
	int32 x_pos;                        ///< x coordinate.
 
	int32 y_pos;                        ///< y coordinate.
 
	int32 z_pos;                        ///< z coordinate.
 
	Direction direction;                ///< facing
 

	
 
	Owner owner;                        ///< Which company owns the vehicle?
 
	/**
 
	 * currently displayed sprite index
 
	 * 0xfd == custom sprite, 0xfe == custom second head sprite
 
	 * 0xff == reserved for another custom sprite
 
	 */
 
	byte spritenum;
 
	VehicleSpriteSeq sprite_seq;        ///< Vehicle appearance.
 
	byte x_extent;                      ///< x-extent of vehicle bounding box
 
	byte y_extent;                      ///< y-extent of vehicle bounding box
 
	byte z_extent;                      ///< z-extent of vehicle bounding box
 
	int8 x_bb_offs;                     ///< x offset of vehicle bounding box
 
	int8 y_bb_offs;                     ///< y offset of vehicle bounding box
 
	int8 x_offs;                        ///< x offset for vehicle sprite
 
	int8 y_offs;                        ///< y offset for vehicle sprite
 
	EngineID engine_type;               ///< The type of engine used for this vehicle.
 

	
 
	TextEffectID fill_percent_te_id;    ///< a text-effect id to a loading indicator object
 
	UnitID unitnumber;                  ///< unit number, for display purposes only
 

	
 
@@ -325,25 +328,25 @@ public:
 
	union {
 
		OrderList *list;            ///< Pointer to the order list for this vehicle
 
		Order     *old;             ///< Only used during conversion of old save games
 
	} orders;                           ///< The orders currently assigned to the vehicle.
 

	
 
	uint16 load_unload_ticks;           ///< Ticks to wait before starting next cycle.
 
	GroupID group_id;                   ///< Index of group Pool array
 
	byte subtype;                       ///< subtype (Filled with values from #AircraftSubType/#DisasterSubType/#EffectVehicleType/#GroundVehicleSubtypeFlags)
 

	
 
	NewGRFCache grf_cache;              ///< Cache of often used calculated NewGRF values
 
	VehicleCache vcache;                ///< Cache of often used vehicle values.
 

	
 
	VehicleSpriteRefreshState rstate;   ///< Values relating to whether sprites should be refreshed, see #VehicleSpriteRefreshState
 
	MutableSpriteCache sprite_cache;    ///< Cache of sprites and values related to recalculating them, see #MutableSpriteCache
 

	
 
	Vehicle(VehicleType type = VEH_INVALID);
 

	
 
	void PreDestructor();
 
	/** We want to 'destruct' the right class. */
 
	virtual ~Vehicle();
 

	
 
	void BeginLoading();
 
	void CancelReservation(StationID next, Station *st);
 
	void LeaveStation();
 

	
 
	GroundVehicleCache *GetGroundVehicleCache();
 
@@ -1035,25 +1038,25 @@ public:
 
 */
 
template <class T, VehicleType Type>
 
struct SpecializedVehicle : public Vehicle {
 
	static const VehicleType EXPECTED_TYPE = Type; ///< Specialized type
 

	
 
	typedef SpecializedVehicle<T, Type> SpecializedVehicleBase; ///< Our type
 

	
 
	/**
 
	 * Set vehicle type correctly
 
	 */
 
	inline SpecializedVehicle<T, Type>() : Vehicle(Type)
 
	{
 
		this->sprite_seq.count = 1;
 
		this->sprite_cache.sprite_seq.count = 1;
 
	}
 

	
 
	/**
 
	 * Get the first vehicle in the chain
 
	 * @return first vehicle in the chain
 
	 */
 
	inline T *First() const { return (T *)this->Vehicle::First(); }
 

	
 
	/**
 
	 * Get the last vehicle in the chain
 
	 * @return last vehicle in the chain
 
	 */
 
@@ -1184,42 +1187,42 @@ struct SpecializedVehicle : public Vehic
 
		if (_network_dedicated) return;
 

	
 
		/* 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();
 

	
 
		/*
 
		 * Only check for a new sprite sequence if the vehicle direction
 
		 * has changed since we last checked it, assuming that otherwise
 
		 * there won't be enough change in bounding box or offsets to need
 
		 * to resolve a new sprite.
 
		 */
 
		if (this->direction != this->rstate.last_direction || this->rstate.is_viewport_candidate) {
 
		if (this->direction != this->sprite_cache.last_direction || this->sprite_cache.is_viewport_candidate) {
 
			VehicleSpriteSeq seq;
 

	
 
			((T*)this)->T::GetImage(this->direction, EIT_ON_MAP, &seq);
 
			if (this->sprite_seq != seq) {
 
			if (this->sprite_cache.sprite_seq != seq) {
 
				sprite_has_changed = true;
 
				this->sprite_seq = seq;
 
				this->sprite_cache.sprite_seq = seq;
 
			}
 

	
 
			this->rstate.last_direction = this->direction;
 
			this->rstate.is_viewport_candidate = false;
 
			this->rstate.sprite_has_viewport_changes = false;
 
			this->sprite_cache.last_direction = this->direction;
 
			this->sprite_cache.is_viewport_candidate = false;
 
			this->sprite_cache.sprite_has_viewport_changes = false;
 
		} else {
 
			/*
 
			 * Changes could still be relevant when we render the vehicle even if
 
			 * they don't alter the bounding box
 
			 */
 
			this->rstate.sprite_has_viewport_changes = true;
 
			this->sprite_cache.sprite_has_viewport_changes = true;
 
		}
 

	
 
		if (force_update || sprite_has_changed) {
 
			this->Vehicle::UpdateViewport(true);
 
		}
 
	}
 

	
 
	/**
 
	 * Returns an iterable ensemble of all valid vehicles of type T
 
	 * @param from index of the first vehicle to consider
 
	 * @return an iterable ensemble of all valid vehicles of type T
 
	 */
0 comments (0 inline, 0 general)