Merge branch 'template_train_replacement' into jgrpp
# Conflicts: # src/linkgraph/linkgraphjob.cpp # src/saveload/extended_ver_sl.cpp # src/train_cmd.cpp # src/vehicle_base.h
This commit is contained in:
		@@ -94,7 +94,7 @@ struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
 | 
			
		||||
	void UpdateDeltaXY(Direction direction);
 | 
			
		||||
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; }
 | 
			
		||||
	bool IsPrimaryVehicle() const                  { return this->IsNormalAircraft(); }
 | 
			
		||||
	SpriteID GetImage(Direction direction, EngineImageType image_type) const;
 | 
			
		||||
	void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const;
 | 
			
		||||
	int GetDisplaySpeed() const    { return this->cur_speed; }
 | 
			
		||||
	int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; }
 | 
			
		||||
	int GetSpeedOldUnits() const   { return this->vcache.cached_max_speed * 10 / 128; }
 | 
			
		||||
@@ -142,7 +142,7 @@ struct Aircraft FINAL : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
 | 
			
		||||
 */
 | 
			
		||||
#define FOR_ALL_AIRCRAFT(var) FOR_ALL_VEHICLES_OF_TYPE(Aircraft, var)
 | 
			
		||||
 | 
			
		||||
SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type);
 | 
			
		||||
void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result);
 | 
			
		||||
 | 
			
		||||
Station *GetTargetAirportIfValid(const Aircraft *v);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -158,64 +158,69 @@ static StationID FindNearestHangar(const Aircraft *v)
 | 
			
		||||
	return index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpriteID Aircraft::GetImage(Direction direction, EngineImageType image_type) const
 | 
			
		||||
void Aircraft::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
 | 
			
		||||
{
 | 
			
		||||
	uint8 spritenum = this->spritenum;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleSprite(this, direction, image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = this->GetEngine()->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_AIRCRAFT>(spritenum));
 | 
			
		||||
	return direction + _aircraft_sprite[spritenum];
 | 
			
		||||
	result->Set(direction + _aircraft_sprite[spritenum]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type)
 | 
			
		||||
void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	assert(v->subtype == AIR_HELICOPTER);
 | 
			
		||||
 | 
			
		||||
	const Aircraft *w = v->Next()->Next();
 | 
			
		||||
	if (is_custom_sprite(v->spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomRotorSprite(v, false, image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomRotorSprite(v, false, image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Return standard rotor sprites if there are no custom sprites for this helicopter */
 | 
			
		||||
	return SPR_ROTOR_STOPPED + w->state;
 | 
			
		||||
	result->Set(SPR_ROTOR_STOPPED + w->state);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpriteID GetAircraftIcon(EngineID engine, EngineImageType image_type)
 | 
			
		||||
static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	const Engine *e = Engine::Get(engine);
 | 
			
		||||
	uint8 spritenum = e->u.air.image_index;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleIcon(engine, DIR_W, image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = e->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_AIRCRAFT>(spritenum));
 | 
			
		||||
	return DIR_W + _aircraft_sprite[spritenum];
 | 
			
		||||
	result->Set(DIR_W + _aircraft_sprite[spritenum]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
 | 
			
		||||
{
 | 
			
		||||
	SpriteID sprite = GetAircraftIcon(engine, image_type);
 | 
			
		||||
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetAircraftIcon(engine, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
	preferred_x = Clamp(preferred_x,
 | 
			
		||||
			left - UnScaleGUI(real_sprite->x_offs),
 | 
			
		||||
			right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs));
 | 
			
		||||
	DrawSprite(sprite, pal, preferred_x, y);
 | 
			
		||||
			left - UnScaleGUI(rect.left),
 | 
			
		||||
			right - UnScaleGUI(rect.right));
 | 
			
		||||
 | 
			
		||||
	seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
 | 
			
		||||
 | 
			
		||||
	if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) {
 | 
			
		||||
		SpriteID rotor_sprite = GetCustomRotorIcon(engine, image_type);
 | 
			
		||||
		if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
 | 
			
		||||
		DrawSprite(rotor_sprite, PAL_NONE, preferred_x, y - ScaleGUITrad(5));
 | 
			
		||||
		VehicleSpriteSeq rotor_seq;
 | 
			
		||||
		GetCustomRotorIcon(engine, image_type, &rotor_seq);
 | 
			
		||||
		if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED);
 | 
			
		||||
		rotor_seq.Draw(preferred_x, y - ScaleGUITrad(5), PAL_NONE, false);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -230,12 +235,16 @@ void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID en
 | 
			
		||||
 */
 | 
			
		||||
void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
 | 
			
		||||
{
 | 
			
		||||
	const Sprite *spr = GetSprite(GetAircraftIcon(engine, image_type), ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetAircraftIcon(engine, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(spr->width);
 | 
			
		||||
	height = UnScaleGUI(spr->height);
 | 
			
		||||
	xoffs  = UnScaleGUI(spr->x_offs);
 | 
			
		||||
	yoffs  = UnScaleGUI(spr->y_offs);
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(rect.right - rect.left + 1);
 | 
			
		||||
	height = UnScaleGUI(rect.bottom - rect.top + 1);
 | 
			
		||||
	xoffs  = UnScaleGUI(rect.left);
 | 
			
		||||
	yoffs  = UnScaleGUI(rect.top);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -326,7 +335,8 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *
 | 
			
		||||
		v->date_of_last_service = _date;
 | 
			
		||||
		v->build_year = u->build_year = _cur_year;
 | 
			
		||||
 | 
			
		||||
		v->cur_image = u->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
		v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
		u->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
 | 
			
		||||
		v->random_bits = VehicleRandomBits();
 | 
			
		||||
		u->random_bits = VehicleRandomBits();
 | 
			
		||||
@@ -360,7 +370,7 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *
 | 
			
		||||
			w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
 | 
			
		||||
			w->spritenum = 0xFF;
 | 
			
		||||
			w->subtype = AIR_ROTOR;
 | 
			
		||||
			w->cur_image = SPR_ROTOR_STOPPED;
 | 
			
		||||
			w->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;
 | 
			
		||||
@@ -479,21 +489,21 @@ static void HelicopterTickHandler(Aircraft *v)
 | 
			
		||||
	int tick = ++u->tick_counter;
 | 
			
		||||
	int spd = u->cur_speed >> 4;
 | 
			
		||||
 | 
			
		||||
	SpriteID img;
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	if (spd == 0) {
 | 
			
		||||
		u->state = HRS_ROTOR_STOPPED;
 | 
			
		||||
		img = GetRotorImage(v, EIT_ON_MAP);
 | 
			
		||||
		if (u->cur_image == img) return;
 | 
			
		||||
		GetRotorImage(v, EIT_ON_MAP, &seq);
 | 
			
		||||
		if (u->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;
 | 
			
		||||
		img = GetRotorImage(v, EIT_ON_MAP);
 | 
			
		||||
		GetRotorImage(v, EIT_ON_MAP, &seq);
 | 
			
		||||
	} else {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	u->cur_image = img;
 | 
			
		||||
	u->sprite_seq = seq;
 | 
			
		||||
 | 
			
		||||
	u->UpdatePositionAndViewport();
 | 
			
		||||
}
 | 
			
		||||
@@ -513,7 +523,9 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z)
 | 
			
		||||
 | 
			
		||||
	v->UpdatePosition();
 | 
			
		||||
	v->UpdateViewport(true, false);
 | 
			
		||||
	if (v->subtype == AIR_HELICOPTER) v->Next()->Next()->cur_image = GetRotorImage(v, EIT_ON_MAP);
 | 
			
		||||
	if (v->subtype == AIR_HELICOPTER) {
 | 
			
		||||
		GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_seq);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Aircraft *u = v->Next();
 | 
			
		||||
 | 
			
		||||
@@ -524,7 +536,7 @@ void SetAircraftPosition(Aircraft *v, 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->cur_image = v->cur_image;
 | 
			
		||||
	u->sprite_seq.CopyWithoutPalette(v->sprite_seq); // the shadow is never coloured
 | 
			
		||||
 | 
			
		||||
	u->UpdatePositionAndViewport();
 | 
			
		||||
 | 
			
		||||
@@ -1295,7 +1307,9 @@ void Aircraft::MarkDirty()
 | 
			
		||||
	this->colourmap = PAL_NONE;
 | 
			
		||||
	this->cur_image_valid_dir = INVALID_DIR;
 | 
			
		||||
	this->UpdateViewport(true, false);
 | 
			
		||||
	if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this, EIT_ON_MAP);
 | 
			
		||||
	if (this->subtype == AIR_HELICOPTER) {
 | 
			
		||||
		GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_seq);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -83,11 +83,14 @@ void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID s
 | 
			
		||||
{
 | 
			
		||||
	bool rtl = _current_text_dir == TD_RTL;
 | 
			
		||||
 | 
			
		||||
	SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type);
 | 
			
		||||
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	int width = UnScaleGUI(real_sprite->width);
 | 
			
		||||
	int x_offs = UnScaleGUI(real_sprite->x_offs);
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
	int width = UnScaleGUI(rect.right - rect.left + 1);
 | 
			
		||||
	int x_offs = UnScaleGUI(rect.left);
 | 
			
		||||
	int x = rtl ? right - width - x_offs : left - x_offs;
 | 
			
		||||
	bool helicopter = v->subtype == AIR_HELICOPTER;
 | 
			
		||||
 | 
			
		||||
@@ -95,17 +98,18 @@ void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID s
 | 
			
		||||
	int heli_offs = 0;
 | 
			
		||||
 | 
			
		||||
	PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 | 
			
		||||
	DrawSprite(sprite, pal, x, y + y_offs);
 | 
			
		||||
	seq.Draw(x, y + y_offs, pal, v->vehstatus & VS_CRASHED);
 | 
			
		||||
	if (helicopter) {
 | 
			
		||||
		const Aircraft *a = Aircraft::From(v);
 | 
			
		||||
		SpriteID rotor_sprite = GetCustomRotorSprite(a, true, image_type);
 | 
			
		||||
		if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
 | 
			
		||||
		VehicleSpriteSeq rotor_seq;
 | 
			
		||||
		GetCustomRotorSprite(a, true, image_type, &rotor_seq);
 | 
			
		||||
		if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED);
 | 
			
		||||
		heli_offs = ScaleGUITrad(5);
 | 
			
		||||
		DrawSprite(rotor_sprite, PAL_NONE, x, y + y_offs - heli_offs);
 | 
			
		||||
		rotor_seq.Draw(x, y + y_offs - heli_offs, PAL_NONE, false);
 | 
			
		||||
	}
 | 
			
		||||
	if (v->index == selection) {
 | 
			
		||||
		x += x_offs;
 | 
			
		||||
		y += UnScaleGUI(real_sprite->y_offs) + y_offs - heli_offs;
 | 
			
		||||
		DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY);
 | 
			
		||||
		y += UnScaleGUI(rect.top) + y_offs - heli_offs;
 | 
			
		||||
		DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(rect.bottom - rect.top + 1) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -474,7 +474,7 @@ void AddArticulatedParts(Vehicle *first)
 | 
			
		||||
		v->max_age = 0;
 | 
			
		||||
		v->engine_type = engine_type;
 | 
			
		||||
		v->value = 0;
 | 
			
		||||
		v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
		v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
		v->random_bits = VehicleRandomBits();
 | 
			
		||||
 | 
			
		||||
		if (flip_image) v->spritenum++;
 | 
			
		||||
 
 | 
			
		||||
@@ -112,7 +112,7 @@ void DisasterVehicle::UpdateImage()
 | 
			
		||||
{
 | 
			
		||||
	SpriteID img = this->image_override;
 | 
			
		||||
	if (img == 0) img = _disaster_images[this->subtype][this->direction];
 | 
			
		||||
	this->cur_image = img;
 | 
			
		||||
	this->sprite_seq.Set(img);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -502,7 +502,8 @@ static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v)
 | 
			
		||||
	v->tick_counter++;
 | 
			
		||||
	if (HasBit(v->tick_counter, 0)) return true;
 | 
			
		||||
 | 
			
		||||
	if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1;
 | 
			
		||||
	SpriteID &cur_image = v->sprite_seq.seq[0].sprite;
 | 
			
		||||
	if (++cur_image > SPR_ROTOR_MOVING_3) cur_image = SPR_ROTOR_MOVING_1;
 | 
			
		||||
 | 
			
		||||
	v->UpdatePositionAndViewport();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -22,10 +22,26 @@
 | 
			
		||||
#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++;
 | 
			
		||||
		return true;
 | 
			
		||||
	} else {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ChimneySmokeInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	uint32 r = Random();
 | 
			
		||||
	v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3);
 | 
			
		||||
	v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3));
 | 
			
		||||
	v->progress = GB(r, 16, 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -40,10 +56,8 @@ static bool ChimneySmokeTick(EffectVehicle *v)
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (v->cur_image != SPR_CHIMNEY_SMOKE_7) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
		} else {
 | 
			
		||||
			v->cur_image = SPR_CHIMNEY_SMOKE_0;
 | 
			
		||||
		if (!IncrementSprite(v, SPR_CHIMNEY_SMOKE_7)) {
 | 
			
		||||
			v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0);
 | 
			
		||||
		}
 | 
			
		||||
		v->progress = 7;
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
@@ -54,7 +68,7 @@ static bool ChimneySmokeTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void SteamSmokeInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_STEAM_SMOKE_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_STEAM_SMOKE_0);
 | 
			
		||||
	v->progress = 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -70,9 +84,7 @@ static bool SteamSmokeTick(EffectVehicle *v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((v->progress & 0xF) == 4) {
 | 
			
		||||
		if (v->cur_image != SPR_STEAM_SMOKE_4) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
		} else {
 | 
			
		||||
		if (!IncrementSprite(v, SPR_STEAM_SMOKE_4)) {
 | 
			
		||||
			delete v;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
@@ -86,7 +98,7 @@ static bool SteamSmokeTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void DieselSmokeInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_DIESEL_SMOKE_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_DIESEL_SMOKE_0);
 | 
			
		||||
	v->progress = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -98,13 +110,11 @@ static bool DieselSmokeTick(EffectVehicle *v)
 | 
			
		||||
		v->z_pos++;
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
	} else if ((v->progress & 7) == 1) {
 | 
			
		||||
		if (v->cur_image != SPR_DIESEL_SMOKE_5) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
			v->UpdatePositionAndViewport();
 | 
			
		||||
		} else {
 | 
			
		||||
		if (!IncrementSprite(v, SPR_DIESEL_SMOKE_5)) {
 | 
			
		||||
			delete v;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -112,7 +122,7 @@ static bool DieselSmokeTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void ElectricSparkInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_ELECTRIC_SPARK_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_ELECTRIC_SPARK_0);
 | 
			
		||||
	v->progress = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -122,13 +132,12 @@ static bool ElectricSparkTick(EffectVehicle *v)
 | 
			
		||||
		v->progress++;
 | 
			
		||||
	} else {
 | 
			
		||||
		v->progress = 0;
 | 
			
		||||
		if (v->cur_image != SPR_ELECTRIC_SPARK_5) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
			v->UpdatePositionAndViewport();
 | 
			
		||||
		} else {
 | 
			
		||||
 | 
			
		||||
		if (!IncrementSprite(v, SPR_ELECTRIC_SPARK_5)) {
 | 
			
		||||
			delete v;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -136,7 +145,7 @@ static bool ElectricSparkTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void SmokeInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_SMOKE_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_SMOKE_0);
 | 
			
		||||
	v->progress = 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -152,9 +161,7 @@ static bool SmokeTick(EffectVehicle *v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((v->progress & 0xF) == 4) {
 | 
			
		||||
		if (v->cur_image != SPR_SMOKE_4) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
		} else {
 | 
			
		||||
		if (!IncrementSprite(v, SPR_SMOKE_4)) {
 | 
			
		||||
			delete v;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
@@ -168,7 +175,7 @@ static bool SmokeTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void ExplosionLargeInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_EXPLOSION_LARGE_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_EXPLOSION_LARGE_0);
 | 
			
		||||
	v->progress = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -176,13 +183,11 @@ static bool ExplosionLargeTick(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->progress++;
 | 
			
		||||
	if ((v->progress & 3) == 0) {
 | 
			
		||||
		if (v->cur_image != SPR_EXPLOSION_LARGE_F) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
			v->UpdatePositionAndViewport();
 | 
			
		||||
		} else {
 | 
			
		||||
		if (!IncrementSprite(v, SPR_EXPLOSION_LARGE_F)) {
 | 
			
		||||
			delete v;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -190,7 +195,7 @@ static bool ExplosionLargeTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void BreakdownSmokeInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_BREAKDOWN_SMOKE_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
 | 
			
		||||
	v->progress = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -198,10 +203,8 @@ static bool BreakdownSmokeTick(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->progress++;
 | 
			
		||||
	if ((v->progress & 7) == 0) {
 | 
			
		||||
		if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
		} else {
 | 
			
		||||
			v->cur_image = SPR_BREAKDOWN_SMOKE_0;
 | 
			
		||||
		if (!IncrementSprite(v, SPR_BREAKDOWN_SMOKE_3)) {
 | 
			
		||||
			v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0);
 | 
			
		||||
		}
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
	}
 | 
			
		||||
@@ -217,7 +220,7 @@ static bool BreakdownSmokeTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void ExplosionSmallInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_EXPLOSION_SMALL_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_EXPLOSION_SMALL_0);
 | 
			
		||||
	v->progress = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -225,13 +228,11 @@ static bool ExplosionSmallTick(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->progress++;
 | 
			
		||||
	if ((v->progress & 3) == 0) {
 | 
			
		||||
		if (v->cur_image != SPR_EXPLOSION_SMALL_B) {
 | 
			
		||||
			v->cur_image++;
 | 
			
		||||
			v->UpdatePositionAndViewport();
 | 
			
		||||
		} else {
 | 
			
		||||
		if (!IncrementSprite(v, SPR_EXPLOSION_SMALL_B)) {
 | 
			
		||||
			delete v;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		v->UpdatePositionAndViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
@@ -239,7 +240,7 @@ static bool ExplosionSmallTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void BulldozerInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_BULLDOZER_NE;
 | 
			
		||||
	v->sprite_seq.Set(SPR_BULLDOZER_NE);
 | 
			
		||||
	v->progress = 0;
 | 
			
		||||
	v->animation_state = 0;
 | 
			
		||||
	v->animation_substate = 0;
 | 
			
		||||
@@ -290,7 +291,7 @@ static bool BulldozerTick(EffectVehicle *v)
 | 
			
		||||
	if ((v->progress & 7) == 0) {
 | 
			
		||||
		const BulldozerMovement *b = &_bulldozer_movement[v->animation_state];
 | 
			
		||||
 | 
			
		||||
		v->cur_image = SPR_BULLDOZER_NE + b->image;
 | 
			
		||||
		v->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;
 | 
			
		||||
@@ -312,7 +313,7 @@ static bool BulldozerTick(EffectVehicle *v)
 | 
			
		||||
 | 
			
		||||
static void BubbleInit(EffectVehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	v->cur_image = SPR_BUBBLE_GENERATE_0;
 | 
			
		||||
	v->sprite_seq.Set(SPR_BUBBLE_GENERATE_0);
 | 
			
		||||
	v->spritenum = 0;
 | 
			
		||||
	v->progress = 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -475,8 +476,8 @@ static bool BubbleTick(EffectVehicle *v)
 | 
			
		||||
	if ((v->progress & 3) != 0) return true;
 | 
			
		||||
 | 
			
		||||
	if (v->spritenum == 0) {
 | 
			
		||||
		v->cur_image++;
 | 
			
		||||
		if (v->cur_image < SPR_BUBBLE_GENERATE_3) {
 | 
			
		||||
		v->sprite_seq.seq[0].sprite++;
 | 
			
		||||
		if (v->sprite_seq.seq[0].sprite < SPR_BUBBLE_GENERATE_3) {
 | 
			
		||||
			v->UpdatePositionAndViewport();
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
@@ -521,7 +522,7 @@ static bool BubbleTick(EffectVehicle *v)
 | 
			
		||||
	v->x_pos += b->x;
 | 
			
		||||
	v->y_pos += b->y;
 | 
			
		||||
	v->z_pos += b->z;
 | 
			
		||||
	v->cur_image = SPR_BUBBLE_0 + b->image;
 | 
			
		||||
	v->sprite_seq.Set(SPR_BUBBLE_0 + b->image);
 | 
			
		||||
 | 
			
		||||
	v->UpdatePositionAndViewport();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -158,6 +158,7 @@ enum EngineMiscFlags {
 | 
			
		||||
	EF_AUTO_REFIT = 4, ///< Automatic refitting is allowed
 | 
			
		||||
	EF_NO_DEFAULT_CARGO_MULTIPLIER = 5, ///< Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipliers. CB 15 is also called in purchase list.
 | 
			
		||||
	EF_NO_BREAKDOWN_SMOKE          = 6, ///< Do not show black smoke during a breakdown.
 | 
			
		||||
	EF_SPRITE_STACK                = 7, ///< Draw vehicle by stacking multiple sprites.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -250,6 +250,7 @@ STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC                              :{BLACK}ทำ
 | 
			
		||||
 | 
			
		||||
# Show engines button
 | 
			
		||||
 | 
			
		||||
STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP                :ถ้าได้อนุญาตที่ปุ่มนี้แล้ว อากาศยานที่ซ่อนจะถูกแสดงออกมา
 | 
			
		||||
 | 
			
		||||
# Query window
 | 
			
		||||
STR_BUTTON_DEFAULT                                              :{BLACK}ค่าปกติ
 | 
			
		||||
@@ -970,6 +971,7 @@ STR_GAME_OPTIONS_RESOLUTION                                     :{BLACK}คว
 | 
			
		||||
STR_GAME_OPTIONS_RESOLUTION_TOOLTIP                             :{BLACK}เลือกความละเอียดของหน้าจอที่จะใช้
 | 
			
		||||
STR_GAME_OPTIONS_RESOLUTION_OTHER                               :อื่นๆ
 | 
			
		||||
 | 
			
		||||
STR_GAME_OPTIONS_GUI_ZOOM_FRAME                                 :{BLACK}ขนาดของแผงควบคุม
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
STR_GAME_OPTIONS_BASE_GRF                                       :{BLACK}ตั้งค่า Graphic พื้นฐาน
 | 
			
		||||
@@ -1086,6 +1088,7 @@ STR_CONFIG_SETTING_TYPE_COMPANY_MENU                            :ตั้งค
 | 
			
		||||
STR_CONFIG_SETTING_TYPE_COMPANY_INGAME                          :ตั้งค่าองค์กร (ถูกเก็บไว้ในการบันทึกเกม; มีผลเฉพาะเกมปัจจุบัน)
 | 
			
		||||
 | 
			
		||||
STR_CONFIG_SETTING_RESTRICT_CATEGORY                            :{BLACK}หมวดหมู่:
 | 
			
		||||
STR_CONFIG_SETTING_RESTRICT_TYPE                                :{BLACK}ชนิด:
 | 
			
		||||
STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT                   :{BLACK}จำกัดรายการด้านล่างให้แสดงเฉพาะการตั้งค่าที่มีการเปลี่ยนแปลง
 | 
			
		||||
STR_CONFIG_SETTING_RESTRICT_BASIC                               :ตั้งค่าพื้นฐาน
 | 
			
		||||
STR_CONFIG_SETTING_RESTRICT_ADVANCED                            :ตั้งค่าขั้นสูง
 | 
			
		||||
@@ -1270,6 +1273,7 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT               :โรงกล
 | 
			
		||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT                              :ระดับความสูงแนวหิมะ: {STRING}
 | 
			
		||||
STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT                     :ควบคุมความสูงเริ่มต้นของหิมะบนพื้นภูมิทัศน์อาร์ติคย่อยๆ, หิมะยังมีผลการสร้างอุตสาหกรรม และการเติบโตของเมือง
 | 
			
		||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN                         :ความหยาบของพื้นที่ (เฉพาะ TerraGenesis): {STRING}
 | 
			
		||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT                :(TerraGenesis only) Choose the frequency of hills: Smooth landscapes have fewer, more wide-spread hills. Rough landscapes have many hills, which may look repetitive
 | 
			
		||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH             :ราบเรียบมาก
 | 
			
		||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH                  :ราบเรียบ
 | 
			
		||||
STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH                   :หยาบ
 | 
			
		||||
@@ -1626,6 +1630,7 @@ STR_CONFIG_SETTING_SOUND                                        :{ORANGE}เส
 | 
			
		||||
STR_CONFIG_SETTING_INTERFACE                                    :{ORANGE}ส่วนเชื่อมต่อผู้ใช้
 | 
			
		||||
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION                       :{ORANGE}การก่อสร้าง
 | 
			
		||||
STR_CONFIG_SETTING_VEHICLES                                     :{ORANGE}ยานพาหนะ
 | 
			
		||||
STR_CONFIG_SETTING_VEHICLES_PHYSICS                             :กายภาพ
 | 
			
		||||
STR_CONFIG_SETTING_VEHICLES_ROUTING                             :{ORANGE}การค้นหาเส้นทางของพาหนะ
 | 
			
		||||
STR_CONFIG_SETTING_ENVIRONMENT                                  :{ORANGE}สิ่งแวดล้อม
 | 
			
		||||
STR_CONFIG_SETTING_ENVIRONMENT_TOWNS                            :{ORANGE}เมือง
 | 
			
		||||
@@ -1701,6 +1706,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE                             :{BLACK}เล
 | 
			
		||||
 | 
			
		||||
STR_INTRO_TOOLTIP_GAME_OPTIONS                                  :{BLACK}แสดงตัวเลือกเกม
 | 
			
		||||
STR_INTRO_TOOLTIP_HIGHSCORE                                     :{BLACK}แสดงตารางคะแนนสูงสุด
 | 
			
		||||
STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE                          :{BLACK}การตั้งค่า หน้าจอ
 | 
			
		||||
STR_INTRO_TOOLTIP_NEWGRF_SETTINGS                               :{BLACK}แสดงการกำหนดค่า NewGRF
 | 
			
		||||
STR_INTRO_TOOLTIP_ONLINE_CONTENT                                :{BLACK}ตรวจสอบเนื้อหาใหม่และการปรับปรุงสำหรับดาวโหลด
 | 
			
		||||
STR_INTRO_TOOLTIP_SCRIPT_SETTINGS                               :{BLACK}แสดงการตั้งค่า AI/Game script
 | 
			
		||||
@@ -2663,6 +2669,7 @@ STR_MAPGEN_BY                                                   :{BLACK}*
 | 
			
		||||
STR_MAPGEN_NUMBER_OF_TOWNS                                      :{BLACK}จำนวนเมือง
 | 
			
		||||
STR_MAPGEN_DATE                                                 :{BLACK}วันที่:
 | 
			
		||||
STR_MAPGEN_NUMBER_OF_INDUSTRIES                                 :{BLACK}จำนวนอุตสาหกรรม:
 | 
			
		||||
STR_MAPGEN_MAX_HEIGHTLEVEL                                      :{BLACK}ขนาดความสูงของแผนที่สูงสุด:
 | 
			
		||||
STR_MAPGEN_SNOW_LINE_HEIGHT                                     :{BLACK}เส้นความสูงเขตหิมะ:
 | 
			
		||||
STR_MAPGEN_SNOW_LINE_UP                                         :{BLACK}ปรับเปลี่ยนความสูงของหิมะขึ้นไป 1 ระดับ
 | 
			
		||||
STR_MAPGEN_SNOW_LINE_DOWN                                       :{BLACK}ปรับเปลี่ยนความสูงของหิมะลงมา 1 ระดับ
 | 
			
		||||
@@ -2773,6 +2780,7 @@ STR_NEWGRF_SETTINGS_DISABLED                                    :{RED}ไม่
 | 
			
		||||
STR_NEWGRF_SETTINGS_INCOMPATIBLE                                :{RED}ไม่รองรับกับ OpenTTD เวอร์ชั่นนี้
 | 
			
		||||
 | 
			
		||||
# NewGRF save preset window
 | 
			
		||||
STR_SAVE_PRESET_SAVE_TOOLTIP                                    :บันทึก ชุดการตั้งค่า ตามที่ได้เลือกไว้
 | 
			
		||||
 | 
			
		||||
# NewGRF parameters window
 | 
			
		||||
STR_NEWGRF_PARAMETERS_CAPTION                                   :{WHITE}เปลี่ยนแปลง NewGRF parameters
 | 
			
		||||
@@ -3342,10 +3350,12 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP                     :{BLACK}เป
 | 
			
		||||
STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP                             :{BLACK}เปลี่ยนชื่อชนิดของเรือ
 | 
			
		||||
STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP                         :{BLACK}เปลี่ยนชื่อชนิดของเครื่องบิน
 | 
			
		||||
 | 
			
		||||
STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON                     :ซ่อน
 | 
			
		||||
 | 
			
		||||
STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON                        :{BLACK}การแสดงผล
 | 
			
		||||
STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON                 :{BLACK}การแสดงผล
 | 
			
		||||
 | 
			
		||||
STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP               :{BLACK}ปรับเปลี่ยน ซ่อน/แสดง ของชนิดเครื่องอากาศยาน
 | 
			
		||||
 | 
			
		||||
STR_QUERY_RENAME_TRAIN_TYPE_CAPTION                             :{WHITE}เปลี่ยนชื่อชนิดของรถไฟ
 | 
			
		||||
STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION                      :{WHITE}เปลี่ยนชื่อชนิดของรถ
 | 
			
		||||
@@ -3451,6 +3461,7 @@ STR_REPLACE_VEHICLE_ROAD_VEHICLE                                :ยานพา
 | 
			
		||||
STR_REPLACE_VEHICLE_SHIP                                        :ยานพาหนะทางน้ำ
 | 
			
		||||
STR_REPLACE_VEHICLE_AIRCRAFT                                    :อากาศยาน
 | 
			
		||||
 | 
			
		||||
STR_REPLACE_VEHICLE_VEHICLES_IN_USE                             :{YELLOW}พาหนะถูกใช้งานอยู่
 | 
			
		||||
 | 
			
		||||
STR_REPLACE_HELP_LEFT_ARRAY                                     :{BLACK}เลือกประเภทของรถจักรที่จะแทนที่
 | 
			
		||||
STR_REPLACE_HELP_RIGHT_ARRAY                                    :{BLACK}เลือกประเภทของพาหนะที่จะแทนที่ทางซ้ายมือ
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,10 @@
 | 
			
		||||
 | 
			
		||||
#include "../safeguards.h"
 | 
			
		||||
 | 
			
		||||
#if !defined(HAVE_OSX_1011_SDK)
 | 
			
		||||
#define kMusicSequenceFile_AnyType 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static FMusicDriver_Cocoa iFMusicDriver_Cocoa;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -68,7 +72,7 @@ static void DoSetVolume()
 | 
			
		||||
			 * risk compilation errors. The header AudioComponent.h
 | 
			
		||||
			 * was introduced in 10.6 so use it to decide which
 | 
			
		||||
			 * type definition to use. */
 | 
			
		||||
#ifdef __AUDIOCOMPONENT_H__
 | 
			
		||||
#if defined(__AUDIOCOMPONENT_H__) || defined(HAVE_OSX_107_SDK)
 | 
			
		||||
			AudioComponentDescription desc;
 | 
			
		||||
#else
 | 
			
		||||
			ComponentDescription desc;
 | 
			
		||||
@@ -159,7 +163,7 @@ void MusicDriver_Cocoa::PlaySong(const char *filename)
 | 
			
		||||
 | 
			
		||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
 | 
			
		||||
	if (MacOSVersionIsAtLeast(10, 5, 0)) {
 | 
			
		||||
		if (MusicSequenceFileLoad(_sequence, url, 0, 0) != noErr) {
 | 
			
		||||
		if (MusicSequenceFileLoad(_sequence, url, kMusicSequenceFile_AnyType, 0) != noErr) {
 | 
			
		||||
			DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file");
 | 
			
		||||
			CFRelease(url);
 | 
			
		||||
			return;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include "win32_m.h"
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <mmsystem.h>
 | 
			
		||||
#include "../os/windows/win32.h"
 | 
			
		||||
 | 
			
		||||
#include "../safeguards.h"
 | 
			
		||||
 | 
			
		||||
@@ -105,6 +106,8 @@ static bool MidiIntIsSongPlaying()
 | 
			
		||||
 | 
			
		||||
static DWORD WINAPI MidiThread(LPVOID arg)
 | 
			
		||||
{
 | 
			
		||||
	SetWin32ThreadName(-1, "ottd:win-midi");
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		char *s;
 | 
			
		||||
		int vol;
 | 
			
		||||
 
 | 
			
		||||
@@ -1029,17 +1029,29 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type)
 | 
			
		||||
void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK, image_type);
 | 
			
		||||
	const SpriteGroup *group = object.Resolve();
 | 
			
		||||
	if (group == NULL || group->GetNumResults() == 0) return 0;
 | 
			
		||||
	VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK);
 | 
			
		||||
	result->Clear();
 | 
			
		||||
 | 
			
		||||
	return group->GetResult() + (direction % group->GetNumResults());
 | 
			
		||||
	bool sprite_stack = HasBit(EngInfo(engine)->misc_flags, EF_SPRITE_STACK);
 | 
			
		||||
	uint max_stack = sprite_stack ? lengthof(result->seq) : 1;
 | 
			
		||||
	for (uint stack = 0; stack < max_stack; ++stack) {
 | 
			
		||||
		object.ResetState();
 | 
			
		||||
		object.callback_param1 = image_type | (stack << 8);
 | 
			
		||||
		const SpriteGroup *group = object.Resolve();
 | 
			
		||||
		uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0;
 | 
			
		||||
		if (group != NULL && group->GetNumResults() != 0) {
 | 
			
		||||
			result->seq[result->count].sprite = group->GetResult() + (direction % group->GetNumResults());
 | 
			
		||||
			result->seq[result->count].pal    = GB(reg100, 0, 16); // zero means default recolouring
 | 
			
		||||
			result->count++;
 | 
			
		||||
		}
 | 
			
		||||
		if (!HasBit(reg100, 31)) break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_view, EngineImageType image_type)
 | 
			
		||||
void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	const Engine *e = Engine::Get(engine);
 | 
			
		||||
 | 
			
		||||
@@ -1047,14 +1059,24 @@ SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_vi
 | 
			
		||||
	assert(e->type == VEH_AIRCRAFT);
 | 
			
		||||
	assert(!(e->u.air.subtype & AIR_CTOL));
 | 
			
		||||
 | 
			
		||||
	VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK, image_type);
 | 
			
		||||
	const SpriteGroup *group = object.Resolve();
 | 
			
		||||
	VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK);
 | 
			
		||||
	result->Clear();
 | 
			
		||||
	uint rotor_pos = v == NULL || info_view ? 0 : v->Next()->Next()->state;
 | 
			
		||||
 | 
			
		||||
	if (group == NULL || group->GetNumResults() == 0) return 0;
 | 
			
		||||
 | 
			
		||||
	if (v == NULL || info_view) return group->GetResult();
 | 
			
		||||
 | 
			
		||||
	return group->GetResult() + (v->Next()->Next()->state % group->GetNumResults());
 | 
			
		||||
	bool sprite_stack = HasBit(e->info.misc_flags, EF_SPRITE_STACK);
 | 
			
		||||
	uint max_stack = sprite_stack ? lengthof(result->seq) : 1;
 | 
			
		||||
	for (uint stack = 0; stack < max_stack; ++stack) {
 | 
			
		||||
		object.ResetState();
 | 
			
		||||
		object.callback_param1 = image_type | (stack << 8);
 | 
			
		||||
		const SpriteGroup *group = object.Resolve();
 | 
			
		||||
		uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0;
 | 
			
		||||
		if (group != NULL && group->GetNumResults() != 0) {
 | 
			
		||||
			result->seq[result->count].sprite = group->GetResult() + (rotor_pos % group->GetNumResults());
 | 
			
		||||
			result->seq[result->count].pal    = GB(reg100, 0, 16); // zero means default recolouring
 | 
			
		||||
			result->count++;
 | 
			
		||||
		}
 | 
			
		||||
		if (!HasBit(reg100, 31)) break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -64,13 +64,19 @@ static const uint TRAININFO_DEFAULT_VEHICLE_WIDTH   = 29;
 | 
			
		||||
static const uint ROADVEHINFO_DEFAULT_VEHICLE_WIDTH = 32;
 | 
			
		||||
static const uint VEHICLEINFO_FULL_VEHICLE_WIDTH    = 32;
 | 
			
		||||
 | 
			
		||||
struct VehicleSpriteSeq;
 | 
			
		||||
 | 
			
		||||
void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const struct SpriteGroup *group, EngineID *train_id, uint trains);
 | 
			
		||||
const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine);
 | 
			
		||||
void SetCustomEngineSprites(EngineID engine, byte cargo, const struct SpriteGroup *group);
 | 
			
		||||
SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type);
 | 
			
		||||
SpriteID GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type);
 | 
			
		||||
#define GetCustomRotorSprite(v, i, image_type) GetRotorOverrideSprite(v->engine_type, v, i, image_type)
 | 
			
		||||
#define GetCustomRotorIcon(et, image_type) GetRotorOverrideSprite(et, NULL, true, image_type)
 | 
			
		||||
 | 
			
		||||
void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result);
 | 
			
		||||
#define GetCustomVehicleSprite(v, direction, image_type, result) GetCustomEngineSprite(v->engine_type, v, direction, image_type, result)
 | 
			
		||||
#define GetCustomVehicleIcon(et, direction, image_type, result) GetCustomEngineSprite(et, NULL, direction, image_type, result)
 | 
			
		||||
 | 
			
		||||
void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type, VehicleSpriteSeq *result);
 | 
			
		||||
#define GetCustomRotorSprite(v, i, image_type, result) GetRotorOverrideSprite(v->engine_type, v, i, image_type, result)
 | 
			
		||||
#define GetCustomRotorIcon(et, image_type, result) GetRotorOverrideSprite(et, NULL, true, image_type, result)
 | 
			
		||||
 | 
			
		||||
/* Forward declaration of GRFFile, to avoid unnecessary inclusion of newgrf.h
 | 
			
		||||
 * elsewhere... */
 | 
			
		||||
@@ -81,8 +87,6 @@ void SetEngineGRF(EngineID engine, const struct GRFFile *file);
 | 
			
		||||
uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v);
 | 
			
		||||
uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent);
 | 
			
		||||
bool UsesWagonOverride(const Vehicle *v);
 | 
			
		||||
#define GetCustomVehicleSprite(v, direction, image_type) GetCustomEngineSprite(v->engine_type, v, direction, image_type)
 | 
			
		||||
#define GetCustomVehicleIcon(et, direction, image_type) GetCustomEngineSprite(et, NULL, direction, image_type)
 | 
			
		||||
 | 
			
		||||
/* Handler to Evaluate callback 36. If the callback fails (i.e. most of the
 | 
			
		||||
 * time) orig_value is returned */
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,17 @@
 | 
			
		||||
#define MACOS_STDAFX_H
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <AvailabilityMacros.h>
 | 
			
		||||
 | 
			
		||||
/* We assume if these macros are defined, the SDK is also at least this version or later. */
 | 
			
		||||
#ifdef MAC_OS_X_VERSION_10_7
 | 
			
		||||
#define HAVE_OSX_107_SDK
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef MAC_OS_X_VERSION_10_11
 | 
			
		||||
#define HAVE_OSX_1011_SDK
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* It would seem that to ensure backward compability we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */
 | 
			
		||||
#ifndef MAC_OS_X_VERSION_10_3
 | 
			
		||||
#define MAC_OS_X_VERSION_10_3 1030
 | 
			
		||||
@@ -57,8 +68,6 @@
 | 
			
		||||
#	error "Compiling 64 bits without _SQ64 set! (or vice versa)"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <AvailabilityMacros.h>
 | 
			
		||||
 | 
			
		||||
/* Name conflict */
 | 
			
		||||
#define Rect        OTTDRect
 | 
			
		||||
#define Point       OTTDPoint
 | 
			
		||||
 
 | 
			
		||||
@@ -785,3 +785,36 @@ uint GetCPUCoreCount()
 | 
			
		||||
	GetSystemInfo(&info);
 | 
			
		||||
	return info.dwNumberOfProcessors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
/* Code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
 | 
			
		||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
 | 
			
		||||
#pragma pack(push,8)
 | 
			
		||||
typedef struct {
 | 
			
		||||
	DWORD dwType;     ///< Must be 0x1000.
 | 
			
		||||
	LPCSTR szName;    ///< Pointer to name (in user addr space).
 | 
			
		||||
	DWORD dwThreadID; ///< Thread ID (-1=caller thread).
 | 
			
		||||
	DWORD dwFlags;    ///< Reserved for future use, must be zero.
 | 
			
		||||
} THREADNAME_INFO;
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Signal thread name to any attached debuggers.
 | 
			
		||||
 */
 | 
			
		||||
void SetWin32ThreadName(DWORD dwThreadID, const char* threadName)
 | 
			
		||||
{
 | 
			
		||||
	THREADNAME_INFO info;
 | 
			
		||||
	info.dwType = 0x1000;
 | 
			
		||||
	info.szName = threadName;
 | 
			
		||||
	info.dwThreadID = dwThreadID;
 | 
			
		||||
	info.dwFlags = 0;
 | 
			
		||||
 | 
			
		||||
#pragma warning(push)
 | 
			
		||||
#pragma warning(disable: 6320 6322)
 | 
			
		||||
	__try {
 | 
			
		||||
		RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
 | 
			
		||||
	} __except (EXCEPTION_EXECUTE_HANDLER) {
 | 
			
		||||
	}
 | 
			
		||||
#pragma warning(pop)
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -39,4 +39,10 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);
 | 
			
		||||
#define SHGFP_TYPE_CURRENT 0
 | 
			
		||||
#endif /* __MINGW32__ */
 | 
			
		||||
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
void SetWin32ThreadName(DWORD dwThreadID, const char* threadName);
 | 
			
		||||
#else
 | 
			
		||||
static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* WIN32_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ struct RoadVehicle FINAL : public GroundVehicle<RoadVehicle, VEH_ROAD> {
 | 
			
		||||
	void UpdateDeltaXY(Direction direction);
 | 
			
		||||
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_ROADVEH_INC : EXPENSES_ROADVEH_RUN; }
 | 
			
		||||
	bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
 | 
			
		||||
	SpriteID GetImage(Direction direction, EngineImageType image_type) const;
 | 
			
		||||
	void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const;
 | 
			
		||||
	int GetDisplaySpeed() const { return this->gcache.last_speed / 2; }
 | 
			
		||||
	int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; }
 | 
			
		||||
	Money GetRunningCost() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -114,40 +114,39 @@ int RoadVehicle::GetDisplayImageWidth(Point *offset) const
 | 
			
		||||
	return ScaleGUITrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpriteID GetRoadVehIcon(EngineID engine, EngineImageType image_type)
 | 
			
		||||
static void GetRoadVehIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	const Engine *e = Engine::Get(engine);
 | 
			
		||||
	uint8 spritenum = e->u.road.image_index;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleIcon(engine, DIR_W, image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = e->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_ROAD>(spritenum));
 | 
			
		||||
	return DIR_W + _roadveh_images[spritenum];
 | 
			
		||||
	result->Set(DIR_W + _roadveh_images[spritenum]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpriteID RoadVehicle::GetImage(Direction direction, EngineImageType image_type) const
 | 
			
		||||
void RoadVehicle::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
 | 
			
		||||
{
 | 
			
		||||
	uint8 spritenum = this->spritenum;
 | 
			
		||||
	SpriteID sprite;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = this->GetEngine()->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_ROAD>(spritenum));
 | 
			
		||||
	sprite = direction + _roadveh_images[spritenum];
 | 
			
		||||
	SpriteID sprite = direction + _roadveh_images[spritenum];
 | 
			
		||||
 | 
			
		||||
	if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
 | 
			
		||||
 | 
			
		||||
	return sprite;
 | 
			
		||||
	result->Set(sprite);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -161,12 +160,16 @@ SpriteID RoadVehicle::GetImage(Direction direction, EngineImageType image_type)
 | 
			
		||||
 */
 | 
			
		||||
void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
 | 
			
		||||
{
 | 
			
		||||
	SpriteID sprite = GetRoadVehIcon(engine, image_type);
 | 
			
		||||
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetRoadVehIcon(engine, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
	preferred_x = Clamp(preferred_x,
 | 
			
		||||
			left - UnScaleGUI(real_sprite->x_offs),
 | 
			
		||||
			right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs));
 | 
			
		||||
	DrawSprite(sprite, pal, preferred_x, y);
 | 
			
		||||
			left - UnScaleGUI(rect.left),
 | 
			
		||||
			right - UnScaleGUI(rect.right));
 | 
			
		||||
 | 
			
		||||
	seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -180,12 +183,16 @@ void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID eng
 | 
			
		||||
 */
 | 
			
		||||
void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
 | 
			
		||||
{
 | 
			
		||||
	const Sprite *spr = GetSprite(GetRoadVehIcon(engine, image_type), ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetRoadVehIcon(engine, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(spr->width);
 | 
			
		||||
	height = UnScaleGUI(spr->height);
 | 
			
		||||
	xoffs  = UnScaleGUI(spr->x_offs);
 | 
			
		||||
	yoffs  = UnScaleGUI(spr->y_offs);
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(rect.right - rect.left + 1);
 | 
			
		||||
	height = UnScaleGUI(rect.bottom - rect.top + 1);
 | 
			
		||||
	xoffs  = UnScaleGUI(rect.left);
 | 
			
		||||
	yoffs  = UnScaleGUI(rect.top);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -308,7 +315,7 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin
 | 
			
		||||
		v->date_of_last_service = _date;
 | 
			
		||||
		v->build_year = _cur_year;
 | 
			
		||||
 | 
			
		||||
		v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
		v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
		v->random_bits = VehicleRandomBits();
 | 
			
		||||
		v->SetFrontEngine();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -149,7 +149,9 @@ void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID se
 | 
			
		||||
 | 
			
		||||
		if (rtl ? px + width > 0 : px - width < max_width) {
 | 
			
		||||
			PaletteID pal = (u->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(u);
 | 
			
		||||
			DrawSprite(u->GetImage(dir, image_type), pal, px + (rtl ? -offset.x : offset.x), ScaleGUITrad(6) + offset.y);
 | 
			
		||||
			VehicleSpriteSeq seq;
 | 
			
		||||
			u->GetImage(dir, image_type, &seq);
 | 
			
		||||
			seq.Draw(px + (rtl ? -offset.x : offset.x), ScaleGUITrad(6) + offset.y, pal, u->vehstatus & VS_CRASHED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		px += rtl ? -width : width;
 | 
			
		||||
 
 | 
			
		||||
@@ -68,11 +68,10 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
 | 
			
		||||
	{ XSLFI_REVERSE_AT_WAYPOINT,    XSCF_NULL,                1,   1, "reverse_at_waypoint",       NULL, NULL, NULL        },
 | 
			
		||||
	{ XSLFI_VEH_LIFETIME_PROFIT,    XSCF_NULL,                1,   1, "veh_lifetime_profit",       NULL, NULL, NULL        },
 | 
			
		||||
	{ XSLFI_LINKGRAPH_DAY_SCALE,    XSCF_NULL,                1,   1, "linkgraph_day_scale",       NULL, NULL, NULL        },
 | 
			
		||||
	{ XSLFI_TEMPLATE_REPLACEMENT,   XSCF_NULL,                1,   1, "template_replacement",      NULL, NULL, "TRPL,TMPL" },
 | 
			
		||||
	{ XSLFI_TEMPLATE_REPLACEMENT,   XSCF_NULL,                2,   2, "template_replacement",      NULL, NULL, "TRPL,TMPL" },
 | 
			
		||||
	{ XSLFI_MORE_RAIL_TYPES,        XSCF_NULL,                1,   1, "more_rail_types",           NULL, NULL, NULL        },
 | 
			
		||||
	{ XSLFI_CARGO_TYPE_ORDERS,      XSCF_NULL,                2,   2, "cargo_type_orders",         NULL, NULL, "ORDX,VEOX" },
 | 
			
		||||
	{ XSLFI_EXTENDED_GAMELOG,       XSCF_NULL,                1,   1, "extended_gamelog",          NULL, NULL, NULL        },
 | 
			
		||||
 | 
			
		||||
	{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1165,7 +1165,7 @@ static const OldChunks vehicle_chunk[] = {
 | 
			
		||||
 | 
			
		||||
	OCL_SVAR(  OC_UINT8, Vehicle, owner ),
 | 
			
		||||
	OCL_SVAR(   OC_TILE, Vehicle, tile ),
 | 
			
		||||
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, cur_image ),
 | 
			
		||||
	OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, sprite_seq.seq[0].sprite ),
 | 
			
		||||
 | 
			
		||||
	OCL_NULL( 8 ),        ///< Vehicle sprite box, calculated automatically
 | 
			
		||||
 | 
			
		||||
@@ -1258,7 +1258,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num)
 | 
			
		||||
			if (v == NULL) continue;
 | 
			
		||||
			v->refit_cap = v->cargo_cap;
 | 
			
		||||
 | 
			
		||||
			SpriteID sprite = v->cur_image;
 | 
			
		||||
			SpriteID sprite = v->sprite_seq.seq[0].sprite;
 | 
			
		||||
			/* no need to override other sprites */
 | 
			
		||||
			if (IsInsideMM(sprite, 1460, 1465)) {
 | 
			
		||||
				sprite += 580; // aircraft smoke puff
 | 
			
		||||
@@ -1269,7 +1269,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num)
 | 
			
		||||
			} else if (IsInsideMM(sprite, 2516, 2539)) {
 | 
			
		||||
				sprite += 1385; // rotor or disaster-related vehicles
 | 
			
		||||
			}
 | 
			
		||||
			v->cur_image = sprite;
 | 
			
		||||
			v->sprite_seq.seq[0].sprite = sprite;
 | 
			
		||||
 | 
			
		||||
			switch (v->type) {
 | 
			
		||||
				case VEH_TRAIN: {
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,9 @@ const SaveLoad* GTD() {
 | 
			
		||||
		SLE_VAR(TemplateVehicle, max_te, SLE_UINT32),
 | 
			
		||||
 | 
			
		||||
		SLE_VAR(TemplateVehicle, spritenum, SLE_UINT8),
 | 
			
		||||
		SLE_VAR(TemplateVehicle, cur_image, SLE_UINT32),
 | 
			
		||||
		SLE_CONDVAR_X(TemplateVehicle, sprite_seq.seq[0].sprite, SLE_UINT32, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 1)),
 | 
			
		||||
		SLE_CONDVAR_X(TemplateVehicle, sprite_seq.count, SLE_UINT32, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2)),
 | 
			
		||||
		SLE_CONDARR_X(TemplateVehicle, sprite_seq.seq, SLE_UINT32, 8, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2)),
 | 
			
		||||
		SLE_VAR(TemplateVehicle, image_width, SLE_UINT32),
 | 
			
		||||
 | 
			
		||||
		SLE_END()
 | 
			
		||||
@@ -123,7 +125,7 @@ void AfterLoadTemplateVehiclesUpdateImage()
 | 
			
		||||
					Train *v = t;
 | 
			
		||||
					for (TemplateVehicle *u = tv; u != NULL; u = u->Next(), v = v->Next()) {
 | 
			
		||||
						u->spritenum = v->spritenum;
 | 
			
		||||
						u->cur_image = v->GetImage(DIR_W, EIT_PURCHASE);
 | 
			
		||||
						v->GetImage(DIR_W, EIT_PURCHASE, &u->sprite_seq);
 | 
			
		||||
						u->image_width = v->GetDisplayImageWidth();
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -456,21 +456,21 @@ void AfterLoadVehicles(bool part_of_load)
 | 
			
		||||
 | 
			
		||||
			case VEH_TRAIN:
 | 
			
		||||
			case VEH_SHIP:
 | 
			
		||||
				v->cur_image = v->GetImage(v->direction, EIT_ON_MAP);
 | 
			
		||||
				v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case VEH_AIRCRAFT:
 | 
			
		||||
				if (Aircraft::From(v)->IsNormalAircraft()) {
 | 
			
		||||
					v->cur_image = v->GetImage(v->direction, EIT_ON_MAP);
 | 
			
		||||
					v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq);
 | 
			
		||||
 | 
			
		||||
					/* The plane's shadow will have the same image as the plane */
 | 
			
		||||
					/* The plane's shadow will have the same image as the plane, but no colour */
 | 
			
		||||
					Vehicle *shadow = v->Next();
 | 
			
		||||
					shadow->cur_image = v->cur_image;
 | 
			
		||||
					shadow->sprite_seq.CopyWithoutPalette(v->sprite_seq);
 | 
			
		||||
 | 
			
		||||
					/* In the case of a helicopter we will update the rotor sprites */
 | 
			
		||||
					if (v->subtype == AIR_HELICOPTER) {
 | 
			
		||||
						Vehicle *rotor = shadow->Next();
 | 
			
		||||
						rotor->cur_image = GetRotorImage(Aircraft::From(v), EIT_ON_MAP);
 | 
			
		||||
						GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_seq);
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					UpdateAircraftCache(Aircraft::From(v), true);
 | 
			
		||||
@@ -839,7 +839,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
 | 
			
		||||
		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_FILE_U8  | SLE_VAR_I32,   0, 163),
 | 
			
		||||
		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_INT32,                  164, SL_MAX_VERSION),
 | 
			
		||||
 | 
			
		||||
		     SLE_VAR(Vehicle, cur_image,             SLE_FILE_U16 | SLE_VAR_U32),
 | 
			
		||||
		     SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
 | 
			
		||||
		SLE_CONDNULL(5,                                                            0,  57),
 | 
			
		||||
		     SLE_VAR(Vehicle, progress,              SLE_UINT8),
 | 
			
		||||
		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
 | 
			
		||||
@@ -879,7 +879,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt)
 | 
			
		||||
		 SLE_CONDVAR(Vehicle, current_order.dest,    SLE_FILE_U8 | SLE_VAR_U16,    0,   4),
 | 
			
		||||
		 SLE_CONDVAR(Vehicle, current_order.dest,    SLE_UINT16,                   5, SL_MAX_VERSION),
 | 
			
		||||
 | 
			
		||||
		     SLE_VAR(Vehicle, cur_image,             SLE_FILE_U16 | SLE_VAR_U32),
 | 
			
		||||
		     SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
 | 
			
		||||
		 SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   0,  30),
 | 
			
		||||
		 SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   31, SL_MAX_VERSION),
 | 
			
		||||
		     SLE_VAR(Vehicle, tick_counter,          SLE_UINT8),
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@ struct Ship FINAL : public SpecializedVehicle<Ship, VEH_SHIP> {
 | 
			
		||||
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_SHIP_INC : EXPENSES_SHIP_RUN; }
 | 
			
		||||
	void PlayLeaveStationSound() const;
 | 
			
		||||
	bool IsPrimaryVehicle() const { return true; }
 | 
			
		||||
	SpriteID GetImage(Direction direction, EngineImageType image_type) const;
 | 
			
		||||
	void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const;
 | 
			
		||||
	int GetDisplaySpeed() const { return this->cur_speed / 2; }
 | 
			
		||||
	int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; }
 | 
			
		||||
	int GetCurrentMaxSpeed() const { return min(this->vcache.cached_max_speed, this->current_order.GetMaxSpeed() * 2); }
 | 
			
		||||
 
 | 
			
		||||
@@ -71,30 +71,34 @@ static inline TrackBits GetTileShipTrackStatus(TileIndex tile)
 | 
			
		||||
	return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpriteID GetShipIcon(EngineID engine, EngineImageType image_type)
 | 
			
		||||
static void GetShipIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	const Engine *e = Engine::Get(engine);
 | 
			
		||||
	uint8 spritenum = e->u.ship.image_index;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleIcon(engine, DIR_W, image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = e->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_SHIP>(spritenum));
 | 
			
		||||
	return DIR_W + _ship_sprites[spritenum];
 | 
			
		||||
	result->Set(DIR_W + _ship_sprites[spritenum]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
 | 
			
		||||
{
 | 
			
		||||
	SpriteID sprite = GetShipIcon(engine, image_type);
 | 
			
		||||
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetShipIcon(engine, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
	preferred_x = Clamp(preferred_x,
 | 
			
		||||
			left - UnScaleGUI(real_sprite->x_offs),
 | 
			
		||||
			right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs));
 | 
			
		||||
	DrawSprite(sprite, pal, preferred_x, y);
 | 
			
		||||
			left - UnScaleGUI(rect.left),
 | 
			
		||||
			right - UnScaleGUI(rect.right));
 | 
			
		||||
 | 
			
		||||
	seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -108,27 +112,31 @@ void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine
 | 
			
		||||
 */
 | 
			
		||||
void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
 | 
			
		||||
{
 | 
			
		||||
	const Sprite *spr = GetSprite(GetShipIcon(engine, image_type), ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetShipIcon(engine, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(spr->width);
 | 
			
		||||
	height = UnScaleGUI(spr->height);
 | 
			
		||||
	xoffs  = UnScaleGUI(spr->x_offs);
 | 
			
		||||
	yoffs  = UnScaleGUI(spr->y_offs);
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(rect.right - rect.left + 1);
 | 
			
		||||
	height = UnScaleGUI(rect.bottom - rect.top + 1);
 | 
			
		||||
	xoffs  = UnScaleGUI(rect.left);
 | 
			
		||||
	yoffs  = UnScaleGUI(rect.top);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpriteID Ship::GetImage(Direction direction, EngineImageType image_type) const
 | 
			
		||||
void Ship::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
 | 
			
		||||
{
 | 
			
		||||
	uint8 spritenum = this->spritenum;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleSprite(this, direction, image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = this->GetEngine()->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_SHIP>(spritenum));
 | 
			
		||||
	return _ship_sprites[spritenum] + direction;
 | 
			
		||||
	result->Set(_ship_sprites[spritenum] + direction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance)
 | 
			
		||||
@@ -769,7 +777,7 @@ CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, u
 | 
			
		||||
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_ships);
 | 
			
		||||
		v->date_of_last_service = _date;
 | 
			
		||||
		v->build_year = _cur_year;
 | 
			
		||||
		v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
		v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
		v->random_bits = VehicleRandomBits();
 | 
			
		||||
 | 
			
		||||
		v->UpdateCache();
 | 
			
		||||
 
 | 
			
		||||
@@ -35,20 +35,23 @@ void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selec
 | 
			
		||||
{
 | 
			
		||||
	bool rtl = _current_text_dir == TD_RTL;
 | 
			
		||||
 | 
			
		||||
	SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type);
 | 
			
		||||
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	int width = UnScaleGUI(real_sprite->width);
 | 
			
		||||
	int x_offs = UnScaleGUI(real_sprite->x_offs);
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
	int width = UnScaleGUI(rect.right - rect.left + 1);
 | 
			
		||||
	int x_offs = UnScaleGUI(rect.left);
 | 
			
		||||
	int x = rtl ? right - width - x_offs : left - x_offs;
 | 
			
		||||
 | 
			
		||||
	y += ScaleGUITrad(10);
 | 
			
		||||
	DrawSprite(sprite, GetVehiclePalette(v), x, y);
 | 
			
		||||
	seq.Draw(x, y, GetVehiclePalette(v), false);
 | 
			
		||||
 | 
			
		||||
	if (v->index == selection) {
 | 
			
		||||
		x += x_offs;
 | 
			
		||||
		y += UnScaleGUI(real_sprite->y_offs);
 | 
			
		||||
		DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + 1, COLOUR_WHITE, FR_BORDERONLY);
 | 
			
		||||
		y += UnScaleGUI(rect.top);
 | 
			
		||||
		DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(rect.bottom - rect.top + 1) + 1, COLOUR_WHITE, FR_BORDERONLY);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include "win32_s.h"
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <mmsystem.h>
 | 
			
		||||
#include "../os/windows/win32.h"
 | 
			
		||||
 | 
			
		||||
#include "../safeguards.h"
 | 
			
		||||
 | 
			
		||||
@@ -41,6 +42,8 @@ static void PrepareHeader(WAVEHDR *hdr)
 | 
			
		||||
 | 
			
		||||
static DWORD WINAPI SoundThread(LPVOID arg)
 | 
			
		||||
{
 | 
			
		||||
	SetWin32ThreadName(-1, "ottd:win-sound");
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
 | 
			
		||||
			if ((hdr->dwFlags & WHDR_INQUEUE) != 0) continue;
 | 
			
		||||
 
 | 
			
		||||
@@ -64,7 +64,7 @@ TemplateVehicle::TemplateVehicle(VehicleType ty, EngineID eid, byte subtypeflag,
 | 
			
		||||
	this->previous = 0x0;
 | 
			
		||||
	this->owner_b = _current_company;
 | 
			
		||||
 | 
			
		||||
	this->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
	this->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
 | 
			
		||||
	this->owner = current_owner;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ public:
 | 
			
		||||
	uint32 max_te;
 | 
			
		||||
 | 
			
		||||
	byte spritenum;
 | 
			
		||||
	SpriteID cur_image;
 | 
			
		||||
	VehicleSpriteSeq sprite_seq;        ///< Vehicle appearance.
 | 
			
		||||
	uint32 image_width;
 | 
			
		||||
 | 
			
		||||
	TemplateVehicle(VehicleType type = VEH_INVALID, EngineID e = INVALID_ENGINE, byte B = 0, Owner = _local_company);
 | 
			
		||||
@@ -105,6 +105,7 @@ public:
 | 
			
		||||
		this->reuse_depot_vehicles = true;
 | 
			
		||||
		this->keep_remaining_vehicles = true;
 | 
			
		||||
		this->refit_as_template = true;
 | 
			
		||||
		this->sprite_seq.count = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~TemplateVehicle();
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,7 @@ void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y)
 | 
			
		||||
 | 
			
		||||
	while (t) {
 | 
			
		||||
		PaletteID pal = GetEnginePalette(t->engine_type, _current_company);
 | 
			
		||||
		DrawSprite(t->cur_image, pal, offset + t->image_width / 2, ScaleGUITrad(11));
 | 
			
		||||
		t->sprite_seq.Draw(offset + t->image_width / 2, ScaleGUITrad(11), pal, false);
 | 
			
		||||
 | 
			
		||||
		offset += t->image_width;
 | 
			
		||||
		t = t->Next();
 | 
			
		||||
@@ -167,7 +167,7 @@ inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicl
 | 
			
		||||
	tmp->max_te = gcache->cached_max_te / 1000;
 | 
			
		||||
 | 
			
		||||
	tmp->spritenum = virt->spritenum;
 | 
			
		||||
	tmp->cur_image = virt->GetImage(DIR_W, EIT_PURCHASE);
 | 
			
		||||
	virt->GetImage(DIR_W, EIT_PURCHASE, &tmp->sprite_seq);
 | 
			
		||||
	Point *p = new Point();
 | 
			
		||||
	tmp->image_width = virt->GetDisplayImageWidth(p);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <process.h>
 | 
			
		||||
#include "../os/windows/win32.h"
 | 
			
		||||
 | 
			
		||||
#include "../safeguards.h"
 | 
			
		||||
 | 
			
		||||
@@ -29,17 +30,19 @@ private:
 | 
			
		||||
	OTTDThreadFunc proc; ///< External thread procedure.
 | 
			
		||||
	void *param;         ///< Parameter for the external thread procedure.
 | 
			
		||||
	bool self_destruct;  ///< Free ourselves when done?
 | 
			
		||||
	const char *name;    ///< Thread name.
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	/**
 | 
			
		||||
	 * Create a win32 thread and start it, calling proc(param).
 | 
			
		||||
	 */
 | 
			
		||||
	ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct) :
 | 
			
		||||
	ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
 | 
			
		||||
		thread(NULL),
 | 
			
		||||
		id(0),
 | 
			
		||||
		proc(proc),
 | 
			
		||||
		param(param),
 | 
			
		||||
		self_destruct(self_destruct)
 | 
			
		||||
		self_destruct(self_destruct),
 | 
			
		||||
		name(name)
 | 
			
		||||
	{
 | 
			
		||||
		this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
 | 
			
		||||
		if (this->thread == NULL) return;
 | 
			
		||||
@@ -85,6 +88,10 @@ private:
 | 
			
		||||
	 */
 | 
			
		||||
	void ThreadProc()
 | 
			
		||||
	{
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
		/* Set thread name for debuggers. Has to be done from the thread due to a race condition in older MS debuggers. */
 | 
			
		||||
		SetWin32ThreadName(-1, this->name);
 | 
			
		||||
#endif
 | 
			
		||||
		try {
 | 
			
		||||
			this->proc(this->param);
 | 
			
		||||
		} catch (OTTDThreadExitSignal) {
 | 
			
		||||
@@ -98,7 +105,7 @@ private:
 | 
			
		||||
 | 
			
		||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL);
 | 
			
		||||
	ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL, name);
 | 
			
		||||
	if (thread != NULL) *thread = to;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1482,36 +1482,302 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
 | 
			
		||||
	{
 | 
			
		||||
		static const uint SMALLEST_ARRANGEMENT = 14;
 | 
			
		||||
		static const uint BIGGEST_ARRANGEMENT  = 20;
 | 
			
		||||
 | 
			
		||||
		/* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
 | 
			
		||||
		 * The total number of buttons should be equal to arrangable_count * 2.
 | 
			
		||||
		 * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a
 | 
			
		||||
		 * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is
 | 
			
		||||
		 * enough space.
 | 
			
		||||
		 */
 | 
			
		||||
		static const byte arrange14[] = {
 | 
			
		||||
			0,  1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29,
 | 
			
		||||
			2,  3,  4,  5,  6,  7,  8,  9, 12, 14, 26, 27, 28, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange15[] = {
 | 
			
		||||
			0,  1,  4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
 | 
			
		||||
			0,  2,  4,  3,  5,  6,  7,  8,  9, 12, 14, 26, 27, 28, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange16[] = {
 | 
			
		||||
			0,  1,  2,  4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
 | 
			
		||||
			0,  1,  3,  5,  6,  7,  8,  9, 12, 14, 26, 27, 28, 19, 20, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange17[] = {
 | 
			
		||||
			0,  1,  2,  4,  6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
 | 
			
		||||
			0,  1,  3,  4,  6,  5,  7,  8,  9, 12, 14, 26, 27, 28, 19, 20, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange18[] = {
 | 
			
		||||
			0,  1,  2,  4,  5,  6,  7,  8,  9, 14, 21, 22, 23, 24, 25, 19, 20, 29,
 | 
			
		||||
			0,  1,  3,  4,  5,  6,  7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange19[] = {
 | 
			
		||||
			0,  1,  2,  4,  5,  6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29,
 | 
			
		||||
			0,  1,  3,  4,  7,  8,  9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange20[] = {
 | 
			
		||||
			0,  1,  2,  4,  5,  6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29,
 | 
			
		||||
			0,  1,  3,  4,  7,  8,  9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29,
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_GOAL,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_STORY,
 | 
			
		||||
			WID_TN_HELP,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange_all[] = {
 | 
			
		||||
			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28
 | 
			
		||||
			WID_TN_PAUSE,
 | 
			
		||||
			WID_TN_FAST_FORWARD,
 | 
			
		||||
			WID_TN_SETTINGS,
 | 
			
		||||
			WID_TN_SAVE,
 | 
			
		||||
			WID_TN_SMALL_MAP,
 | 
			
		||||
			WID_TN_TOWNS,
 | 
			
		||||
			WID_TN_SUBSIDIES,
 | 
			
		||||
			WID_TN_STATIONS,
 | 
			
		||||
			WID_TN_FINANCES,
 | 
			
		||||
			WID_TN_COMPANIES,
 | 
			
		||||
			WID_TN_STORY,
 | 
			
		||||
			WID_TN_GOAL,
 | 
			
		||||
			WID_TN_GRAPHS,
 | 
			
		||||
			WID_TN_LEAGUE,
 | 
			
		||||
			WID_TN_INDUSTRIES,
 | 
			
		||||
			WID_TN_TRAINS,
 | 
			
		||||
			WID_TN_ROADVEHS,
 | 
			
		||||
			WID_TN_SHIPS,
 | 
			
		||||
			WID_TN_AIRCRAFTS,
 | 
			
		||||
			WID_TN_ZOOM_IN,
 | 
			
		||||
			WID_TN_ZOOM_OUT,
 | 
			
		||||
			WID_TN_RAILS,
 | 
			
		||||
			WID_TN_ROADS,
 | 
			
		||||
			WID_TN_WATER,
 | 
			
		||||
			WID_TN_AIR,
 | 
			
		||||
			WID_TN_LANDSCAPE,
 | 
			
		||||
			WID_TN_MUSIC_SOUND,
 | 
			
		||||
			WID_TN_MESSAGES,
 | 
			
		||||
			WID_TN_HELP
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
 | 
			
		||||
@@ -1553,14 +1819,65 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
 | 
			
		||||
	/* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
 | 
			
		||||
	{
 | 
			
		||||
		static const byte arrange_all[] = {
 | 
			
		||||
			0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
 | 
			
		||||
			WID_TE_PAUSE,
 | 
			
		||||
			WID_TE_FAST_FORWARD,
 | 
			
		||||
			WID_TE_SETTINGS,
 | 
			
		||||
			WID_TE_SAVE,
 | 
			
		||||
			WID_TE_SPACER,
 | 
			
		||||
			WID_TE_DATE_PANEL,
 | 
			
		||||
			WID_TE_SMALL_MAP,
 | 
			
		||||
			WID_TE_ZOOM_IN,
 | 
			
		||||
			WID_TE_ZOOM_OUT,
 | 
			
		||||
			WID_TE_LAND_GENERATE,
 | 
			
		||||
			WID_TE_TOWN_GENERATE,
 | 
			
		||||
			WID_TE_INDUSTRY,
 | 
			
		||||
			WID_TE_ROADS,
 | 
			
		||||
			WID_TE_WATER,
 | 
			
		||||
			WID_TE_TREES,
 | 
			
		||||
			WID_TE_SIGNS,
 | 
			
		||||
			WID_TE_MUSIC_SOUND,
 | 
			
		||||
			WID_TE_HELP,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange_nopanel[] = {
 | 
			
		||||
			0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
 | 
			
		||||
			WID_TE_PAUSE,
 | 
			
		||||
			WID_TE_FAST_FORWARD,
 | 
			
		||||
			WID_TE_SETTINGS,
 | 
			
		||||
			WID_TE_SAVE,
 | 
			
		||||
			WID_TE_DATE_PANEL,
 | 
			
		||||
			WID_TE_SMALL_MAP,
 | 
			
		||||
			WID_TE_ZOOM_IN,
 | 
			
		||||
			WID_TE_ZOOM_OUT,
 | 
			
		||||
			WID_TE_LAND_GENERATE,
 | 
			
		||||
			WID_TE_TOWN_GENERATE,
 | 
			
		||||
			WID_TE_INDUSTRY,
 | 
			
		||||
			WID_TE_ROADS,
 | 
			
		||||
			WID_TE_WATER,
 | 
			
		||||
			WID_TE_TREES,
 | 
			
		||||
			WID_TE_SIGNS,
 | 
			
		||||
			WID_TE_MUSIC_SOUND,
 | 
			
		||||
			WID_TE_HELP,
 | 
			
		||||
		};
 | 
			
		||||
		static const byte arrange_switch[] = {
 | 
			
		||||
			18,  8, 11, 12, 13, 14, 15, 16, 17, 29,
 | 
			
		||||
			 0,  1,  2,  3, 18,  9, 10, 26, 28, 29,
 | 
			
		||||
			WID_TE_DATE_PANEL,
 | 
			
		||||
			WID_TE_SMALL_MAP,
 | 
			
		||||
			WID_TE_LAND_GENERATE,
 | 
			
		||||
			WID_TE_TOWN_GENERATE,
 | 
			
		||||
			WID_TE_INDUSTRY,
 | 
			
		||||
			WID_TE_ROADS,
 | 
			
		||||
			WID_TE_WATER,
 | 
			
		||||
			WID_TE_TREES,
 | 
			
		||||
			WID_TE_SIGNS,
 | 
			
		||||
			WID_TE_SWITCH_BAR,
 | 
			
		||||
			// lower toolbar
 | 
			
		||||
			WID_TE_PAUSE,
 | 
			
		||||
			WID_TE_FAST_FORWARD,
 | 
			
		||||
			WID_TE_SETTINGS,
 | 
			
		||||
			WID_TE_SAVE,
 | 
			
		||||
			WID_TE_DATE_PANEL,
 | 
			
		||||
			WID_TE_ZOOM_IN,
 | 
			
		||||
			WID_TE_ZOOM_OUT,
 | 
			
		||||
			WID_TE_MUSIC_SOUND,
 | 
			
		||||
			WID_TE_HELP, WID_TE_SWITCH_BAR,
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		/* If we can place all buttons *and* the panels, show them. */
 | 
			
		||||
@@ -1917,7 +2234,14 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index)
 | 
			
		||||
	NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
 | 
			
		||||
	for (uint i = 0; i < WID_TN_END; i++) {
 | 
			
		||||
		switch (i) {
 | 
			
		||||
			case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break;
 | 
			
		||||
			case WID_TN_SMALL_MAP:
 | 
			
		||||
			case WID_TN_FINANCES:
 | 
			
		||||
			case WID_TN_VEHICLE_START:
 | 
			
		||||
			case WID_TN_ZOOM_IN:
 | 
			
		||||
			case WID_TN_BUILDING_TOOLS_START:
 | 
			
		||||
			case WID_TN_MUSIC_SOUND:
 | 
			
		||||
				hor->Add(new NWidgetSpacer(0, 0));
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
		hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i));
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,7 @@ struct Train FINAL : public GroundVehicle<Train, VEH_TRAIN> {
 | 
			
		||||
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
 | 
			
		||||
	void PlayLeaveStationSound() const;
 | 
			
		||||
	bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
 | 
			
		||||
	SpriteID GetImage(Direction direction, EngineImageType image_type) const;
 | 
			
		||||
	void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const;
 | 
			
		||||
	int GetDisplaySpeed() const { return this->gcache.last_speed; }
 | 
			
		||||
	int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; }
 | 
			
		||||
	Money GetRunningCost() const;
 | 
			
		||||
 
 | 
			
		||||
@@ -545,41 +545,40 @@ static SpriteID GetDefaultTrainSprite(uint8 spritenum, Direction direction)
 | 
			
		||||
 * @param image_type Visualisation context.
 | 
			
		||||
 * @return Sprite to display.
 | 
			
		||||
 */
 | 
			
		||||
SpriteID Train::GetImage(Direction direction, EngineImageType image_type) const
 | 
			
		||||
void Train::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
 | 
			
		||||
{
 | 
			
		||||
	uint8 spritenum = this->spritenum;
 | 
			
		||||
	SpriteID sprite;
 | 
			
		||||
 | 
			
		||||
	if (HasBit(this->flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type);
 | 
			
		||||
		if (sprite != 0) return sprite;
 | 
			
		||||
		GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result);
 | 
			
		||||
		if (result->IsValid()) return;
 | 
			
		||||
 | 
			
		||||
		spritenum = this->GetEngine()->original_image_index;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
 | 
			
		||||
	sprite = GetDefaultTrainSprite(spritenum, direction);
 | 
			
		||||
	SpriteID sprite = GetDefaultTrainSprite(spritenum, direction);
 | 
			
		||||
 | 
			
		||||
	if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
 | 
			
		||||
 | 
			
		||||
	return sprite;
 | 
			
		||||
	result->Set(sprite);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type)
 | 
			
		||||
static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type, VehicleSpriteSeq *result)
 | 
			
		||||
{
 | 
			
		||||
	const Engine *e = Engine::Get(engine);
 | 
			
		||||
	Direction dir = rear_head ? DIR_E : DIR_W;
 | 
			
		||||
	uint8 spritenum = e->u.rail.image_index;
 | 
			
		||||
 | 
			
		||||
	if (is_custom_sprite(spritenum)) {
 | 
			
		||||
		SpriteID sprite = GetCustomVehicleIcon(engine, dir, image_type);
 | 
			
		||||
		if (sprite != 0) {
 | 
			
		||||
		GetCustomVehicleIcon(engine, dir, image_type, result);
 | 
			
		||||
		if (result->IsValid()) {
 | 
			
		||||
			if (e->GetGRF() != NULL) {
 | 
			
		||||
				y += ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch);
 | 
			
		||||
			}
 | 
			
		||||
			return sprite;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		spritenum = Engine::Get(engine)->original_image_index;
 | 
			
		||||
@@ -587,7 +586,7 @@ static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImage
 | 
			
		||||
 | 
			
		||||
	if (rear_head) spritenum++;
 | 
			
		||||
 | 
			
		||||
	return GetDefaultTrainSprite(spritenum, DIR_W);
 | 
			
		||||
	result->Set(GetDefaultTrainSprite(spritenum, DIR_W));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
 | 
			
		||||
@@ -596,24 +595,31 @@ void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engin
 | 
			
		||||
		int yf = y;
 | 
			
		||||
		int yr = y;
 | 
			
		||||
 | 
			
		||||
		SpriteID spritef = GetRailIcon(engine, false, yf, image_type);
 | 
			
		||||
		SpriteID spriter = GetRailIcon(engine, true, yr, image_type);
 | 
			
		||||
		const Sprite *real_spritef = GetSprite(spritef, ST_NORMAL);
 | 
			
		||||
		const Sprite *real_spriter = GetSprite(spriter, ST_NORMAL);
 | 
			
		||||
		VehicleSpriteSeq seqf, seqr;
 | 
			
		||||
		GetRailIcon(engine, false, yf, image_type, &seqf);
 | 
			
		||||
		GetRailIcon(engine, true, yr, image_type, &seqr);
 | 
			
		||||
 | 
			
		||||
		Rect rectf, rectr;
 | 
			
		||||
		seqf.GetBounds(&rectf);
 | 
			
		||||
		seqr.GetBounds(&rectr);
 | 
			
		||||
 | 
			
		||||
		preferred_x = SoftClamp(preferred_x,
 | 
			
		||||
				left - UnScaleGUI(real_spritef->x_offs) + ScaleGUITrad(14),
 | 
			
		||||
				right - UnScaleGUI(real_spriter->width) - UnScaleGUI(real_spriter->x_offs) - ScaleGUITrad(15));
 | 
			
		||||
				left - UnScaleGUI(rectf.left) + ScaleGUITrad(14),
 | 
			
		||||
				right - UnScaleGUI(rectr.right) - ScaleGUITrad(15));
 | 
			
		||||
 | 
			
		||||
		DrawSprite(spritef, pal, preferred_x - ScaleGUITrad(14), yf);
 | 
			
		||||
		DrawSprite(spriter, pal, preferred_x + ScaleGUITrad(15), yr);
 | 
			
		||||
		seqf.Draw(preferred_x - ScaleGUITrad(14), yf, pal, pal == PALETTE_CRASH);
 | 
			
		||||
		seqr.Draw(preferred_x + ScaleGUITrad(15), yr, pal, pal == PALETTE_CRASH);
 | 
			
		||||
	} else {
 | 
			
		||||
		SpriteID sprite = GetRailIcon(engine, false, y, image_type);
 | 
			
		||||
		const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
		VehicleSpriteSeq seq;
 | 
			
		||||
		GetRailIcon(engine, false, y, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
		Rect rect;
 | 
			
		||||
		seq.GetBounds(&rect);
 | 
			
		||||
		preferred_x = Clamp(preferred_x,
 | 
			
		||||
				left - UnScaleGUI(real_sprite->x_offs),
 | 
			
		||||
				right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs));
 | 
			
		||||
		DrawSprite(sprite, pal, preferred_x, y);
 | 
			
		||||
				left - UnScaleGUI(rect.left),
 | 
			
		||||
				right - UnScaleGUI(rect.right));
 | 
			
		||||
 | 
			
		||||
		seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -630,23 +636,26 @@ void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs,
 | 
			
		||||
{
 | 
			
		||||
	int y = 0;
 | 
			
		||||
 | 
			
		||||
	SpriteID sprite = GetRailIcon(engine, false, y, image_type);
 | 
			
		||||
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
	VehicleSpriteSeq seq;
 | 
			
		||||
	GetRailIcon(engine, false, y, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(real_sprite->width);
 | 
			
		||||
	height = UnScaleGUI(real_sprite->height);
 | 
			
		||||
	xoffs  = UnScaleGUI(real_sprite->x_offs);
 | 
			
		||||
	yoffs  = UnScaleGUI(real_sprite->y_offs);
 | 
			
		||||
	Rect rect;
 | 
			
		||||
	seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
	width  = UnScaleGUI(rect.right - rect.left + 1);
 | 
			
		||||
	height = UnScaleGUI(rect.bottom - rect.top + 1);
 | 
			
		||||
	xoffs  = UnScaleGUI(rect.left);
 | 
			
		||||
	yoffs  = UnScaleGUI(rect.top);
 | 
			
		||||
 | 
			
		||||
	if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
 | 
			
		||||
		sprite = GetRailIcon(engine, true, y, image_type);
 | 
			
		||||
		real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
		GetRailIcon(engine, true, y, image_type, &seq);
 | 
			
		||||
		seq.GetBounds(&rect);
 | 
			
		||||
 | 
			
		||||
		/* Calculate values relative to an imaginary center between the two sprites. */
 | 
			
		||||
		width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(real_sprite->width) + UnScaleGUI(real_sprite->x_offs) - xoffs;
 | 
			
		||||
		height = max<uint>(height, UnScaleGUI(real_sprite->height));
 | 
			
		||||
		width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(rect.right) - xoffs;
 | 
			
		||||
		height = max<uint>(height, UnScaleGUI(rect.bottom - rect.top + 1));
 | 
			
		||||
		xoffs  = xoffs - ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2;
 | 
			
		||||
		yoffs  = min(yoffs, UnScaleGUI(real_sprite->y_offs));
 | 
			
		||||
		yoffs  = min(yoffs, UnScaleGUI(rect.top));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -702,7 +711,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
 | 
			
		||||
 | 
			
		||||
		v->date_of_last_service = _date;
 | 
			
		||||
		v->build_year = _cur_year;
 | 
			
		||||
		v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
		v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
		v->random_bits = VehicleRandomBits();
 | 
			
		||||
 | 
			
		||||
		v->group_id = DEFAULT_GROUP;
 | 
			
		||||
@@ -774,7 +783,7 @@ static void AddRearEngineToMultiheadedTrain(Train *v)
 | 
			
		||||
	u->reliability_spd_dec = v->reliability_spd_dec;
 | 
			
		||||
	u->date_of_last_service = v->date_of_last_service;
 | 
			
		||||
	u->build_year = v->build_year;
 | 
			
		||||
	u->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
	u->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
	u->random_bits = VehicleRandomBits();
 | 
			
		||||
	v->SetMultiheaded();
 | 
			
		||||
	u->SetMultiheaded();
 | 
			
		||||
@@ -841,7 +850,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
 | 
			
		||||
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
 | 
			
		||||
		v->date_of_last_service = _date;
 | 
			
		||||
		v->build_year = _cur_year;
 | 
			
		||||
		v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
		v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
		v->random_bits = VehicleRandomBits();
 | 
			
		||||
 | 
			
		||||
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 | 
			
		||||
@@ -4095,14 +4104,14 @@ static void ChangeTrainDirRandomly(Train *v)
 | 
			
		||||
		/* We don't need to twist around vehicles if they're not visible */
 | 
			
		||||
		if (!(v->vehstatus & VS_HIDDEN)) {
 | 
			
		||||
			v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
 | 
			
		||||
			v->UpdateDeltaXY(v->direction);
 | 
			
		||||
			v->cur_image = v->GetImage(v->direction, EIT_ON_MAP);
 | 
			
		||||
			/* Refrain from updating the z position of the vehicle when on
 | 
			
		||||
			 * a bridge, because UpdateInclination() will put the vehicle under
 | 
			
		||||
			 * the bridge in that case */
 | 
			
		||||
			if (v->track != TRACK_BIT_WORMHOLE) {
 | 
			
		||||
				v->UpdatePosition();
 | 
			
		||||
				v->UpdateInclination(false, false);
 | 
			
		||||
				v->UpdateInclination(false, true);
 | 
			
		||||
			} else {
 | 
			
		||||
				v->UpdateViewport(false, true);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} while ((v = v->Next()) != NULL);
 | 
			
		||||
@@ -4719,7 +4728,7 @@ Train* CmdBuildVirtualRailWagon(const Engine *e)
 | 
			
		||||
	v->railtype = rvi->railtype;
 | 
			
		||||
 | 
			
		||||
	v->build_year = _cur_year;
 | 
			
		||||
	v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
	v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
	v->random_bits = VehicleRandomBits();
 | 
			
		||||
 | 
			
		||||
	v->group_id = DEFAULT_GROUP;
 | 
			
		||||
@@ -4795,7 +4804,7 @@ Train* CmdBuildVirtualRailVehicle(EngineID eid, bool lax_engine_check, StringID
 | 
			
		||||
	v->railtype = rvi->railtype;
 | 
			
		||||
	_new_vehicle_id = v->index;
 | 
			
		||||
 | 
			
		||||
	v->cur_image = SPR_IMG_QUERY;
 | 
			
		||||
	v->sprite_seq.Set(SPR_IMG_QUERY);
 | 
			
		||||
	v->random_bits = VehicleRandomBits();
 | 
			
		||||
 | 
			
		||||
	v->group_id = DEFAULT_GROUP;
 | 
			
		||||
 
 | 
			
		||||
@@ -126,7 +126,9 @@ void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID select
 | 
			
		||||
 | 
			
		||||
		if (rtl ? px + width > 0 : px - width < max_width) {
 | 
			
		||||
			PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 | 
			
		||||
			DrawSprite(v->GetImage(dir, image_type), pal, px + (rtl ? -offset.x : offset.x), height / 2 + offset.y);
 | 
			
		||||
			VehicleSpriteSeq seq;
 | 
			
		||||
			v->GetImage(dir, image_type, &seq);
 | 
			
		||||
			seq.Draw(px + (rtl ? -offset.x : offset.x), height / 2 + offset.y, pal, v->vehstatus & VS_CRASHED);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!v->IsArticulatedPart()) sel_articulated = false;
 | 
			
		||||
@@ -440,7 +442,9 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po
 | 
			
		||||
						pitch = ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch);
 | 
			
		||||
					}
 | 
			
		||||
					PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 | 
			
		||||
					DrawSprite(u->GetImage(dir, EIT_IN_DETAILS), pal, px + (rtl ? -offset.x : offset.x), y - line_height * vscroll_pos + sprite_y_offset + pitch);
 | 
			
		||||
					VehicleSpriteSeq seq;
 | 
			
		||||
					u->GetImage(dir, EIT_IN_DETAILS, &seq);
 | 
			
		||||
					seq.Draw(px + (rtl ? -offset.x : offset.x), y - line_height * vscroll_pos + sprite_y_offset + pitch, pal, v->vehstatus & VS_CRASHED);
 | 
			
		||||
				}
 | 
			
		||||
				px += rtl ? -width : width;
 | 
			
		||||
				dx += width;
 | 
			
		||||
 
 | 
			
		||||
@@ -75,6 +75,47 @@ uint16 _returned_mail_refit_capacity; ///< Stores the mail capacity after a refi
 | 
			
		||||
VehiclePool _vehicle_pool("Vehicle");
 | 
			
		||||
INSTANTIATE_POOL_METHODS(Vehicle)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Determine shared bounds of all sprites.
 | 
			
		||||
 * @param [out] bounds Shared bounds.
 | 
			
		||||
 */
 | 
			
		||||
void VehicleSpriteSeq::GetBounds(Rect *bounds) const
 | 
			
		||||
{
 | 
			
		||||
	bounds->left = bounds->top = bounds->right = bounds->bottom = 0;
 | 
			
		||||
	for (uint i = 0; i < this->count; ++i) {
 | 
			
		||||
		const Sprite *spr = GetSprite(this->seq[i].sprite, ST_NORMAL);
 | 
			
		||||
		if (i == 0) {
 | 
			
		||||
			bounds->left = spr->x_offs;
 | 
			
		||||
			bounds->top  = spr->y_offs;
 | 
			
		||||
			bounds->right  = spr->width  + spr->x_offs - 1;
 | 
			
		||||
			bounds->bottom = spr->height + spr->y_offs - 1;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (spr->x_offs < bounds->left) bounds->left = spr->x_offs;
 | 
			
		||||
			if (spr->y_offs < bounds->top)  bounds->top  = spr->y_offs;
 | 
			
		||||
			int right  = spr->width  + spr->x_offs - 1;
 | 
			
		||||
			int bottom = spr->height + spr->y_offs - 1;
 | 
			
		||||
			if (right  > bounds->right)  bounds->right  = right;
 | 
			
		||||
			if (bottom > bounds->bottom) bounds->bottom = bottom;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Draw the sprite sequence.
 | 
			
		||||
 * @param x X position
 | 
			
		||||
 * @param y Y position
 | 
			
		||||
 * @param default_pal Vehicle palette
 | 
			
		||||
 * @param force_pal Whether to ignore individual palettes, and draw everything with \a default_pal.
 | 
			
		||||
 */
 | 
			
		||||
void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const
 | 
			
		||||
{
 | 
			
		||||
	for (uint i = 0; i < this->count; ++i) {
 | 
			
		||||
		PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal;
 | 
			
		||||
		DrawSprite(this->seq[i].sprite, pal, x, y);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Function to tell if a vehicle needs to be autorenewed
 | 
			
		||||
 * @param *c The vehicle owner
 | 
			
		||||
@@ -1162,7 +1203,6 @@ void CallVehicleTicks()
 | 
			
		||||
 */
 | 
			
		||||
static void DoDrawVehicle(const Vehicle *v)
 | 
			
		||||
{
 | 
			
		||||
	SpriteID image = v->cur_image;
 | 
			
		||||
	PaletteID pal = PAL_NONE;
 | 
			
		||||
 | 
			
		||||
	if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 | 
			
		||||
@@ -1177,8 +1217,14 @@ static void DoDrawVehicle(const Vehicle *v)
 | 
			
		||||
		if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	AddSortableSpriteToDraw(image, pal, 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);
 | 
			
		||||
	StartSpriteCombine();
 | 
			
		||||
	for (uint i = 0; i < v->sprite_seq.count; ++i) {
 | 
			
		||||
		PaletteID pal2 = v->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,
 | 
			
		||||
			v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs);
 | 
			
		||||
	}
 | 
			
		||||
	EndSpriteCombine();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1899,20 +1945,19 @@ void Vehicle::UpdatePosition()
 | 
			
		||||
 */
 | 
			
		||||
void Vehicle::UpdateViewport(bool dirty)
 | 
			
		||||
{
 | 
			
		||||
	int img = this->cur_image;
 | 
			
		||||
	Rect new_coord;
 | 
			
		||||
	this->sprite_seq.GetBounds(&new_coord);
 | 
			
		||||
 | 
			
		||||
	Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos);
 | 
			
		||||
	const Sprite *spr = GetSprite(img, ST_NORMAL);
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	pt.x += spr->x_offs;
 | 
			
		||||
	pt.y += spr->y_offs;
 | 
			
		||||
 | 
			
		||||
	UpdateVehicleViewportHash(this, pt.x, pt.y);
 | 
			
		||||
	UpdateVehicleViewportHash(this, new_coord.left, new_coord.top);
 | 
			
		||||
 | 
			
		||||
	Rect old_coord = this->coord;
 | 
			
		||||
	this->coord.left   = pt.x;
 | 
			
		||||
	this->coord.top    = pt.y;
 | 
			
		||||
	this->coord.right  = pt.x + spr->width + 2 * ZOOM_LVL_BASE;
 | 
			
		||||
	this->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE;
 | 
			
		||||
	this->coord = new_coord;
 | 
			
		||||
 | 
			
		||||
	if (dirty) {
 | 
			
		||||
		if (old_coord.left == INVALID_COORD) {
 | 
			
		||||
 
 | 
			
		||||
@@ -137,6 +137,63 @@ struct VehicleCache {
 | 
			
		||||
	byte cached_vis_effect;  ///< Visual effect to show (see #VisualEffect)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** 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
 | 
			
		||||
	{
 | 
			
		||||
		return !this->operator==(other);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Check whether the sequence contains any sprites.
 | 
			
		||||
	 */
 | 
			
		||||
	bool IsValid() const
 | 
			
		||||
	{
 | 
			
		||||
		return this->count != 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Clear all information.
 | 
			
		||||
	 */
 | 
			
		||||
	void Clear()
 | 
			
		||||
	{
 | 
			
		||||
		this->count = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Assign a single sprite to the sequence.
 | 
			
		||||
	 */
 | 
			
		||||
	void Set(SpriteID sprite)
 | 
			
		||||
	{
 | 
			
		||||
		this->count = 1;
 | 
			
		||||
		this->seq[0].sprite = sprite;
 | 
			
		||||
		this->seq[0].pal = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Copy data from another sprite sequence, while dropping all recolouring information.
 | 
			
		||||
	 */
 | 
			
		||||
	void CopyWithoutPalette(const VehicleSpriteSeq &src)
 | 
			
		||||
	{
 | 
			
		||||
		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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/** A vehicle pool for a little over 1 million vehicles. */
 | 
			
		||||
typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
 | 
			
		||||
extern VehiclePool _vehicle_pool;
 | 
			
		||||
@@ -230,7 +287,7 @@ public:
 | 
			
		||||
	 * 0xff == reserved for another custom sprite
 | 
			
		||||
	 */
 | 
			
		||||
	byte spritenum;
 | 
			
		||||
	SpriteID cur_image;                 ///< sprite number for this vehicle
 | 
			
		||||
	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
 | 
			
		||||
@@ -394,9 +451,9 @@ public:
 | 
			
		||||
	/**
 | 
			
		||||
	 * Gets the sprite to show for the given direction
 | 
			
		||||
	 * @param direction the direction the vehicle is facing
 | 
			
		||||
	 * @return the sprite for the given vehicle in the given direction
 | 
			
		||||
	 * @param [out] result Vehicle sprite sequence.
 | 
			
		||||
	 */
 | 
			
		||||
	virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
 | 
			
		||||
	virtual void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { result->Clear(); }
 | 
			
		||||
 | 
			
		||||
	const GRFFile *GetGRF() const;
 | 
			
		||||
	uint32 GetGRFID() const;
 | 
			
		||||
@@ -1012,7 +1069,10 @@ struct SpecializedVehicle : public Vehicle {
 | 
			
		||||
	/**
 | 
			
		||||
	 * Set vehicle type correctly
 | 
			
		||||
	 */
 | 
			
		||||
	inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
 | 
			
		||||
	inline SpecializedVehicle<T, Type>() : Vehicle(Type)
 | 
			
		||||
	{
 | 
			
		||||
		this->sprite_seq.count = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get the first vehicle in the chain
 | 
			
		||||
@@ -1154,15 +1214,20 @@ struct SpecializedVehicle : public Vehicle {
 | 
			
		||||
		/* 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(this->direction);
 | 
			
		||||
		SpriteID old_image = this->cur_image;
 | 
			
		||||
		if (this->cur_image_valid_dir != this->direction) {
 | 
			
		||||
			_sprite_group_resolve_check_veh_check = true;
 | 
			
		||||
			_sprite_group_resolve_check_veh_type = EXPECTED_TYPE;
 | 
			
		||||
			this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
 | 
			
		||||
			VehicleSpriteSeq seq;
 | 
			
		||||
			((T *)this)->T::GetImage(this->direction, EIT_ON_MAP, &seq);
 | 
			
		||||
			this->cur_image_valid_dir = _sprite_group_resolve_check_veh_check ? this->direction : INVALID_DIR;
 | 
			
		||||
			_sprite_group_resolve_check_veh_check = false;
 | 
			
		||||
			if (force_update || this->sprite_seq != seq) {
 | 
			
		||||
				this->sprite_seq = seq;
 | 
			
		||||
				this->Vehicle::UpdateViewport(true);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (force_update) {
 | 
			
		||||
			this->Vehicle::UpdateViewport(true);
 | 
			
		||||
		}
 | 
			
		||||
		if (force_update || this->cur_image != old_image) this->Vehicle::UpdateViewport(true);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -850,7 +850,7 @@ inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicl
 | 
			
		||||
	tmp->max_te = gcache->cached_max_te / 1000;
 | 
			
		||||
 | 
			
		||||
	tmp->spritenum = virt->spritenum;
 | 
			
		||||
	tmp->cur_image = virt->GetImage(DIR_W, EIT_PURCHASE);
 | 
			
		||||
	virt->GetImage(DIR_W, EIT_PURCHASE, &tmp->sprite_seq);
 | 
			
		||||
	tmp->image_width = virt->GetDisplayImageWidth();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2384,9 +2384,7 @@ struct VehicleDetailsWindow : Window {
 | 
			
		||||
			case WID_VD_MIDDLE_DETAILS: {
 | 
			
		||||
				/* For other vehicles, at the place of the matrix. */
 | 
			
		||||
				bool rtl = _current_text_dir == TD_RTL;
 | 
			
		||||
				uint sprite_width = UnScaleGUI(
 | 
			
		||||
						max<uint>(GetSprite(v->GetImage(rtl ? DIR_E : DIR_W, EIT_IN_DETAILS), ST_NORMAL)->width, 70U)) +
 | 
			
		||||
						WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
 | 
			
		||||
				uint sprite_width = GetSingleVehicleWidth(v, EIT_IN_DETAILS) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
 | 
			
		||||
 | 
			
		||||
				uint text_left  = r.left  + (rtl ? 0 : sprite_width);
 | 
			
		||||
				uint text_right = r.right - (rtl ? sprite_width : 0);
 | 
			
		||||
@@ -2672,8 +2670,8 @@ static const uint32 _vehicle_command_translation_table[][4] = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This is the Callback method after the cloning attempt of a vehicle
 | 
			
		||||
 * @param result the result of the cloning command
 | 
			
		||||
 * This is the Callback method after attempting to start/stop a vehicle
 | 
			
		||||
 * @param result the result of the start/stop command
 | 
			
		||||
 * @param tile unused
 | 
			
		||||
 * @param p1 vehicle ID
 | 
			
		||||
 * @param p2 unused
 | 
			
		||||
@@ -3201,9 +3199,11 @@ int GetSingleVehicleWidth(const Vehicle *v, EngineImageType image_type)
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			bool rtl = _current_text_dir == TD_RTL;
 | 
			
		||||
			SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type);
 | 
			
		||||
			const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 | 
			
		||||
			return UnScaleGUI(real_sprite->width);
 | 
			
		||||
			VehicleSpriteSeq seq;
 | 
			
		||||
			v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
 | 
			
		||||
			Rect rec;
 | 
			
		||||
			seq.GetBounds(&rec);
 | 
			
		||||
			return UnScaleGUI(rec.right - rec.left + 1);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3237,16 +3237,24 @@ void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type)
 | 
			
		||||
	_cursor.sprite_count = 0;
 | 
			
		||||
	int total_width = 0;
 | 
			
		||||
	for (; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) {
 | 
			
		||||
		if (_cursor.sprite_count == lengthof(_cursor.sprite_seq)) break;
 | 
			
		||||
		if (total_width >= 2 * (int)VEHICLEINFO_FULL_VEHICLE_WIDTH) break;
 | 
			
		||||
 | 
			
		||||
		_cursor.sprite_seq[_cursor.sprite_count].sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type);
 | 
			
		||||
		_cursor.sprite_seq[_cursor.sprite_count].pal = GetVehiclePalette(v);
 | 
			
		||||
		_cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width;
 | 
			
		||||
		_cursor.sprite_pos[_cursor.sprite_count].y = 0;
 | 
			
		||||
		PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 | 
			
		||||
		VehicleSpriteSeq seq;
 | 
			
		||||
		v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
 | 
			
		||||
 | 
			
		||||
		if (_cursor.sprite_count + seq.count > lengthof(_cursor.sprite_seq)) break;
 | 
			
		||||
 | 
			
		||||
		for (uint i = 0; i < seq.count; ++i) {
 | 
			
		||||
			PaletteID pal2 = (v->vehstatus & VS_CRASHED) || !seq.seq[i].pal ? pal : seq.seq[i].pal;
 | 
			
		||||
			_cursor.sprite_seq[_cursor.sprite_count].sprite = seq.seq[i].sprite;
 | 
			
		||||
			_cursor.sprite_seq[_cursor.sprite_count].pal = pal2;
 | 
			
		||||
			_cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width;
 | 
			
		||||
			_cursor.sprite_pos[_cursor.sprite_count].y = 0;
 | 
			
		||||
			_cursor.sprite_count++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		total_width += GetSingleVehicleWidth(v, image_type);
 | 
			
		||||
		_cursor.sprite_count++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int offs = ((int)VEHICLEINFO_FULL_VEHICLE_WIDTH - total_width) / 2;
 | 
			
		||||
 
 | 
			
		||||
@@ -110,15 +110,23 @@ static CGColorSpaceRef QZ_GetCorrectColorSpace()
 | 
			
		||||
	static CGColorSpaceRef colorSpace = NULL;
 | 
			
		||||
 | 
			
		||||
	if (colorSpace == NULL) {
 | 
			
		||||
		CMProfileRef sysProfile;
 | 
			
		||||
 | 
			
		||||
		if (CMGetSystemProfile(&sysProfile) == noErr) {
 | 
			
		||||
			colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysProfile);
 | 
			
		||||
			CMCloseProfile(sysProfile);
 | 
			
		||||
		} else {
 | 
			
		||||
			colorSpace = CGColorSpaceCreateDeviceRGB();
 | 
			
		||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
 | 
			
		||||
		if (MacOSVersionIsAtLeast(10, 5, 0)) {
 | 
			
		||||
			colorSpace = CGDisplayCopyColorSpace(CGMainDisplayID());
 | 
			
		||||
		} else
 | 
			
		||||
#endif
 | 
			
		||||
		{
 | 
			
		||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(HAVE_OSX_1011_SDK)
 | 
			
		||||
			CMProfileRef sysProfile;
 | 
			
		||||
			if (CMGetSystemProfile(&sysProfile) == noErr) {
 | 
			
		||||
				colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysProfile);
 | 
			
		||||
				CMCloseProfile(sysProfile);
 | 
			
		||||
			}
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (colorSpace == NULL) colorSpace = CGColorSpaceCreateDeviceRGB();
 | 
			
		||||
 | 
			
		||||
		if (colorSpace == NULL) error("Could not get system colour space. You might need to recalibrate your monitor.");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -84,6 +84,7 @@ static void DedicatedSignalHandler(int sig)
 | 
			
		||||
# endif
 | 
			
		||||
# include <time.h>
 | 
			
		||||
# include <tchar.h>
 | 
			
		||||
# include "../os/windows/win32.h"
 | 
			
		||||
static HANDLE _hInputReady, _hWaitForInputHandling;
 | 
			
		||||
static HANDLE _hThread; // Thread to close
 | 
			
		||||
static char _win_console_thread_buffer[200];
 | 
			
		||||
@@ -95,6 +96,8 @@ static void WINAPI CheckForConsoleInput()
 | 
			
		||||
	/* WinCE doesn't support console stuff */
 | 
			
		||||
	return;
 | 
			
		||||
#else
 | 
			
		||||
	SetWin32ThreadName(-1, "ottd:win-console");
 | 
			
		||||
 | 
			
		||||
	DWORD nb;
 | 
			
		||||
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
 | 
			
		||||
	for (;;) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1199,7 +1199,7 @@ void VideoDriver_Win32::MainLoop()
 | 
			
		||||
			_draw_threaded = false;
 | 
			
		||||
		} else {
 | 
			
		||||
			_draw_continue = true;
 | 
			
		||||
			_draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread);
 | 
			
		||||
			_draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread, "ottd:draw-win32");
 | 
			
		||||
 | 
			
		||||
			/* Free the mutex if we won't be able to use it. */
 | 
			
		||||
			if (!_draw_threaded) {
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,8 @@ enum ToolbarNormalWidgets {
 | 
			
		||||
	WID_TN_AIRCRAFTS,     ///< Aircraft menu.
 | 
			
		||||
	WID_TN_ZOOM_IN,       ///< Zoom in the main viewport.
 | 
			
		||||
	WID_TN_ZOOM_OUT,      ///< Zoom out the main viewport.
 | 
			
		||||
	WID_TN_RAILS,         ///< Rail building menu.
 | 
			
		||||
	WID_TN_BUILDING_TOOLS_START, ///< Helper for the offset of the building tools
 | 
			
		||||
	WID_TN_RAILS         = WID_TN_BUILDING_TOOLS_START, ///< Rail building menu.
 | 
			
		||||
	WID_TN_ROADS,         ///< Road building menu.
 | 
			
		||||
	WID_TN_WATER,         ///< Water building toolbar.
 | 
			
		||||
	WID_TN_AIR,           ///< Airport building toolbar.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user