Changeset - r12290:442d5d533a57
[Not reviewed]
master
0 17 0
smatz - 15 years ago 2009-07-01 22:22:01
smatz@openttd.org
(svn r16717) -Codechange: make IsFrontEngine() member of Train
17 files changed with 118 insertions and 110 deletions:
0 comments (0 inline, 0 general)
src/autoreplace_cmd.cpp
Show inline comments
 
@@ -596,51 +596,52 @@ static CommandCost ReplaceChain(Vehicle 
 
	return cost;
 
}
 

	
 
/** Autoreplaces a vehicle
 
 * Trains are replaced as a whole chain, free wagons in depot are replaced on their own
 
 * @param tile not used
 
 * @param flags type of operation
 
 * @param p1 Index of vehicle
 
 * @param p2 not used
 
 */
 
CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
 
	bool nothing_to_do = true;
 

	
 
	Vehicle *v = Vehicle::GetIfValid(p1);
 
	if (v == NULL) return CMD_ERROR;
 

	
 
	if (!CheckOwnership(v->owner)) return CMD_ERROR;
 
	if (!v->IsInDepot()) return CMD_ERROR;
 
	if (v->vehstatus & VS_CRASHED) return CMD_ERROR;
 

	
 
	bool free_wagon = false;
 
	if (v->type == VEH_TRAIN) {
 
		if (IsArticulatedPart(v) || IsRearDualheaded(v)) return CMD_ERROR;
 
		free_wagon = !IsFrontEngine(v);
 
		if (free_wagon && IsFrontEngine(v->First())) return CMD_ERROR;
 
		Train *t = Train::From(v);
 
		if (IsArticulatedPart(t) || IsRearDualheaded(t)) return CMD_ERROR;
 
		free_wagon = !t->IsFrontEngine();
 
		if (free_wagon && t->First()->IsFrontEngine()) return CMD_ERROR;
 
	} else {
 
		if (!v->IsPrimaryVehicle()) return CMD_ERROR;
 
	}
 

	
 
	const Company *c = Company::Get(_current_company);
 
	bool wagon_removal = c->settings.renew_keep_length;
 

	
 
	/* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */
 
	Vehicle *w = v;
 
	bool any_replacements = false;
 
	while (w != NULL && !any_replacements) {
 
		any_replacements = (GetNewEngineType(w, c) != INVALID_ENGINE);
 
		w = (!free_wagon && w->type == VEH_TRAIN ? GetNextUnit(Train::From(w)) : NULL);
 
	}
 

	
 
	if (any_replacements) {
 
		bool was_stopped = free_wagon || ((v->vehstatus & VS_STOPPED) != 0);
 

	
 
		/* Stop the vehicle */
 
		if (!was_stopped) cost.AddCost(StartStopVehicle(v, true));
 
		if (cost.Failed()) return cost;
 

	
 
		assert(v->IsStoppedInDepot());
 

	
src/depot_gui.cpp
Show inline comments
 
@@ -416,62 +416,62 @@ struct DepotWindow : Window {
 
		pos = ((row + this->vscroll.pos) * boxes_in_each_row) + xt;
 

	
 
		if ((int)(this->vehicle_list.Length() + this->wagon_list.Length()) <= pos) {
 
			if (this->type == VEH_TRAIN) {
 
				d->head  = NULL;
 
				d->wagon = NULL;
 
				return MODE_DRAG_VEHICLE;
 
			} else {
 
				return MODE_ERROR; // empty block, so no vehicle is selected
 
			}
 
		}
 

	
 
		if ((int)this->vehicle_list.Length() > pos) {
 
			*veh = this->vehicle_list[pos];
 
			skip = this->hscroll.pos;
 
		} else {
 
			pos -= this->vehicle_list.Length();
 
			*veh = this->wagon_list[pos];
 
			/* free wagons don't have an initial loco. */
 
			x -= _traininfo_vehicle_width;
 
		}
 

	
 
		switch (this->type) {
 
			case VEH_TRAIN: {
 
				const Vehicle *v = *veh;
 
				const Train *v = Train::From(*veh);
 
				d->head = d->wagon = v;
 

	
 
				/* either pressed the flag or the number, but only when it's a loco */
 
				if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
 
				if (x < 0 && v->IsFrontEngine()) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
 

	
 
				skip = (skip * 8) / _traininfo_vehicle_width;
 
				x = (x * 8) / _traininfo_vehicle_width;
 

	
 
				/* Skip vehicles that are scrolled off the list */
 
				x += skip;
 

	
 
				/* find the vehicle in this row that was clicked */
 
				while (v != NULL && (x -= Train::From(v)->tcache.cached_veh_length) >= 0) v = v->Next();
 
				while (v != NULL && (x -= v->tcache.cached_veh_length) >= 0) v = v->Next();
 

	
 
				/* if an articulated part was selected, find its parent */
 
				while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
 

	
 
				d->wagon = v;
 

	
 
				return MODE_DRAG_VEHICLE;
 
				}
 
				break;
 

	
 
			case VEH_ROAD:
 
				if (xm >= 24) return MODE_DRAG_VEHICLE;
 
				if (xm <= 16) return MODE_SHOW_VEHICLE;
 
				break;
 

	
 
			case VEH_SHIP:
 
				if (xm >= 19) return MODE_DRAG_VEHICLE;
 
				if (ym <= 10) return MODE_SHOW_VEHICLE;
 
				break;
 

	
 
			case VEH_AIRCRAFT:
 
				if (xm >= 12) return MODE_DRAG_VEHICLE;
 
				if (ym <= 12) return MODE_SHOW_VEHICLE;
 
				break;
 
@@ -543,49 +543,49 @@ struct DepotWindow : Window {
 
					case VEH_AIRCRAFT: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_AIRCRAFT);     break;
 
					default: NOT_REACHED();
 
				}
 
				DoCommandP(v->tile, v->index, 0, command);
 
			} break;
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	/**
 
	 * Clones a vehicle
 
	 * @param *v is the original vehicle to clone
 
	 * @param *w is the window of the depot where the clone is build
 
	 */
 
	void HandleCloneVehClick(const Vehicle *v, const Window *w)
 
	{
 
		StringID error_str;
 

	
 
		if (v == NULL) return;
 

	
 
		if (!v->IsPrimaryVehicle()) {
 
			v = v->First();
 
			/* Do nothing when clicking on a train in depot with no loc attached */
 
			if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
 
			if (v->type == VEH_TRAIN && !Train::From(v)->IsFrontEngine()) return;
 
		}
 

	
 
		switch (v->type) {
 
			case VEH_TRAIN:    error_str = STR_ERROR_CAN_T_BUILD_RAILROAD_VEHICLE; break;
 
			case VEH_ROAD:     error_str = STR_ERROR_CAN_T_BUILD_ROAD_VEHICLE;     break;
 
			case VEH_SHIP:     error_str = STR_ERROR_CAN_T_BUILD_SHIP;             break;
 
			case VEH_AIRCRAFT: error_str = STR_ERROR_CAN_T_BUILD_AIRCRAFT;         break;
 
			default: return;
 
		}
 

	
 
		DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CMD_CLONE_VEHICLE | CMD_MSG(error_str), CcCloneVehicle);
 

	
 
		ResetObjectToPlace();
 
	}
 

	
 
	void ResizeDepotButtons(Window *w)
 
	{
 
		ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
 

	
 
		if (this->type == VEH_TRAIN) {
 
			/* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
 
			 * This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason                                                  */
 
			this->widget[DEPOT_WIDGET_SELL_CHAIN].top    = ((this->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - this->widget[DEPOT_WIDGET_SELL].top) / 2) + this->widget[DEPOT_WIDGET_SELL].top;
 
			this->widget[DEPOT_WIDGET_SELL].bottom     = this->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
 
@@ -929,76 +929,76 @@ struct DepotWindow : Window {
 
			_place_clicked_vehicle = NULL;
 
			HandleCloneVehClick(v, this);
 
		}
 
	}
 

	
 
	virtual void OnDragDrop(Point pt, int widget)
 
	{
 
		switch (widget) {
 
			case DEPOT_WIDGET_MATRIX: {
 
				const Vehicle *v = NULL;
 
				VehicleID sel = this->sel;
 

	
 
				this->sel = INVALID_VEHICLE;
 
				this->SetDirty();
 

	
 
				if (this->type == VEH_TRAIN) {
 
					GetDepotVehiclePtData gdvp = { NULL, NULL };
 

	
 
					if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
 
						sel != INVALID_VEHICLE) {
 
						if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
 
							DoCommandP(Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_MAKE_VEHICLE_TURN));
 
						} else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
 
							TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
 
						} else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
 
						} else if (gdvp.head != NULL && Train::From(gdvp.head)->IsFrontEngine()) {
 
							ShowVehicleViewWindow(gdvp.head);
 
						}
 
					}
 
				} else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
 
					v != NULL &&
 
					sel == v->index) {
 
					ShowVehicleViewWindow(v);
 
				}
 
			} break;
 

	
 
			case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
 
				if (!this->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
 
					this->sel != INVALID_VEHICLE) {
 
					uint command;
 

	
 
					if (this->IsWidgetDisabled(widget)) return;
 
					if (this->sel == INVALID_VEHICLE) return;
 

	
 
					this->HandleButtonClick(widget);
 

	
 
					const Vehicle *v = Vehicle::Get(this->sel);
 
					this->sel = INVALID_VEHICLE;
 
					this->SetDirty();
 

	
 
					int sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
 

	
 
					bool is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
 
					bool is_engine = (v->type != VEH_TRAIN || Train::From(v)->IsFrontEngine());
 

	
 
					if (is_engine) {
 
						_backup_orders_tile = v->tile;
 
						BackupVehicleOrders(v);
 
					}
 

	
 
					switch (v->type) {
 
						case VEH_TRAIN:    command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_ERROR_CAN_T_SELL_RAILROAD_VEHICLE); break;
 
						case VEH_ROAD:     command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_ERROR_CAN_T_SELL_ROAD_VEHICLE);       break;
 
						case VEH_SHIP:     command = CMD_SELL_SHIP | CMD_MSG(STR_ERROR_CAN_T_SELL_SHIP);                   break;
 
						case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_ERROR_CAN_T_SELL_AIRCRAFT);           break;
 
						default: NOT_REACHED();
 
					}
 

	
 
					if (!DoCommandP(v->tile, v->index, sell_cmd, command) && is_engine) _backup_orders_tile = 0;
 
				}
 
				break;
 
			default:
 
				this->sel = INVALID_VEHICLE;
 
				this->SetDirty();
 
		}
 
		_cursor.vehchain = false;
 
	}
 

	
src/elrail.cpp
Show inline comments
 
@@ -547,38 +547,38 @@ bool SettingsDisableElrail(int32 p1)
 
		/* if it is an electric rail engine and its railtype is the wrong one */
 
		if (rv_info->engclass == 2 && rv_info->railtype == old_railtype) {
 
			/* change it to the proper one */
 
			rv_info->railtype = new_railtype;
 
		}
 
	}
 

	
 
	/* when disabling elrails, make sure that all existing trains can run on
 
	 *  normal rail too */
 
	if (disable) {
 
		FOR_ALL_TRAINS(t) {
 
			if (t->railtype == RAILTYPE_ELECTRIC) {
 
				/* this railroad vehicle is now compatible only with elrail,
 
				 *  so add there also normal rail compatibility */
 
				t->compatible_railtypes |= RAILTYPES_RAIL;
 
				t->railtype = RAILTYPE_RAIL;
 
				SetBit(t->flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL);
 
			}
 
		}
 
	}
 

	
 
	/* Fix the total power and acceleration for trains */
 
	FOR_ALL_TRAINS(t) {
 
		/* power and acceleration is cached only for front engines */
 
		if (IsFrontEngine(t)) {
 
		if (t->IsFrontEngine()) {
 
			TrainPowerChanged(t);
 
			UpdateTrainAcceleration(t);
 
		}
 
	}
 

	
 
	FOR_ALL_COMPANIES(c) c->avail_railtypes = GetCompanyRailtypes(c->index);
 

	
 
	/* This resets the _last_built_railtype, which will be invalid for electric
 
	 * rails. It may have unintended consequences if that function is ever
 
	 * extended, though. */
 
	ReinitGuiAfterToggleElrail(disable);
 
	return true;
 
}
src/group.h
Show inline comments
 
@@ -62,32 +62,32 @@ static inline uint GetGroupArraySize()
 

	
 
/**
 
 * Get the number of engines with EngineID id_e in the group with GroupID
 
 * id_g
 
 * @param id_g The GroupID of the group used
 
 * @param id_e The EngineID of the engine to count
 
 * @return The number of engines with EngineID id_e in the group
 
 */
 
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e);
 

	
 
static inline void IncreaseGroupNumVehicle(GroupID id_g)
 
{
 
	Group *g = Group::GetIfValid(id_g);
 
	if (g != NULL) g->num_vehicle++;
 
}
 

	
 
static inline void DecreaseGroupNumVehicle(GroupID id_g)
 
{
 
	Group *g = Group::GetIfValid(id_g);
 
	if (g != NULL) g->num_vehicle--;
 
}
 

	
 

	
 
void InitializeGroup();
 
void SetTrainGroupID(Vehicle *v, GroupID grp);
 
void UpdateTrainGroupID(Vehicle *v);
 
void SetTrainGroupID(Train *v, GroupID grp);
 
void UpdateTrainGroupID(Train *v);
 
void RemoveVehicleFromGroup(const Vehicle *v);
 
void RemoveAllGroupsForCompany(const CompanyID company);
 

	
 
extern GroupID _new_group_id;
 

	
 
#endif /* GROUP_H */
src/group_cmd.cpp
Show inline comments
 
@@ -189,49 +189,49 @@ CommandCost CmdRenameGroup(TileIndex til
 
 * @param p2   vehicle to add to a group
 
 *   - p2 bit 0-15 : VehicleID
 
 */
 
CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Vehicle *v = Vehicle::GetIfValid(p2);
 
	GroupID new_g = p1;
 

	
 
	if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
 

	
 
	if (Group::IsValidID(new_g)) {
 
		Group *g = Group::Get(new_g);
 
		if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
 
	}
 

	
 
	if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		DecreaseGroupNumVehicle(v->group_id);
 
		IncreaseGroupNumVehicle(new_g);
 

	
 
		switch (v->type) {
 
			default: NOT_REACHED();
 
			case VEH_TRAIN:
 
				SetTrainGroupID(v, new_g);
 
				SetTrainGroupID(Train::From(v), new_g);
 
				break;
 
			case VEH_ROAD:
 
			case VEH_SHIP:
 
			case VEH_AIRCRAFT:
 
				if (IsEngineCountable(v)) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
 
				v->group_id = new_g;
 
				break;
 
		}
 

	
 
		/* Update the Replace Vehicle Windows */
 
		InvalidateWindow(WC_REPLACE_VEHICLE, v->type);
 
		InvalidateWindowData(GetWindowClassForVehicleType(v->type), (v->type << 11) | VLW_GROUP_LIST | _current_company);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Add all shared vehicles of all vehicles from a group
 
 * @param tile unused
 
 * @param p1   index of group array
 
 *  - p1 bit 0-15 : GroupID
 
 * @param p2   type of vehicles
 
 */
 
@@ -321,77 +321,77 @@ CommandCost CmdSetGroupReplaceProtection
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Decrease the num_vehicle variable before delete an front engine from a group
 
 * @note Called in CmdSellRailWagon and DeleteLasWagon,
 
 * @param v     FrontEngine of the train we want to remove.
 
 */
 
void RemoveVehicleFromGroup(const Vehicle *v)
 
{
 
	if (!v->IsPrimaryVehicle()) return;
 

	
 
	if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id);
 
}
 

	
 

	
 
/**
 
 * Affect the groupID of a train to new_g.
 
 * @note called in CmdAddVehicleGroup and CmdMoveRailVehicle
 
 * @param v     First vehicle of the chain.
 
 * @param new_g index of array group
 
 */
 
void SetTrainGroupID(Vehicle *v, GroupID new_g)
 
void SetTrainGroupID(Train *v, GroupID new_g)
 
{
 
	if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
 

	
 
	assert(v->type == VEH_TRAIN && IsFrontEngine(v));
 
	assert(v->IsFrontEngine());
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
		if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
 

	
 
		u->group_id = new_g;
 
	}
 

	
 
	/* Update the Replace Vehicle Windows */
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
 
}
 

	
 

	
 
/**
 
 * Recalculates the groupID of a train. Should be called each time a vehicle is added
 
 * to/removed from the chain,.
 
 * @note this needs to be called too for 'wagon chains' (in the depot, without an engine)
 
 * @note Called in CmdBuildRailVehicle, CmdBuildRailWagon, CmdMoveRailVehicle, CmdSellRailWagon
 
 * @param v First vehicle of the chain.
 
 */
 
void UpdateTrainGroupID(Vehicle *v)
 
void UpdateTrainGroupID(Train *v)
 
{
 
	assert(v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v)));
 
	assert(v->IsFrontEngine() || IsFreeWagon(v));
 

	
 
	GroupID new_g = IsFrontEngine(v) ? v->group_id : (GroupID)DEFAULT_GROUP;
 
	GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP;
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
		if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
 

	
 
		u->group_id = new_g;
 
	}
 

	
 
	/* Update the Replace Vehicle Windows */
 
	InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
 
}
 

	
 
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
 
{
 
	if (Group::IsValidID(id_g)) return Group::Get(id_g)->num_engines[id_e];
 

	
 
	uint num = Company::Get(company)->num_engines[id_e];
 
	if (!IsDefaultGroupID(id_g)) return num;
 

	
 
	const Group *g;
 
	FOR_ALL_GROUPS(g) {
 
		if (g->owner == company) num -= g->num_engines[id_e];
 
	}
 
	return num;
 
}
 

	
src/industry_cmd.cpp
Show inline comments
 
@@ -2002,49 +2002,49 @@ static void CanCargoServiceIndustry(Carg
 
 *
 
 * @param ind: Industry being investigated.
 
 *
 
 * @return: 0 if nobody can service the industry, 2 if the local company can
 
 * service the industry, and 1 otherwise (only competitors can service the
 
 * industry)
 
 */
 
int WhoCanServiceIndustry(Industry *ind)
 
{
 
	/* Find all stations within reach of the industry */
 
	StationList stations;
 
	FindStationsAroundTiles(ind->xy, ind->width, ind->height, &stations);
 

	
 
	if (stations.Length() == 0) return 0; // No stations found at all => nobody services
 

	
 
	const Vehicle *v;
 
	int result = 0;
 
	FOR_ALL_VEHICLES(v) {
 
		/* Is it worthwhile to try this vehicle? */
 
		if (v->owner != _local_company && result != 0) continue;
 

	
 
		/* Check whether it accepts the right kind of cargo */
 
		bool c_accepts = false;
 
		bool c_produces = false;
 
		if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
 
		if (v->type == VEH_TRAIN && Train::From(v)->IsFrontEngine()) {
 
			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
				CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces);
 
			}
 
		} else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) {
 
			CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces);
 
		} else {
 
			continue;
 
		}
 
		if (!c_accepts && !c_produces) continue; // Wrong cargo
 

	
 
		/* Check orders of the vehicle.
 
		 * We cannot check the first of shared orders only, since the first vehicle in such a chain
 
		 * may have a different cargo type.
 
		 */
 
		const Order *o;
 
		FOR_VEHICLE_ORDERS(v, o) {
 
			if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) {
 
				/* Vehicle visits a station to load or unload */
 
				Station *st = Station::Get(o->GetDestination());
 
				assert(st != NULL);
 

	
 
				/* Same cargo produced by industry is dropped here => not serviced by vehicle v */
 
				if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break;
 

	
src/saveload/afterload.cpp
Show inline comments
 
@@ -964,49 +964,49 @@ bool AfterLoadGame()
 
				case MP_ROAD:
 
					if (IsLevelCrossing(t)) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				case MP_STATION:
 
					if (IsRailwayStation(t)) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				case MP_TUNNELBRIDGE:
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
		}
 

	
 
		FOR_ALL_TRAINS(v) {
 
			if (IsFrontEngine(v) || IsFreeWagon(v)) TrainConsistChanged(v, true);
 
			if (v->IsFrontEngine() || IsFreeWagon(v)) TrainConsistChanged(v, true);
 
		}
 

	
 
	}
 

	
 
	/* In version 16.1 of the savegame a company can decide if trains, which get
 
	 * replaced, shall keep their old length. In all prior versions, just default
 
	 * to false */
 
	if (CheckSavegameVersionOldStyle(16, 1)) {
 
		FOR_ALL_COMPANIES(c) c->settings.renew_keep_length = false;
 
	}
 

	
 
	/* In version 17, ground type is moved from m2 to m4 for depots and
 
	 * waypoints to make way for storing the index in m2. The custom graphics
 
	 * id which was stored in m4 is now saved as a grf/id reference in the
 
	 * waypoint struct. */
 
	if (CheckSavegameVersion(17)) {
 
		Waypoint *wp;
 

	
 
		FOR_ALL_WAYPOINTS(wp) {
 
			if (wp->deleted == 0) {
 
				const StationSpec *statspec = NULL;
 

	
 
				if (HasBit(_m[wp->xy].m3, 4))
 
					statspec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1);
 
@@ -1323,49 +1323,49 @@ bool AfterLoadGame()
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			if (IsStatueTile(t)) {
 
				_m[t].m2 = CalcClosestTownFromTile(t)->index;
 
			}
 
		}
 
	}
 

	
 
	/* A setting containing the proportion of towns that grow twice as
 
	 * fast was added in version 54. From version 56 this is now saved in the
 
	 * town as cities can be built specifically in the scenario editor. */
 
	if (CheckSavegameVersion(56)) {
 
		Town *t;
 

	
 
		FOR_ALL_TOWNS(t) {
 
			if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) {
 
				t->larger_town = true;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(57)) {
 
		Vehicle *v;
 
		/* Added a FIFO queue of vehicles loading at stations */
 
		FOR_ALL_VEHICLES(v) {
 
			if ((v->type != VEH_TRAIN || IsFrontEngine(v)) &&  // for all locs
 
			if ((v->type != VEH_TRAIN || Train::From(v)->IsFrontEngine()) &&  // for all locs
 
					!(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed
 
					v->current_order.IsType(OT_LOADING)) {         // loading
 
				Station::Get(v->last_station_visited)->loading_vehicles.push_back(v);
 

	
 
				/* The loading finished flag is *only* set when actually completely
 
				 * finished. Because the vehicle is loading, it is not finished. */
 
				ClrBit(v->vehicle_flags, VF_LOADING_FINISHED);
 
			}
 
		}
 
	} else if (CheckSavegameVersion(59)) {
 
		/* For some reason non-loading vehicles could be in the station's loading vehicle list */
 

	
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			std::list<Vehicle *>::iterator iter;
 
			for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) {
 
				Vehicle *v = *iter;
 
				iter++;
 
				if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v);
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(58)) {
src/saveload/vehicle_sl.cpp
Show inline comments
 
@@ -7,63 +7,63 @@
 
#include "../train.h"
 
#include "../roadveh.h"
 
#include "../ship.h"
 
#include "../aircraft.h"
 
#include "../station_base.h"
 
#include "../effectvehicle_base.h"
 

	
 
#include "saveload.h"
 

	
 
#include <map>
 

	
 
/*
 
 * Link front and rear multiheaded engines to each other
 
 * This is done when loading a savegame
 
 */
 
void ConnectMultiheadedTrains()
 
{
 
	Train *v;
 

	
 
	FOR_ALL_TRAINS(v) {
 
		v->other_multiheaded_part = NULL;
 
	}
 

	
 
	FOR_ALL_TRAINS(v) {
 
		if (IsFrontEngine(v) || IsFreeWagon(v)) {
 
		if (v->IsFrontEngine() || IsFreeWagon(v)) {
 
			/* Two ways to associate multiheaded parts to each other:
 
			 * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
 
			 * bracket-matching:    Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
 
			 *
 
			 * Note: Old savegames might contain chains which do not comply with these rules, e.g.
 
			 *   - the front and read parts have invalid orders
 
			 *   - different engine types might be combined
 
			 *   - there might be different amounts of front and rear parts.
 
			 *
 
			 * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
 
			 *   This is why two matching strategies are needed.
 
			 */
 

	
 
			bool sequential_matching = IsFrontEngine(v);
 
			bool sequential_matching = v->IsFrontEngine();
 

	
 
			for (Train *u = v; u != NULL; u = GetNextVehicle(u)) {
 
				if (u->other_multiheaded_part != NULL) continue; // we already linked this one
 

	
 
				if (IsMultiheaded(u)) {
 
					if (!IsTrainEngine(u)) {
 
						/* we got a rear car without a front car. We will convert it to a front one */
 
						SetTrainEngine(u);
 
						u->spritenum--;
 
					}
 

	
 
					/* Find a matching back part */
 
					EngineID eid = u->engine_type;
 
					Train *w;
 
					if (sequential_matching) {
 
						for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
 
							if (w->engine_type != eid || w->other_multiheaded_part != NULL || !IsMultiheaded(w)) continue;
 

	
 
							/* we found a car to partner with this engine. Now we will make sure it face the right way */
 
							if (IsTrainEngine(w)) {
 
								ClearTrainEngine(w);
 
								w->spritenum++;
 
							}
 
							break;
 
@@ -287,60 +287,63 @@ void AfterLoadVehicles(bool part_of_load
 
		if (v->Previous() == NULL) {
 
			for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
				u->first = v;
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(105)) {
 
		/* Before 105 there was no order for shared orders, thus it messed up horribly */
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->First() != v || v->orders.list != NULL || v->previous_shared != NULL || v->next_shared == NULL) continue;
 

	
 
			v->orders.list = new OrderList(NULL, v);
 
			for (Vehicle *u = v; u != NULL; u = u->next_shared) {
 
				u->orders.list = v->orders.list;
 
			}
 
		}
 
	}
 

	
 
	CheckValidVehicles();
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		assert(v->first != NULL);
 

	
 
		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
 
			if (IsFrontEngine(v)) Train::From(v)->tcache.last_speed = v->cur_speed; // update displayed train speed
 
			TrainConsistChanged(Train::From(v), false);
 
		if (v->type == VEH_TRAIN) {
 
			Train *t = Train::From(v);
 
			if (t->IsFrontEngine() || IsFreeWagon(t)) {
 
				t->tcache.last_speed = t->cur_speed; // update displayed train speed
 
				TrainConsistChanged(t, false);
 
			}
 
		} else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
 
			RoadVehUpdateCache(RoadVehicle::From(v));
 
		}
 
	}
 

	
 
	/* Stop non-front engines */
 
	if (CheckSavegameVersion(112)) {
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
 
			if (v->type == VEH_TRAIN && !Train::From(v)->IsFrontEngine()) {
 
				if (IsTrainEngine(v)) v->vehstatus |= VS_STOPPED;
 
				/* cur_speed is now relevant for non-front parts - nonzero breaks
 
				 * moving-wagons-inside-depot- and autoreplace- code */
 
				v->cur_speed = 0;
 
			}
 
			/* trains weren't stopping gradually in old OTTD versions (and TTO/TTD)
 
			 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
 
			if ((v->vehstatus & VS_STOPPED) && (v->type != VEH_TRAIN || CheckSavegameVersionOldStyle(2, 1))) {
 
				v->cur_speed = 0;
 
			}
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		switch (v->type) {
 
			case VEH_ROAD: {
 
				RoadVehicle *rv = RoadVehicle::From(v);
 
				rv->roadtype = HasBit(EngInfo(v->First()->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
 
				rv->compatible_roadtypes = RoadTypeToRoadTypes(rv->roadtype);
 
			}
 
				/* FALL THROUGH */
 
			case VEH_TRAIN:
 
			case VEH_SHIP:
 
				v->cur_image = v->GetImage(v->direction);
src/settings.cpp
Show inline comments
 
@@ -679,85 +679,85 @@ static bool CloseSignalGUI(int32 p1)
 
{
 
	if (p1 == 0) {
 
		DeleteWindowByClass(WC_BUILD_SIGNAL);
 
	}
 
	return true;
 
}
 

	
 
static bool InvalidateTownViewWindow(int32 p1)
 
{
 
	InvalidateWindowClassesData(WC_TOWN_VIEW, p1);
 
	return true;
 
}
 

	
 
static bool DeleteSelectStationWindow(int32 p1)
 
{
 
	DeleteWindowById(WC_SELECT_STATION, 0);
 
	return true;
 
}
 

	
 
static bool UpdateConsists(int32 p1)
 
{
 
	Train *t;
 
	FOR_ALL_TRAINS(t) {
 
		/* Update the consist of all trains so the maximum speed is set correctly. */
 
		if (IsFrontEngine(t) || IsFreeWagon(t)) TrainConsistChanged(t, true);
 
		if (t->IsFrontEngine() || IsFreeWagon(t)) TrainConsistChanged(t, true);
 
	}
 
	return true;
 
}
 

	
 
/* Check service intervals of vehicles, p1 is value of % or day based servicing */
 
static bool CheckInterval(int32 p1)
 
{
 
	VehicleDefaultSettings *vds;
 
	if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) {
 
		vds = &_settings_client.company.vehicle;
 
	} else {
 
		vds = &Company::Get(_current_company)->settings.vehicle;
 
	}
 

	
 
	if (p1) {
 
		vds->servint_trains   = 50;
 
		vds->servint_roadveh  = 50;
 
		vds->servint_aircraft = 50;
 
		vds->servint_ships    = 50;
 
	} else {
 
		vds->servint_trains   = 150;
 
		vds->servint_roadveh  = 150;
 
		vds->servint_aircraft = 360;
 
		vds->servint_ships    = 100;
 
	}
 

	
 
	InvalidateDetailsWindow(0);
 

	
 
	return true;
 
}
 

	
 
static bool TrainAccelerationModelChanged(int32 p1)
 
{
 
	Train *t;
 
	FOR_ALL_TRAINS(t) {
 
		if (IsFrontEngine(t)) {
 
		if (t->IsFrontEngine()) {
 
			t->tcache.cached_max_curve_speed = GetTrainCurveSpeedLimit(t);
 
			UpdateTrainAcceleration(t);
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
static bool DragSignalsDensityChanged(int32)
 
{
 
	SetWindowDirty(FindWindowById(WC_BUILD_SIGNAL, 0));
 

	
 
	return true;
 
}
 

	
 
/*
 
 * A: competitors
 
 * B: competitor start time. Deprecated since savegame version 110.
 
 * C: town count (3 = high, 0 = very low)
 
 * D: industry count (4 = high, 0 = none)
 
 * E: inital loan (in GBP)
 
 * F: interest rate
 
 * G: running costs (0 = low, 2 = high)
 
 * H: construction speed of competitors (0 = very slow, 4 = very fast)
src/station_cmd.cpp
Show inline comments
 
@@ -2487,49 +2487,49 @@ static void AnimateTile_Station(TileInde
 
				MarkTileDirtyByTile(tile);
 
			}
 
			break;
 
		}
 
	}
 
}
 

	
 

	
 
static bool ClickTile_Station(TileIndex tile)
 
{
 
	if (IsHangar(tile)) {
 
		ShowDepotWindow(tile, VEH_AIRCRAFT);
 
	} else {
 
		ShowStationViewWindow(GetStationIndex(tile));
 
	}
 
	return true;
 
}
 

	
 
static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y)
 
{
 
	StationID station_id = GetStationIndex(tile);
 

	
 
	if (v->type == VEH_TRAIN) {
 
		if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE;
 
		if (!IsRailwayStation(tile) || !IsFrontEngine(v)) return VETSB_CONTINUE;
 
		if (!IsRailwayStation(tile) || !Train::From(v)->IsFrontEngine()) return VETSB_CONTINUE;
 

	
 
		int station_ahead;
 
		int station_length;
 
		int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length);
 

	
 
		/* Stop whenever that amount of station ahead + the distance from the
 
		 * begin of the platform to the stop location is longer than the length
 
		 * of the platform. Station ahead 'includes' the current tile where the
 
		 * vehicle is on, so we need to substract that. */
 
		if (!IsInsideBS(stop + station_ahead, station_length, TILE_SIZE)) return VETSB_CONTINUE;
 

	
 
		DiagDirection dir = DirToDiagDir(v->direction);
 

	
 
		x &= 0xF;
 
		y &= 0xF;
 

	
 
		if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y);
 
		if (y == TILE_SIZE / 2) {
 
			if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x;
 
			stop &= TILE_SIZE - 1;
 

	
 
			if (x == stop) return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station
 
			if (x < stop) {
 
				uint16 spd;
src/train.h
Show inline comments
 
@@ -30,59 +30,48 @@ enum VehicleRailFlags {
 
	/* used to mark that electric train engine is allowed to run on normal rail */
 
	VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6,
 

	
 
	/* used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only) */
 
	VRF_TOGGLE_REVERSE = 7,
 

	
 
	/* used to mark a train that can't get a path reservation */
 
	VRF_TRAIN_STUCK    = 8,
 
};
 

	
 

	
 
/** enum to handle train subtypes
 
 * Do not access it directly unless you have to. Use the access functions below
 
 * This is an enum to tell what bit to access as it is a bitmask
 
 */
 
enum TrainSubtype {
 
	TS_FRONT             = 0, ///< Leading engine of a train
 
	TS_ARTICULATED_PART  = 1, ///< Articulated part of an engine
 
	TS_WAGON             = 2, ///< Wagon
 
	TS_ENGINE            = 3, ///< Engine, that can be front engines, but might be placed behind another engine
 
	TS_FREE_WAGON        = 4, ///< First in a wagon chain (in depot)
 
	TS_MULTIHEADED       = 5, ///< Engine is a multiheaded
 
};
 

	
 

	
 
/** Check if a vehicle is front engine
 
 * @param v vehicle to check
 
 * @return Returns true if vehicle is a front engine
 
 */
 
static inline bool IsFrontEngine(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	return HasBit(v->subtype, TS_FRONT);
 
}
 

	
 
/** Set front engine state
 
 * @param v vehicle to change
 
 */
 
static inline void SetFrontEngine(Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	SetBit(v->subtype, TS_FRONT);
 
}
 

	
 
/** Remove the front engine state
 
 * @param v vehicle to change
 
 */
 
static inline void ClearFrontEngine(Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	ClrBit(v->subtype, TS_FRONT);
 
}
 

	
 
/** Check if a vehicle is an articulated part of an engine
 
 * @param v vehicle to check
 
 * @return Returns true if vehicle is an articulated part
 
 */
 
static inline bool IsArticulatedPart(const Vehicle *v)
 
{
 
@@ -303,60 +292,67 @@ struct TrainCache {
 
struct Train : public SpecializedVehicle<Train, VEH_TRAIN> {
 
	TrainCache tcache;
 

	
 
	/* Link between the two ends of a multiheaded engine */
 
	Train *other_multiheaded_part;
 

	
 
	uint16 crash_anim_pos;
 

	
 
	uint16 flags;
 
	TrackBitsByte track;
 
	byte force_proceed;
 
	RailTypeByte railtype;
 
	RailTypes compatible_railtypes;
 

	
 
	/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
 
	Train() : SpecializedVehicle<Train, VEH_TRAIN>() {}
 
	/** We want to 'destruct' the right class. */
 
	virtual ~Train() { this->PreDestructor(); }
 

	
 
	const char *GetTypeString() const { return "train"; }
 
	void MarkDirty();
 
	void UpdateDeltaXY(Direction direction);
 
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
 
	void PlayLeaveStationSound() const;
 
	bool IsPrimaryVehicle() const { return IsFrontEngine(this); }
 
	bool IsPrimaryVehicle() const { return this->IsFrontEngine(); }
 
	SpriteID GetImage(Direction direction) const;
 
	int GetDisplaySpeed() const { return this->tcache.last_speed; }
 
	int GetDisplayMaxSpeed() const { return this->tcache.cached_max_speed; }
 
	Money GetRunningCost() const;
 
	bool IsInDepot() const { return CheckTrainInDepot(this, false) != -1; }
 
	bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
 
	bool Tick();
 
	void OnNewDay();
 
	Trackdir GetVehicleTrackdir() const;
 
	TileIndex GetOrderStationLocation(StationID station);
 
	bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
 

	
 
	/**
 
	 * Check if a vehicle is front engine
 
	 * @param v vehicle to check
 
	 * @return Returns true if vehicle is a front engine
 
	 */
 
	FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, TS_FRONT); }
 
};
 

	
 
#define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
 

	
 
/**
 
 * Get the next part of a multi-part engine.
 
 * Will only work on a multi-part engine (EngineHasArticPart(v) == true),
 
 * Result is undefined for normal engine.
 
 */
 
static inline Train *GetNextArticPart(const Train *v)
 
{
 
	assert(EngineHasArticPart(v));
 
	return v->Next();
 
}
 

	
 
/** Get the last part of a multi-part engine.
 
 * @param v Vehicle.
 
 * @return Last part of the engine.
 
 */
 
static inline Train *GetLastEnginePart(Train *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	while (EngineHasArticPart(v)) v = GetNextArticPart(v);
 
	return v;
src/train_cmd.cpp
Show inline comments
 
@@ -196,53 +196,52 @@ void CheckTrainsLengths()
 
							(w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
 
						SetDParam(0, v->index);
 
						SetDParam(1, v->owner);
 
						ShowErrorMessage(INVALID_STRING_ID, STR_BROKEN_VEHICLE_LENGTH, 0, 0, true);
 

	
 
						if (!_networking) DoCommandP(0, PM_PAUSED_ERROR, 1, CMD_PAUSE);
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
 

	
 
/**
 
 * Recalculates the cached stuff of a train. Should be called each time a vehicle is added
 
 * to/removed from the chain, and when the game is loaded.
 
 * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine)
 
 * @param v First vehicle of the chain.
 
 * @param same_length should length of vehicles stay the same?
 
 */
 
void TrainConsistChanged(Train *v, bool same_length)
 
{
 
	uint16 max_speed = UINT16_MAX;
 

	
 
	assert(v->type == VEH_TRAIN);
 
	assert(IsFrontEngine(v) || IsFreeWagon(v));
 
	assert(v->IsFrontEngine() || IsFreeWagon(v));
 

	
 
	const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
 
	EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
 
	EngineID first_engine = v->IsFrontEngine() ? v->engine_type : INVALID_ENGINE;
 
	v->tcache.cached_total_length = 0;
 
	v->compatible_railtypes = RAILTYPES_NONE;
 

	
 
	bool train_can_tilt = true;
 

	
 
	for (Train *u = v; u != NULL; u = u->Next()) {
 
		const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
 

	
 
		/* Check the v->first cache. */
 
		assert(u->First() == v);
 

	
 
		/* update the 'first engine' */
 
		u->tcache.first_engine = v == u ? INVALID_ENGINE : first_engine;
 
		u->railtype = rvi_u->railtype;
 

	
 
		if (IsTrainEngine(u)) first_engine = u->engine_type;
 

	
 
		/* Set user defined data to its default value */
 
		u->tcache.user_def_data = rvi_u->user_def_data;
 
		v->InvalidateNewGRFCache();
 
		u->InvalidateNewGRFCache();
 
	}
 

	
 
	for (Train *u = v; u != NULL; u = u->Next()) {
 
@@ -326,49 +325,49 @@ void TrainConsistChanged(Train *v, bool 
 
			veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
 
		}
 
		if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
 
		veh_len = 8 - Clamp(veh_len, 0, 7);
 

	
 
		/* verify length hasn't changed */
 
		if (same_length && veh_len != u->tcache.cached_veh_length) RailVehicleLengthChanged(u);
 

	
 
		/* update vehicle length? */
 
		if (!same_length) u->tcache.cached_veh_length = veh_len;
 

	
 
		v->tcache.cached_total_length += u->tcache.cached_veh_length;
 
		v->InvalidateNewGRFCache();
 
		u->InvalidateNewGRFCache();
 
	}
 

	
 
	/* store consist weight/max speed in cache */
 
	v->tcache.cached_max_speed = max_speed;
 
	v->tcache.cached_tilt = train_can_tilt;
 
	v->tcache.cached_max_curve_speed = GetTrainCurveSpeedLimit(v);
 

	
 
	/* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */
 
	TrainCargoChanged(v);
 

	
 
	if (IsFrontEngine(v)) {
 
	if (v->IsFrontEngine()) {
 
		UpdateTrainAcceleration(v);
 
		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
	}
 
}
 

	
 
enum AccelType {
 
	AM_ACCEL,
 
	AM_BRAKE
 
};
 

	
 
/**
 
 * Get the stop location of (the center) of the front vehicle of a train at
 
 * a platform of a station.
 
 * @param station_id     the ID of the station where we're stopping
 
 * @param tile           the tile where the vehicle currently is
 
 * @param v              the vehicle to get the stop location of
 
 * @param station_ahead  'return' the amount of 1/16th tiles in front of the train
 
 * @param station_length 'return' the station length in 1/16th tiles
 
 * @return the location, calculated from the begin of the station to stop at.
 
 */
 
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
 
{
 
	const Station *st = Station::Get(station_id);
 
	*station_ahead  = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE;
 
@@ -462,49 +461,49 @@ int GetTrainCurveSpeedLimit(Train *v)
 
		}
 
	}
 

	
 
	if (max_speed != absolute_max_speed) {
 
		/* Apply the engine's rail type curve speed advantage, if it slowed by curves */
 
		const RailtypeInfo *rti = GetRailTypeInfo(v->railtype);
 
		max_speed += (max_speed / 2) * rti->curve_speed;
 

	
 
		if (v->tcache.cached_tilt) {
 
			/* Apply max_speed bonus of 20% for a tilting train */
 
			max_speed += max_speed / 5;
 
		}
 
	}
 

	
 
	return max_speed;
 
}
 

	
 
/** new acceleration*/
 
static int GetTrainAcceleration(Train *v, bool mode)
 
{
 
	int max_speed = v->tcache.cached_max_curve_speed;
 
	assert(max_speed == GetTrainCurveSpeedLimit(v)); // safety check, will be removed later
 
	int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
 

	
 
	if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
 
	if (IsTileType(v->tile, MP_STATION) && v->IsFrontEngine()) {
 
		StationID sid = GetStationIndex(v->tile);
 
		if (v->current_order.ShouldStopAtStation(v, sid)) {
 
			int station_ahead;
 
			int station_length;
 
			int stop_at = GetTrainStopLocation(sid, v->tile, v, &station_ahead, &station_length);
 

	
 
			/* The distance to go is whatever is still ahead of the train minus the
 
			 * distance from the train's stop location to the end of the platform */
 
			int distance_to_go = station_ahead / TILE_SIZE - (station_length - stop_at) / TILE_SIZE;
 

	
 
			if (distance_to_go > 0) {
 
				int st_max_speed = 120;
 

	
 
				int delta_v = v->cur_speed / (distance_to_go + 1);
 
				if (v->max_speed > (v->cur_speed - delta_v)) {
 
					st_max_speed = v->cur_speed - (delta_v / 10);
 
				}
 

	
 
				st_max_speed = max(st_max_speed, 25 * distance_to_go);
 
				max_speed = min(max_speed, st_max_speed);
 
			}
 
		}
 
	}
 

	
 
@@ -556,49 +555,49 @@ static int GetTrainAcceleration(Train *v
 
				force /= 10;
 
				if (mode == AM_ACCEL && force > max_te) force = max_te;
 
				break;
 

	
 
			default: NOT_REACHED();
 
			case RAILTYPE_MAGLEV:
 
				force = power / 25;
 
				break;
 
		}
 
	} else {
 
		/* "kickoff" acceleration */
 
		force = (mode == AM_ACCEL && v->railtype != RAILTYPE_MAGLEV) ? min(max_te, power) : power;
 
		force = max(force, (mass * 8) + resistance);
 
	}
 

	
 
	if (mode == AM_ACCEL) {
 
		return (force - resistance) / (mass * 2);
 
	} else {
 
		return min(-force - resistance, -10000) / mass;
 
	}
 
}
 

	
 
void UpdateTrainAcceleration(Train *v)
 
{
 
	assert(IsFrontEngine(v));
 
	assert(v->IsFrontEngine());
 

	
 
	v->max_speed = v->tcache.cached_max_speed;
 

	
 
	uint power = v->tcache.cached_power;
 
	uint weight = v->tcache.cached_weight;
 
	assert(weight != 0);
 
	v->acceleration = Clamp(power / weight * 4, 1, 255);
 
}
 

	
 
static SpriteID GetDefaultTrainSprite(uint8 spritenum, Direction direction)
 
{
 
	return ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
 
}
 

	
 
SpriteID Train::GetImage(Direction direction) 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)));
 
		if (sprite != 0) return sprite;
 
@@ -918,49 +917,49 @@ CommandCost CmdBuildRailVehicle(TileInde
 
	}
 

	
 
	return value;
 
}
 

	
 

	
 
/* Check if all the wagons of the given train are in a depot, returns the
 
 * number of cars (including loco) then. If not it returns -1 */
 
int CheckTrainInDepot(const Train *v, bool needs_to_be_stopped)
 
{
 
	TileIndex tile = v->tile;
 

	
 
	/* check if stopped in a depot */
 
	if (!IsRailDepotTile(tile) || v->cur_speed != 0) return -1;
 

	
 
	int count = 0;
 
	for (; v != NULL; v = v->Next()) {
 
		/* This count is used by the depot code to determine the number of engines
 
		 * in the consist. Exclude articulated parts so that autoreplacing to
 
		 * engines with more articulated parts than before works correctly.
 
		 *
 
		 * Also skip counting rear ends of multiheaded engines */
 
		if (!IsArticulatedPart(v) && !IsRearDualheaded(v)) count++;
 
		if (v->track != TRACK_BIT_DEPOT || v->tile != tile ||
 
				(IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
 
				(v->IsFrontEngine() && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
 
			return -1;
 
		}
 
	}
 

	
 
	return count;
 
}
 

	
 
/* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
 
int CheckTrainStoppedInDepot(const Train *v)
 
{
 
	return CheckTrainInDepot(v, true);
 
}
 

	
 
/* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
 
inline bool CheckTrainIsInsideDepot(const Train *v)
 
{
 
	return CheckTrainInDepot(v, false) > 0;
 
}
 

	
 
/**
 
 * Unlink a rail wagon from the consist.
 
 * @param v Vehicle to remove.
 
 * @param first The first vehicle of the consist.
 
 * @return The first vehicle of the consist.
 
@@ -1012,49 +1011,49 @@ static Train *FindGoodVehiclePos(const T
 
 * add a vehicle v behind vehicle dest
 
 * use this function since it sets flags as needed
 
 */
 
static void AddWagonToConsist(Train *v, Train *dest)
 
{
 
	UnlinkWagon(v, v->First());
 
	if (dest == NULL) return;
 

	
 
	Train *next = dest->Next();
 
	v->SetNext(NULL);
 
	dest->SetNext(v);
 
	v->SetNext(next);
 
	ClearFreeWagon(v);
 
	ClearFrontEngine(v);
 
}
 

	
 
/*
 
 * move around on the train so rear engines are placed correctly according to the other engines
 
 * always call with the front engine
 
 */
 
static void NormaliseTrainConsist(Train *v)
 
{
 
	if (IsFreeWagon(v)) return;
 

	
 
	assert(IsFrontEngine(v));
 
	assert(v->IsFrontEngine());
 

	
 
	for (; v != NULL; v = GetNextVehicle(v)) {
 
		if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
 

	
 
		/* make sure that there are no free cars before next engine */
 
		Train *u;
 
		for (u = v; u->Next() != NULL && !IsTrainEngine(u->Next()); u = u->Next()) {}
 

	
 
		if (u == v->other_multiheaded_part) continue;
 
		AddWagonToConsist(v->other_multiheaded_part, u);
 
	}
 
}
 

	
 
/** Move a rail vehicle around inside the depot.
 
 * @param tile unused
 
 * @param flags type of operation
 
 *              Note: DC_AUTOREPLACE is set when autoreplace tries to undo its modifications or moves vehicles to temporary locations inside the depot.
 
 * @param p1 various bitstuffed elements
 
 * - p1 (bit  0 - 15) source vehicle index
 
 * - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line
 
 * @param p2 (bit 0) move all vehicles following the source vehicle
 
 */
 
CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
@@ -1115,70 +1114,70 @@ CommandCost CmdMoveRailVehicle(TileIndex
 

	
 
		/* check the destination row if the source and destination aren't the same. */
 
		if (src_head != dst_head) {
 
			int dst_len = 0;
 

	
 
			if (dst_head != NULL) {
 
				/* check if all vehicles in the dest train are stopped. */
 
				dst_len = CheckTrainStoppedInDepot(dst_head);
 
				if (dst_len < 0) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
 
			}
 

	
 
			/* We are moving between rows, so only count the wagons from the source
 
			 * row that are being moved. */
 
			if (HasBit(p2, 0)) {
 
				const Train *u;
 
				for (u = src_head; u != src && u != NULL; u = GetNextVehicle(u))
 
					src_len--;
 
			} else {
 
				/* If moving only one vehicle, just count that. */
 
				src_len = 1;
 
			}
 

	
 
			if (src_len + dst_len > max_len) {
 
				/* Abort if we're adding too many wagons to a train. */
 
				if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
 
				if (dst_head != NULL && dst_head->IsFrontEngine()) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
 
				/* Abort if we're making a train on a new row. */
 
				if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
 
			}
 
		} else {
 
			/* Abort if we're creating a new train on an existing row. */
 
			if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
 
				return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
 
		}
 
	}
 

	
 
	/* moving a loco to a new line?, then we need to assign a unitnumber. */
 
	if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
 
	if (dst == NULL && !src->IsFrontEngine() && IsTrainEngine(src)) {
 
		UnitID unit_num = ((flags & DC_AUTOREPLACE) != 0 ? 0 : GetFreeUnitNumber(VEH_TRAIN));
 
		if (unit_num > _settings_game.vehicle.max_trains)
 
			return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 

	
 
		if (flags & DC_EXEC) src->unitnumber = unit_num;
 
	}
 

	
 
	/* When we move the front vehicle, the second vehicle might need a unitnumber */
 
	if (!HasBit(p2, 0) && (IsFreeWagon(src) || (IsFrontEngine(src) && dst == NULL)) && (flags & DC_AUTOREPLACE) == 0) {
 
	if (!HasBit(p2, 0) && (IsFreeWagon(src) || (src->IsFrontEngine() && dst == NULL)) && (flags & DC_AUTOREPLACE) == 0) {
 
		Vehicle *second = GetNextUnit(src);
 
		if (second != NULL && IsTrainEngine(second) && GetFreeUnitNumber(VEH_TRAIN) > _settings_game.vehicle.max_trains) {
 
			return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
		}
 
	}
 

	
 
	/*
 
	 * Check whether the vehicles in the source chain are in the destination
 
	 * chain. This can easily be done by checking whether the first vehicle
 
	 * of the source chain is in the destination chain as the Next/Previous
 
	 * pointers always make a doubly linked list of it where the assumption
 
	 * v->Next()->Previous() == v holds (assuming v->Next() != NULL).
 
	 */
 
	bool src_in_dst = false;
 
	for (Train *v = dst_head; !src_in_dst && v != NULL; v = v->Next()) src_in_dst = v == src;
 

	
 
	/*
 
	 * If the source chain is in the destination chain then the user is
 
	 * only reordering the vehicles, thus not attaching a new vehicle.
 
	 * Therefor the 'allow wagon attach' callback does not need to be
 
	 * called. If it would be called strange things would happen because
 
	 * one 'attaches' an already 'attached' vehicle causing more trouble
 
	 * than it actually solves (infinite loops and such).
 
	 */
 
@@ -1247,210 +1246,210 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
			 */
 
			Train *to_add = next_to_attach;
 
			next_to_attach = next_to_attach->Next();
 

	
 
			to_add->SetNext(NULL);
 
			dst_tail->SetNext(to_add);
 
			dst_tail = dst_tail->Next();
 
		}
 

	
 
		/*
 
		 * When we reach this the attaching is allowed. It also means that the
 
		 * chain of vehicles to attach is empty, so we do not need to merge that.
 
		 * This means only the splitting needs to be done.
 
		 * Furthermore the 'previous' link of the original source vehicle needs
 
		 * to be restored, otherwise the train goes missing in the depot.
 
		 */
 
		orig_tail->SetNext(NULL);
 
		if (src_previous != NULL) src_previous->SetNext(src);
 
	}
 

	
 
	/* do it? */
 
	if (flags & DC_EXEC) {
 
		/* If we move the front Engine and if the second vehicle is not an engine
 
		   add the whole vehicle to the DEFAULT_GROUP */
 
		if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
 
		if (src->IsFrontEngine() && !IsDefaultGroupID(src->group_id)) {
 
			Vehicle *v = GetNextVehicle(src);
 

	
 
			if (v != NULL && IsTrainEngine(v)) {
 
				v->group_id   = src->group_id;
 
				src->group_id = DEFAULT_GROUP;
 
			}
 
		}
 

	
 
		if (HasBit(p2, 0)) {
 
			/* unlink ALL wagons */
 
			if (src != src_head) {
 
				Train *v = src_head;
 
				while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
 
				GetLastEnginePart(v)->SetNext(NULL);
 
			} else {
 
				InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line
 
				src_head = NULL;
 
			}
 
		} else {
 
			/* if moving within the same chain, dont use dst_head as it may get invalidated */
 
			if (src_head == dst_head) dst_head = NULL;
 
			/* unlink single wagon from linked list */
 
			src_head = UnlinkWagon(src, src_head);
 
			GetLastEnginePart(src)->SetNext(NULL);
 
		}
 

	
 
		if (dst == NULL) {
 
			/* We make a new line in the depot, so we know already that we invalidate the window data */
 
			InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
 

	
 
			/* move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. */
 
			if (IsTrainEngine(src)) {
 
				if (!IsFrontEngine(src)) {
 
				if (!src->IsFrontEngine()) {
 
					/* setting the type to 0 also involves setting up the orders field. */
 
					SetFrontEngine(src);
 
					assert(src->orders.list == NULL);
 

	
 
					/* Decrease the engines number of the src engine_type */
 
					if (!IsDefaultGroupID(src->group_id) && Group::IsValidID(src->group_id)) {
 
						Group::Get(src->group_id)->num_engines[src->engine_type]--;
 
					}
 

	
 
					/* If we move an engine to a new line affect it to the DEFAULT_GROUP */
 
					src->group_id = DEFAULT_GROUP;
 
				}
 
			} else {
 
				SetFreeWagon(src);
 
			}
 
			dst_head = src;
 
		} else {
 
			if (IsFrontEngine(src)) {
 
			if (src->IsFrontEngine()) {
 
				/* the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. */
 
				DeleteWindowById(WC_VEHICLE_VIEW, src->index);
 
				DeleteWindowById(WC_VEHICLE_ORDERS, src->index);
 
				DeleteWindowById(WC_VEHICLE_REFIT, src->index);
 
				DeleteWindowById(WC_VEHICLE_DETAILS, src->index);
 
				DeleteWindowById(WC_VEHICLE_TIMETABLE, src->index);
 
				DeleteVehicleOrders(src);
 
				RemoveVehicleFromGroup(src);
 
			}
 

	
 
			if (IsFrontEngine(src) || IsFreeWagon(src)) {
 
			if (src->IsFrontEngine() || IsFreeWagon(src)) {
 
				InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
 
				ClearFrontEngine(src);
 
				ClearFreeWagon(src);
 
				src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
 
			}
 

	
 
			/* link in the wagon(s) in the chain. */
 
			{
 
				Train *v;
 

	
 
				for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)) {}
 
				GetLastEnginePart(v)->SetNext(dst->Next());
 
			}
 
			dst->SetNext(src);
 
		}
 

	
 
		if (src->other_multiheaded_part != NULL) {
 
			if (src->other_multiheaded_part == src_head) {
 
				src_head = src_head->Next();
 
			}
 
			AddWagonToConsist(src->other_multiheaded_part, src);
 
		}
 

	
 
		/* If there is an engine behind first_engine we moved away, it should become new first_engine
 
		 * To do this, CmdMoveRailVehicle must be called once more
 
		 * we can't loop forever here because next time we reach this line we will have a front engine */
 
		if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
 
		if (src_head != NULL && !src_head->IsFrontEngine() && IsTrainEngine(src_head)) {
 
			/* As in CmdMoveRailVehicle src_head->group_id will be equal to DEFAULT_GROUP
 
			 * we need to save the group and reaffect it to src_head */
 
			const GroupID tmp_g = src_head->group_id;
 
			CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1, text);
 
			SetTrainGroupID(src_head, tmp_g);
 
			src_head = NULL; // don't do anything more to this train since the new call will do it
 
		}
 

	
 
		if (src_head != NULL) {
 
			NormaliseTrainConsist(src_head);
 
			TrainConsistChanged(src_head, false);
 
			UpdateTrainGroupID(src_head);
 
			if (IsFrontEngine(src_head)) {
 
			if (src_head->IsFrontEngine()) {
 
				/* Update the refit button and window */
 
				InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
 
				InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH);
 
			}
 
			/* Update the depot window */
 
			InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
 
		}
 

	
 
		if (dst_head != NULL) {
 
			NormaliseTrainConsist(dst_head);
 
			TrainConsistChanged(dst_head, false);
 
			UpdateTrainGroupID(dst_head);
 
			if (IsFrontEngine(dst_head)) {
 
			if (dst_head->IsFrontEngine()) {
 
				/* Update the refit button and window */
 
				InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH);
 
				InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
 
			}
 
			/* Update the depot window */
 
			InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
 
		}
 

	
 
		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/** Sell a (single) train wagon/engine.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 the wagon/engine index
 
 * @param p2 the selling mode
 
 * - p2 = 0: only sell the single dragged wagon/engine (and any belonging rear-engines)
 
 * - p2 = 1: sell the vehicle and all vehicles following it in the chain
 
 *           if the wagon is dragged, don't delete the possibly belonging rear-engine to some front
 
 */
 
CommandCost CmdSellRailWagon(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	/* Check if we deleted a vehicle window */
 
	Window *w = NULL;
 

	
 
	Train *v = Train::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 
	if (p2 > 1) return CMD_ERROR;
 

	
 
	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
 

	
 
	while (IsArticulatedPart(v)) v = v->Previous();
 
	Train *first = v->First();
 

	
 
	/* make sure the vehicle is stopped in the depot */
 
	if (CheckTrainStoppedInDepot(first) < 0) {
 
		return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
 
	}
 

	
 
	if (IsRearDualheaded(v)) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
 

	
 
	if (flags & DC_EXEC) {
 
		if (v == first && IsFrontEngine(first)) {
 
		if (v == first && first->IsFrontEngine()) {
 
			DeleteWindowById(WC_VEHICLE_VIEW, first->index);
 
			DeleteWindowById(WC_VEHICLE_ORDERS, first->index);
 
			DeleteWindowById(WC_VEHICLE_REFIT, first->index);
 
			DeleteWindowById(WC_VEHICLE_DETAILS, first->index);
 
			DeleteWindowById(WC_VEHICLE_TIMETABLE, first->index);
 
		}
 
		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
 
		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	}
 

	
 
	CommandCost cost(EXPENSES_NEW_VEHICLES);
 
	switch (p2) {
 
		case 0: { // Delete given wagon
 
			bool switch_engine = false;    // update second wagon to engine?
 

	
 
			/* 1. Delete the engine, if it is dualheaded also delete the matching
 
			 * rear engine of the loco (from the point of deletion onwards) */
 
			Train *rear = (IsMultiheaded(v) &&
 
				IsTrainEngine(v)) ? v->other_multiheaded_part : NULL;
 

	
 
			if (rear != NULL) {
 
				cost.AddCost(-rear->value);
 
				if (flags & DC_EXEC) {
 
					UnlinkWagon(rear, first);
 
@@ -1491,49 +1490,49 @@ CommandCost CmdSellRailWagon(TileIndex t
 
						/* We are selling a free wagon, and construct a new train at the same time.
 
						 * This needs lots of extra checks (e.g. train limit), which are done by first moving
 
						 * the remaining vehicles to a new row */
 
						cost.AddCost(DoCommand(0, new_f->index | INVALID_VEHICLE << 16, 1, flags, CMD_MOVE_RAIL_VEHICLE));
 
						if (cost.Failed()) return cost;
 
					}
 
				}
 
			}
 

	
 
			/* 3. Delete the requested wagon */
 
			cost.AddCost(-v->value);
 
			if (flags & DC_EXEC) {
 
				first = UnlinkWagon(v, first);
 
				delete v;
 

	
 
				/* 4 If the second wagon was an engine, update it to front_engine
 
				 * which UnlinkWagon() has changed to TS_Free_Car */
 
				if (switch_engine) SetFrontEngine(first);
 

	
 
				/* 5. If the train still exists, update its acceleration, window, etc. */
 
				if (first != NULL) {
 
					NormaliseTrainConsist(first);
 
					TrainConsistChanged(first, false);
 
					UpdateTrainGroupID(first);
 
					if (IsFrontEngine(first)) InvalidateWindow(WC_VEHICLE_REFIT, first->index);
 
					if (first->IsFrontEngine()) InvalidateWindow(WC_VEHICLE_REFIT, first->index);
 
				}
 

	
 
			}
 
		} break;
 
		case 1: { // Delete wagon and all wagons after it given certain criteria
 
			/* Start deleting every vehicle after the selected one
 
			 * If we encounter a matching rear-engine to a front-engine
 
			 * earlier in the chain (before deletion), leave it alone */
 
			for (Train *tmp; v != NULL; v = tmp) {
 
				tmp = GetNextVehicle(v);
 

	
 
				if (IsMultiheaded(v)) {
 
					if (IsTrainEngine(v)) {
 
						/* We got a front engine of a multiheaded set. Now we will sell the rear end too */
 
						Train *rear = v->other_multiheaded_part;
 

	
 
						if (rear != NULL) {
 
							cost.AddCost(-rear->value);
 

	
 
							/* If this is a multiheaded vehicle with nothing
 
							 * between the parts, tmp will be pointing to the
 
							 * rear part, which is unlinked from the train and
 
							 * deleted here. However, because tmp has already
 
							 * been set it needs to be updated now so that the
 
@@ -1699,56 +1698,58 @@ static void ReverseTrainSwapVeh(Train *v
 
	/* Update train's power incase tiles were different rail type */
 
	TrainPowerChanged(v);
 
}
 

	
 

	
 
/**
 
 * Check if the vehicle is a train
 
 * @param v vehicle on tile
 
 * @return v if it is a train, NULL otherwise
 
 */
 
static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
 
{
 
	return (v->type == VEH_TRAIN) ? v : NULL;
 
}
 

	
 

	
 
/**
 
 * Checks if a train is approaching a rail-road crossing
 
 * @param v vehicle on tile
 
 * @param data tile with crossing we are testing
 
 * @return v if it is approaching a crossing, NULL otherwise
 
 */
 
static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data)
 
{
 
	/* not a train || not front engine || crashed */
 
	if (v->type != VEH_TRAIN || !IsFrontEngine(v) || (v->vehstatus & VS_CRASHED)) return NULL;
 

	
 
	TileIndex tile = *(TileIndex*)data;
 

	
 
	if (TrainApproachingCrossingTile(Train::From(v)) != tile) return NULL;
 

	
 
	return v;
 
	if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
 

	
 
	Train *t = Train::From(v);
 
	if (!t->IsFrontEngine()) return NULL;
 

	
 
	TileIndex tile = *(TileIndex *)data;
 

	
 
	if (TrainApproachingCrossingTile(t) != tile) return NULL;
 

	
 
	return t;
 
}
 

	
 

	
 
/**
 
 * Finds a vehicle approaching rail-road crossing
 
 * @param tile tile to test
 
 * @return true if a vehicle is approaching the crossing
 
 * @pre tile is a rail-road crossing
 
 */
 
static bool TrainApproachingCrossing(TileIndex tile)
 
{
 
	assert(IsLevelCrossingTile(tile));
 

	
 
	DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile));
 
	TileIndex tile_from = tile + TileOffsByDiagDir(dir);
 

	
 
	if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true;
 

	
 
	dir = ReverseDiagDir(dir);
 
	tile_from = tile + TileOffsByDiagDir(dir);
 

	
 
	return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum);
 
}
 

	
 
@@ -2491,49 +2492,49 @@ static void ClearPathReservation(const T
 
				SetTunnelBridgeReservation(end, false);
 

	
 
				if (_settings_client.gui.show_track_reservation) {
 
					MarkTileDirtyByTile(tile);
 
					MarkTileDirtyByTile(end);
 
				}
 
			}
 
		}
 
	} else if (IsRailwayStationTile(tile)) {
 
		TileIndex new_tile = TileAddByDiagDir(tile, dir);
 
		/* If the new tile is not a further tile of the same station, we
 
		 * clear the reservation for the whole platform. */
 
		if (!IsCompatibleTrainStationTile(new_tile, tile)) {
 
			SetRailwayStationPlatformReservation(tile, ReverseDiagDir(dir), false);
 
		}
 
	} else {
 
		/* Any other tile */
 
		UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
 
	}
 
}
 

	
 
/** Free the reserved path in front of a vehicle. */
 
void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_td)
 
{
 
	assert(IsFrontEngine(v));
 
	assert(v->IsFrontEngine());
 

	
 
	TileIndex tile = origin != INVALID_TILE ? origin : v->tile;
 
	Trackdir  td = orig_td != INVALID_TRACKDIR ? orig_td : v->GetVehicleTrackdir();
 
	bool      free_tile = tile != v->tile || !(IsRailwayStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE));
 
	StationID station_id = IsRailwayStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION;
 

	
 
	/* Don't free reservation if it's not ours. */
 
	if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return;
 

	
 
	CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
 
	while (ft.Follow(tile, td)) {
 
		tile = ft.m_new_tile;
 
		TrackdirBits bits = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile));
 
		td = RemoveFirstTrackdir(&bits);
 
		assert(bits == TRACKDIR_BIT_NONE);
 

	
 
		if (!IsValidTrackdir(td)) break;
 

	
 
		if (IsTileType(tile, MP_RAILWAY)) {
 
			if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) {
 
				/* Conventional signal along trackdir: remove reservation and stop. */
 
				UnreserveRailTrack(tile, TrackdirToTrack(td));
 
				break;
 
			}
 
@@ -3077,49 +3078,49 @@ static Track ChooseTrainTrack(Train *v, 
 
			if (mark_stuck) MarkTrainAsStuck(v);
 
			if (got_reservation != NULL) *got_reservation = false;
 
			changed_signal = false;
 
		}
 
		break;
 
	}
 

	
 
	TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir()));
 

	
 
	if (changed_signal) MarkTileDirtyByTile(tile);
 

	
 
	return best_track;
 
}
 

	
 
/**
 
 * Try to reserve a path to a safe position.
 
 *
 
 * @param v The vehicle
 
 * @param mark_as_stuck Should the train be marked as stuck on a failed reservation?
 
 * @param first_tile_okay True if no path should be reserved if the current tile is a safe position.
 
 * @return True if a path could be reserved.
 
 */
 
bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
 
{
 
	assert(v->type == VEH_TRAIN && IsFrontEngine(v));
 
	assert(v->IsFrontEngine());
 

	
 
	/* We have to handle depots specially as the track follower won't look
 
	 * at the depot tile itself but starts from the next tile. If we are still
 
	 * inside the depot, a depot reservation can never be ours. */
 
	if (v->track == TRACK_BIT_DEPOT) {
 
		if (GetDepotWaypointReservation(v->tile)) {
 
			if (mark_as_stuck) MarkTrainAsStuck(v);
 
			return false;
 
		} else {
 
			/* Depot not reserved, but the next tile might be. */
 
			TileIndex next_tile = TileAddByDiagDir(v->tile, GetRailDepotDirection(v->tile));
 
			if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false;
 
		}
 
	}
 

	
 
	/* Special check if we are in front of a two-sided conventional signal. */
 
	DiagDirection dir = TrainExitDir(v->direction, v->track);
 
	TileIndex next_tile = TileAddByDiagDir(v->tile, dir);
 
	if (IsTileType(next_tile, MP_RAILWAY) && HasReservedTracks(next_tile, DiagdirReachesTracks(dir))) {
 
		/* Can have only one reserved trackdir. */
 
		Trackdir td = FindFirstTrackdir(TrackBitsToTrackdirBits(GetReservedTrackbits(next_tile)) & DiagdirReachesTrackdirs(dir));
 
		if (HasSignalOnTrackdir(next_tile, td) && HasSignalOnTrackdir(next_tile, ReverseTrackdir(td)) &&
 
				!IsPbsSignal(GetSignalType(next_tile, TrackdirToTrack(td)))) {
 
			/* Signal already reserved, is not ours. */
 
@@ -3398,49 +3399,49 @@ static byte AfterSetTrainPos(Train *v, b
 
			 * To check whether the current tile is sloped, and in which
 
			 * direction it is sloped, we get the 'z' at the center of
 
			 * the tile (middle_z) and the edge of the tile (old_z),
 
			 * which we then can compare. */
 
			static const int HALF_TILE_SIZE = TILE_SIZE / 2;
 
			static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1);
 

	
 
			byte middle_z = GetSlopeZ((v->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (v->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE);
 

	
 
			if (middle_z != v->z_pos) {
 
				SetBit(v->flags, (middle_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
 
			}
 
		}
 
	}
 

	
 
	VehicleMove(v, true);
 
	return old_z;
 
}
 

	
 
/* Check if the vehicle is compatible with the specified tile */
 
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
 
{
 
	return
 
		IsTileOwner(tile, v->owner) && (
 
			!IsFrontEngine(v) ||
 
			!v->IsFrontEngine() ||
 
			HasBit(v->compatible_railtypes, GetRailType(tile))
 
		);
 
}
 

	
 
struct RailtypeSlowdownParams {
 
	byte small_turn, large_turn;
 
	byte z_up; // fraction to remove when moving up
 
	byte z_down; // fraction to remove when moving down
 
};
 

	
 
static const RailtypeSlowdownParams _railtype_slowdown[] = {
 
	/* normal accel */
 
	{256 / 4, 256 / 2, 256 / 4, 2}, ///< normal
 
	{256 / 4, 256 / 2, 256 / 4, 2}, ///< electrified
 
	{256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail
 
	{0,       256 / 2, 256 / 4, 2}, ///< maglev
 
};
 

	
 
/** Modify the speed of the vehicle due to a change in altitude */
 
static inline void AffectSpeedByZChange(Train *v, byte old_z)
 
{
 
	if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL) return;
 

	
 
	const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->railtype];
 
@@ -3452,49 +3453,49 @@ static inline void AffectSpeedByZChange(
 
		if (spd <= v->max_speed) v->cur_speed = spd;
 
	}
 
}
 

	
 
static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
 
{
 
	if (IsTileType(tile, MP_RAILWAY) &&
 
			GetRailTileType(tile) == RAIL_TILE_SIGNALS) {
 
		TrackdirBits tracks = TrackBitsToTrackdirBits(GetTrackBits(tile)) & DiagdirReachesTrackdirs(dir);
 
		Trackdir trackdir = FindFirstTrackdir(tracks);
 
		if (UpdateSignalsOnSegment(tile,  TrackdirToExitdir(trackdir), GetTileOwner(tile)) == SIGSEG_PBS && HasSignalOnTrackdir(tile, trackdir)) {
 
			/* A PBS block with a non-PBS signal facing us? */
 
			if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
 
		}
 
	}
 
	return false;
 
}
 

	
 

	
 
static void SetVehicleCrashed(Train *v)
 
{
 
	if (v->crash_anim_pos != 0) return;
 

	
 
	/* Free a possible path reservation and try to mark all tiles occupied by the train reserved. */
 
	if (IsFrontEngine(v)) {
 
	if (v->IsFrontEngine()) {
 
		/* Remove all reservations, also the ones currently under the train
 
		 * and any railway station paltform reservation. */
 
		FreeTrainTrackReservation(v);
 
		for (const Train *u = v; u != NULL; u = u->Next()) {
 
			ClearPathReservation(u, u->tile, u->GetVehicleTrackdir());
 
			if (IsTileType(u->tile, MP_TUNNELBRIDGE)) {
 
				/* ClearPathReservation will not free the wormhole exit
 
				 * if the train has just entered the wormhole. */
 
				SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(u->tile), false);
 
			}
 
		}
 
	}
 

	
 
	/* we may need to update crossing we were approaching */
 
	TileIndex crossing = TrainApproachingCrossingTile(v);
 

	
 
	v->crash_anim_pos++;
 

	
 
	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 

	
 
	if (v->track == TRACK_BIT_DEPOT) {
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
	}
 
@@ -3610,85 +3611,88 @@ static bool CheckTrainCollision(Train *v
 
	tcc.num = 0;
 

	
 
	/* find colliding vehicles */
 
	if (v->track == TRACK_BIT_WORMHOLE) {
 
		FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
 
		FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
 
	} else {
 
		FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
 
	}
 

	
 
	/* any dead -> no crash */
 
	if (tcc.num == 0) return false;
 

	
 
	SetDParam(0, tcc.num);
 
	AddVehicleNewsItem(STR_NEWS_TRAIN_CRASH,
 
		NS_ACCIDENT,
 
		v->index
 
	);
 

	
 
	ModifyStationRatingAround(v->tile, v->owner, -160, 30);
 
	SndPlayVehicleFx(SND_13_BIG_CRASH, v);
 
	return true;
 
}
 

	
 
static Vehicle *CheckVehicleAtSignal(Vehicle *v, void *data)
 
static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
 
{
 
	if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
 

	
 
	Train *t = Train::From(v);
 
	DiagDirection exitdir = *(DiagDirection *)data;
 

	
 
	/* front engine of a train, not inside wormhole or depot, not crashed */
 
	if (v->type == VEH_TRAIN && IsFrontEngine(v) && (Train::From(v)->track & TRACK_BIT_MASK) && !(v->vehstatus & VS_CRASHED)) {
 
		if (v->cur_speed <= 5 && TrainExitDir(v->direction, Train::From(v)->track) == exitdir) return v;
 
	}
 

	
 
	return NULL;
 
	/* not front engine of a train, inside wormhole or depot, crashed */
 
	if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return NULL;
 

	
 
	if (t->cur_speed > 5 || TrainExitDir(t->direction, t->track) != exitdir) return NULL;
 

	
 
	return t;
 
}
 

	
 
static void TrainController(Train *v, Vehicle *nomove)
 
{
 
	Train *first = v->First();
 
	Train *prev;
 
	bool direction_changed = false; // has direction of any part changed?
 

	
 
	/* For every vehicle after and including the given vehicle */
 
	for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
 
		DiagDirection enterdir = DIAGDIR_BEGIN;
 
		bool update_signals_crossing = false; // will we update signals or crossing state?
 

	
 
		GetNewVehiclePosResult gp = GetNewVehiclePos(v);
 
		if (v->track != TRACK_BIT_WORMHOLE) {
 
			/* Not inside tunnel */
 
			if (gp.old_tile == gp.new_tile) {
 
				/* Staying in the old tile */
 
				if (v->track == TRACK_BIT_DEPOT) {
 
					/* Inside depot */
 
					gp.x = v->x_pos;
 
					gp.y = v->y_pos;
 
				} else {
 
					/* Not inside depot */
 

	
 
					/* Reverse when we are at the end of the track already, do not move to the new position */
 
					if (IsFrontEngine(v) && !TrainCheckIfLineEnds(v)) return;
 
					if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v)) return;
 

	
 
					uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
 
					if (HasBit(r, VETS_CANNOT_ENTER)) {
 
						goto invalid_rail;
 
					}
 
					if (HasBit(r, VETS_ENTERED_STATION)) {
 
						/* The new position is the end of the platform */
 
						TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
 
					}
 
				}
 
			} else {
 
				/* A new tile is about to be entered. */
 

	
 
				/* Determine what direction we're entering the new tile from */
 
				enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
 
				assert(IsValidDiagDirection(enterdir));
 

	
 
				/* Get the status of the tracks in the new tile and mask
 
				 * away the bits that aren't reachable. */
 
				TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir));
 
				TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
 

	
 
				TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
 
				TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs);
 
@@ -3716,49 +3720,49 @@ static void TrainController(Train *v, Ve
 
					/* Check if it's a red signal and that force proceed is not clicked. */
 
					if ((red_signals & chosen_track) && v->force_proceed == 0) {
 
						/* In front of a red signal */
 
						Trackdir i = FindFirstTrackdir(trackdirbits);
 

	
 
						/* Don't handle stuck trains here. */
 
						if (HasBit(v->flags, VRF_TRAIN_STUCK)) return;
 

	
 
						if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) {
 
							v->cur_speed = 0;
 
							v->subspeed = 0;
 
							v->progress = 255 - 100;
 
							if (_settings_game.pf.wait_oneway_signal == 255 || ++v->load_unload_time_rem < _settings_game.pf.wait_oneway_signal * 20) return;
 
						} else if (HasSignalOnTrackdir(gp.new_tile, i)) {
 
							v->cur_speed = 0;
 
							v->subspeed = 0;
 
							v->progress = 255 - 10;
 
							if (_settings_game.pf.wait_twoway_signal == 255 || ++v->load_unload_time_rem < _settings_game.pf.wait_twoway_signal * 73) {
 
								DiagDirection exitdir = TrackdirToExitdir(i);
 
								TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
 

	
 
								exitdir = ReverseDiagDir(exitdir);
 

	
 
								/* check if a train is waiting on the other side */
 
								if (!HasVehicleOnPos(o_tile, &exitdir, &CheckVehicleAtSignal)) return;
 
								if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return;
 
							}
 
						}
 

	
 
						/* If we would reverse but are currently in a PBS block and
 
						 * reversing of stuck trains is disabled, don't reverse. */
 
						if (_settings_game.pf.wait_for_pbs_path == 255 && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
 
							v->load_unload_time_rem = 0;
 
							return;
 
						}
 
						goto reverse_train_direction;
 
					} else {
 
						TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track));
 
					}
 
				} else {
 
					/* The wagon is active, simply follow the prev vehicle. */
 
					if (prev->tile == gp.new_tile) {
 
						/* Choose the same track as prev */
 
						if (prev->track == TRACK_BIT_WORMHOLE) {
 
							/* Vehicles entering tunnels enter the wormhole earlier than for bridges.
 
							 * However, just choose the track into the wormhole. */
 
							assert(IsTunnel(prev->tile));
 
							chosen_track = bits;
 
						} else {
 
							chosen_track = prev->track;
 
@@ -3784,162 +3788,162 @@ static void TrainController(Train *v, Ve
 
					chosen_track &= bits;
 
				}
 

	
 
				/* Make sure chosen track is a valid track */
 
				assert(
 
						chosen_track == TRACK_BIT_X     || chosen_track == TRACK_BIT_Y ||
 
						chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER ||
 
						chosen_track == TRACK_BIT_LEFT  || chosen_track == TRACK_BIT_RIGHT);
 

	
 
				/* Update XY to reflect the entrance to the new tile, and select the direction to use */
 
				const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir];
 
				gp.x = (gp.x & ~0xF) | b[0];
 
				gp.y = (gp.y & ~0xF) | b[1];
 
				Direction chosen_dir = (Direction)b[2];
 

	
 
				/* Call the landscape function and tell it that the vehicle entered the tile */
 
				uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
 
				if (HasBit(r, VETS_CANNOT_ENTER)) {
 
					goto invalid_rail;
 
				}
 

	
 
				if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
 
					Track track = FindFirstTrack(chosen_track);
 
					Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
 
					if (IsFrontEngine(v) && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
 
					if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
 
						SetSignalStateByTrackdir(gp.new_tile, tdir, SIGNAL_STATE_RED);
 
						MarkTileDirtyByTile(gp.new_tile);
 
					}
 

	
 
					/* Clear any track reservation when the last vehicle leaves the tile */
 
					if (v->Next() == NULL) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
 

	
 
					v->tile = gp.new_tile;
 

	
 
					if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
 
						TrainPowerChanged(v->First());
 
					}
 

	
 
					v->track = chosen_track;
 
					assert(v->track);
 
				}
 

	
 
				/* We need to update signal status, but after the vehicle position hash
 
				 * has been updated by AfterSetTrainPos() */
 
				update_signals_crossing = true;
 

	
 
				if (chosen_dir != v->direction) {
 
					if (prev == NULL && _settings_game.vehicle.train_acceleration_model == TAM_ORIGINAL) {
 
						const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->railtype];
 
						DirDiff diff = DirDifference(v->direction, chosen_dir);
 
						v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
 
					}
 
					direction_changed = true;
 
					v->direction = chosen_dir;
 
				}
 

	
 
				if (IsFrontEngine(v)) {
 
				if (v->IsFrontEngine()) {
 
					v->load_unload_time_rem = 0;
 

	
 
					/* If we are approching a crossing that is reserved, play the sound now. */
 
					TileIndex crossing = TrainApproachingCrossingTile(v);
 
					if (crossing != INVALID_TILE && GetCrossingReservation(crossing)) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
 

	
 
					/* Always try to extend the reservation when entering a tile. */
 
					CheckNextTrainTile(v);
 
				}
 

	
 
				if (HasBit(r, VETS_ENTERED_STATION)) {
 
					/* The new position is the location where we want to stop */
 
					TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
 
				}
 
			}
 
		} else {
 
			/* In a tunnel or on a bridge
 
			 * - for tunnels, only the part when the vehicle is not visible (part of enter/exit tile too)
 
			 * - for bridges, only the middle part - without the bridge heads */
 
			if (!(v->vehstatus & VS_HIDDEN)) {
 
				v->cur_speed =
 
					min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed);
 
			}
 

	
 
			if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
 
				/* Perform look-ahead on tunnel exit. */
 
				if (IsFrontEngine(v)) {
 
				if (v->IsFrontEngine()) {
 
					TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile)));
 
					CheckNextTrainTile(v);
 
				}
 
			} else {
 
				v->x_pos = gp.x;
 
				v->y_pos = gp.y;
 
				VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
 
				continue;
 
			}
 
		}
 

	
 
		/* update image of train, as well as delta XY */
 
		v->UpdateDeltaXY(v->direction);
 

	
 
		v->x_pos = gp.x;
 
		v->y_pos = gp.y;
 

	
 
		/* update the Z position of the vehicle */
 
		byte old_z = AfterSetTrainPos(v, (gp.new_tile != gp.old_tile));
 

	
 
		if (prev == NULL) {
 
			/* This is the first vehicle in the train */
 
			AffectSpeedByZChange(v, old_z);
 
		}
 

	
 
		if (update_signals_crossing) {
 
			if (IsFrontEngine(v)) {
 
			if (v->IsFrontEngine()) {
 
				if (TrainMovedChangeSignals(gp.new_tile, enterdir)) {
 
					/* We are entering a block with PBS signals right now, but
 
					 * not through a PBS signal. This means we don't have a
 
					 * reservation right now. As a conventional signal will only
 
					 * ever be green if no other train is in the block, getting
 
					 * a path should always be possible. If the player built
 
					 * such a strange network that it is not possible, the train
 
					 * will be marked as stuck and the player has to deal with
 
					 * the problem. */
 
					if ((!HasReservedTracks(gp.new_tile, v->track) &&
 
							!TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) ||
 
							!TryPathReserve(v)) {
 
						MarkTrainAsStuck(v);
 
					}
 
				}
 
			}
 

	
 
			/* Signals can only change when the first
 
			 * (above) or the last vehicle moves. */
 
			if (v->Next() == NULL) {
 
				TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
 
				if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile);
 
			}
 
		}
 

	
 
		/* Do not check on every tick to save some computing time. */
 
		if (IsFrontEngine(v) && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
 
		if (v->IsFrontEngine() && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
 
	}
 

	
 
	if (direction_changed) first->tcache.cached_max_curve_speed = GetTrainCurveSpeedLimit(first);
 

	
 
	return;
 

	
 
invalid_rail:
 
	/* We've reached end of line?? */
 
	if (prev != NULL) error("Disconnecting train");
 

	
 
reverse_train_direction:
 
	v->load_unload_time_rem = 0;
 
	v->cur_speed = 0;
 
	v->subspeed = 0;
 
	ReverseTrainDirection(v);
 
}
 

	
 
/** Collect trackbits of all crashed train vehicles on a tile
 
 * @param v Vehicle passed from Find/HasVehicleOnPos()
 
 * @param data trackdirbits for the result
 
 * @return NULL to iterate over all vehicles on the tile.
 
 */
 
static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
 
{
 
@@ -4181,49 +4185,49 @@ static bool TrainCanLeaveTile(const Trai
 
	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
		DiagDirection dir = GetTunnelBridgeDirection(tile);
 
		if (DiagDirToDir(dir) == v->direction) return false;
 
	}
 

	
 
	/* entering a depot? */
 
	if (IsRailDepotTile(tile)) {
 
		DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile));
 
		if (DiagDirToDir(dir) == v->direction) return false;
 
	}
 

	
 
	return true;
 
}
 

	
 

	
 
/**
 
 * Determines whether train is approaching a rail-road crossing
 
 *   (thus making it barred)
 
 * @param v front engine of train
 
 * @return TileIndex of crossing the train is approaching, else INVALID_TILE
 
 * @pre v in non-crashed front engine
 
 */
 
static TileIndex TrainApproachingCrossingTile(const Train *v)
 
{
 
	assert(IsFrontEngine(v));
 
	assert(v->IsFrontEngine());
 
	assert(!(v->vehstatus & VS_CRASHED));
 

	
 
	if (!TrainCanLeaveTile(v)) return INVALID_TILE;
 

	
 
	DiagDirection dir = TrainExitDir(v->direction, v->track);
 
	TileIndex tile = v->tile + TileOffsByDiagDir(dir);
 

	
 
	/* not a crossing || wrong axis || unusable rail (wrong type or owner) */
 
	if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) ||
 
			!CheckCompatibleRail(v, tile)) {
 
		return INVALID_TILE;
 
	}
 

	
 
	return tile;
 
}
 

	
 

	
 
/**
 
 * Checks for line end. Also, bars crossing at next tile if needed
 
 *
 
 * @param v vehicle we are checking
 
 * @return true iff we did NOT have to reverse
 
 */
 
static bool TrainCheckIfLineEnds(Train *v)
 
@@ -4426,49 +4430,49 @@ Money Train::GetRunningCost() const
 
	const Train *v = this;
 

	
 
	do {
 
		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
 

	
 
		byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost);
 
		if (cost_factor == 0) continue;
 

	
 
		/* Halve running cost for multiheaded parts */
 
		if (IsMultiheaded(v)) cost_factor /= 2;
 

	
 
		cost += cost_factor * GetPriceByIndex(rvi->running_cost_class);
 
	} while ((v = GetNextVehicle(v)) != NULL);
 

	
 
	return cost;
 
}
 

	
 

	
 
bool Train::Tick()
 
{
 
	if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo();
 

	
 
	this->tick_counter++;
 

	
 
	if (IsFrontEngine(this)) {
 
	if (this->IsFrontEngine()) {
 
		if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
 

	
 
		this->current_order_time++;
 

	
 
		if (!TrainLocoHandler(this, false)) return false;
 

	
 
		return TrainLocoHandler(this, true);
 
	} else if (IsFreeWagon(this) && (this->vehstatus & VS_CRASHED)) {
 
		/* Delete flooded standalone wagon chain */
 
		if (++this->crash_anim_pos >= 4400) {
 
			delete this;
 
			return false;
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
static void CheckIfTrainNeedsService(Train *v)
 
{
 
	static const uint MAX_ACCEPTABLE_DEPOT_DIST = 16;
 

	
 
	if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
 
	if (v->IsInDepot()) {
 
@@ -4485,49 +4489,49 @@ static void CheckIfTrainNeedsService(Tra
 
			 * schedule? */
 
			v->current_order.MakeDummy();
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		}
 
		return;
 
	}
 

	
 
	const Depot *depot = Depot::GetByTile(tfdd.tile);
 

	
 
	if (v->current_order.IsType(OT_GOTO_DEPOT) &&
 
			v->current_order.GetDestination() != depot->index &&
 
			!Chance16(3, 16)) {
 
		return;
 
	}
 

	
 
	v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
 
	v->dest_tile = tfdd.tile;
 
	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
}
 

	
 
void Train::OnNewDay()
 
{
 
	if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
 

	
 
	if (IsFrontEngine(this)) {
 
	if (this->IsFrontEngine()) {
 
		CheckVehicleBreakdown(this);
 
		AgeVehicle(this);
 

	
 
		CheckIfTrainNeedsService(this);
 

	
 
		CheckOrders(this);
 

	
 
		/* update destination */
 
		if (this->current_order.IsType(OT_GOTO_STATION)) {
 
			TileIndex tile = Station::Get(this->current_order.GetDestination())->train_tile;
 
			if (tile != INVALID_TILE) this->dest_tile = tile;
 
		}
 

	
 
		if (this->running_ticks != 0) {
 
			/* running costs */
 
			CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR  * DAY_TICKS));
 

	
 
			this->profit_this_year -= cost.GetCost();
 
			this->running_ticks = 0;
 

	
 
			SubtractMoneyFromCompanyFract(this->owner, cost);
 

	
 
			InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
 
			InvalidateWindowClasses(WC_TRAINS_LIST);
src/train_gui.cpp
Show inline comments
 
@@ -5,49 +5,49 @@
 
#include "stdafx.h"
 
#include "window_gui.h"
 
#include "gfx_func.h"
 
#include "command_func.h"
 
#include "vehicle_gui.h"
 
#include "train.h"
 
#include "newgrf_engine.h"
 
#include "strings_func.h"
 
#include "vehicle_func.h"
 
#include "engine_base.h"
 
#include "window_func.h"
 
#include "settings_type.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (!success) return;
 

	
 
	/* find a locomotive in the depot. */
 
	const Vehicle *found = NULL;
 
	const Train *t;
 
	FOR_ALL_TRAINS(t) {
 
		if (IsFrontEngine(t) && t->tile == tile &&
 
		if (t->IsFrontEngine() && t->tile == tile &&
 
				t->track == TRACK_BIT_DEPOT) {
 
			if (found != NULL) return; // must be exactly one.
 
			found = t;
 
		}
 
	}
 

	
 
	/* if we found a loco, */
 
	if (found != NULL) {
 
		found = GetLastVehicleInChain(found);
 
		/* put the new wagon at the end of the loco. */
 
		DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, CMD_MOVE_RAIL_VEHICLE);
 
		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	}
 
}
 

	
 
void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (!success) return;
 

	
 
	const Vehicle *v = Vehicle::Get(_new_vehicle_id);
 
	if (tile == _backup_orders_tile) {
 
		_backup_orders_tile = 0;
 
		RestoreVehicleOrders(v);
 
	}
src/tunnelbridge_cmd.cpp
Show inline comments
 
@@ -1353,49 +1353,49 @@ static const byte _road_exit_tunnel_fram
 

	
 
static const byte _tunnel_fractcoord_4[4]    = {0x52, 0x85, 0x98, 0x29};
 
static const byte _tunnel_fractcoord_5[4]    = {0x92, 0x89, 0x58, 0x25};
 
static const byte _tunnel_fractcoord_6[4]    = {0x92, 0x89, 0x56, 0x45};
 
static const byte _tunnel_fractcoord_7[4]    = {0x52, 0x85, 0x96, 0x49};
 

	
 
static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
 
{
 
	int z = GetSlopeZ(x, y) - v->z_pos;
 

	
 
	if (abs(z) > 2) return VETSB_CANNOT_ENTER;
 
	const DiagDirection dir = GetTunnelBridgeDirection(tile);
 

	
 
	if (IsTunnel(tile)) {
 
		byte fc;
 
		DiagDirection vdir;
 

	
 
		if (v->type == VEH_TRAIN) {
 
			Train *t = Train::From(v);
 
			fc = (x & 0xF) + (y << 4);
 

	
 
			vdir = DirToDiagDir(t->direction);
 

	
 
			if (t->track != TRACK_BIT_WORMHOLE && dir == vdir) {
 
				if (IsFrontEngine(t) && fc == _tunnel_fractcoord_1[dir]) {
 
				if (t->IsFrontEngine() && fc == _tunnel_fractcoord_1[dir]) {
 
					if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
 
						SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
 
					}
 
					return VETSB_CONTINUE;
 
				}
 
				if (fc == _tunnel_fractcoord_2[dir]) {
 
					t->tile = tile;
 
					t->track = TRACK_BIT_WORMHOLE;
 
					t->vehstatus |= VS_HIDDEN;
 
					return VETSB_ENTERED_WORMHOLE;
 
				}
 
			}
 

	
 
			if (dir == ReverseDiagDir(vdir) && fc == _tunnel_fractcoord_3[dir] && z == 0) {
 
				/* We're at the tunnel exit ?? */
 
				t->tile = tile;
 
				t->track = (TrackBits)_exit_tunnel_track[dir];
 
				assert(t->track);
 
				t->vehstatus &= ~VS_HIDDEN;
 
				return VETSB_ENTERED_WORMHOLE;
 
			}
 
		} else if (v->type == VEH_ROAD) {
 
			RoadVehicle *rv = RoadVehicle::From(v);
 
			fc = (x & 0xF) + (y << 4);
src/vehicle.cpp
Show inline comments
 
@@ -497,49 +497,49 @@ void Vehicle::PreDestructor()
 
		Station::Get(this->last_station_visited)->loading_vehicles.remove(this);
 

	
 
		HideFillingPercent(&this->fill_percent_te_id);
 
	}
 

	
 
	if (IsEngineCountable(this)) {
 
		Company::Get(this->owner)->num_engines[this->engine_type]--;
 
		if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
 

	
 
		DeleteGroupHighlightOfVehicle(this);
 
		if (Group::IsValidID(this->group_id)) Group::Get(this->group_id)->num_engines[this->engine_type]--;
 
		if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
 
	}
 

	
 
	if (this->type == VEH_ROAD) ClearSlot(RoadVehicle::From(this));
 
	if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) {
 
		Aircraft *a = Aircraft::From(this);
 
		Station *st = GetTargetAirportIfValid(a);
 
		if (st != NULL) {
 
			const AirportFTA *layout = st->Airport()->layout;
 
			CLRBITS(st->airport_flags, layout[a->previous_pos].block | layout[a->pos].block);
 
		}
 
	}
 

	
 
	if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (IsFrontEngine(this) || IsFreeWagon(this)))) {
 
	if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (Train::From(this)->IsFrontEngine() || IsFreeWagon(this)))) {
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
 
	}
 

	
 
	if (this->IsPrimaryVehicle()) {
 
		DeleteWindowById(WC_VEHICLE_VIEW, this->index);
 
		DeleteWindowById(WC_VEHICLE_ORDERS, this->index);
 
		DeleteWindowById(WC_VEHICLE_REFIT, this->index);
 
		DeleteWindowById(WC_VEHICLE_DETAILS, this->index);
 
		DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index);
 
		InvalidateWindow(WC_COMPANY, this->owner);
 
	}
 
	InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0);
 

	
 
	this->cargo.Truncate(0);
 
	DeleteVehicleOrders(this);
 
	DeleteDepotHighlightOfVehicle(this);
 

	
 
	extern void StopGlobalFollowVehicle(const Vehicle *v);
 
	StopGlobalFollowVehicle(this);
 

	
 
	ReleaseDisastersTargetingVehicle(this->index);
 
}
 

	
 
Vehicle::~Vehicle()
 
@@ -938,60 +938,62 @@ uint8 CalcPercentVehicleFilled(const Veh
 
			cars++;
 
		}
 
	}
 

	
 
	if (colour != NULL) {
 
		if (unloading == 0 && loading) {
 
			*colour = STR_PERCENT_UP;
 
		} else if (cars == unloading || !loading) {
 
			*colour = STR_PERCENT_DOWN;
 
		} else {
 
			*colour = STR_PERCENT_UP_DOWN;
 
		}
 
	}
 

	
 
	/* Train without capacity */
 
	if (max == 0) return 100;
 

	
 
	/* Return the percentage */
 
	return (count * 100) / max;
 
}
 

	
 
void VehicleEnterDepot(Vehicle *v)
 
{
 
	switch (v->type) {
 
		case VEH_TRAIN:
 
		case VEH_TRAIN: {
 
			Train *t = Train::From(v);
 
			InvalidateWindowClasses(WC_TRAINS_LIST);
 
			/* Clear path reservation */
 
			SetDepotWaypointReservation(v->tile, false);
 
			if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
 
			SetDepotWaypointReservation(t->tile, false);
 
			if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile);
 

	
 
			if (!IsFrontEngine(v)) v = v->First();
 
			UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
 
			v->load_unload_time_rem = 0;
 
			ClrBit(Train::From(v)->flags, VRF_TOGGLE_REVERSE);
 
			TrainConsistChanged(Train::From(v), true);
 
			if (!t->IsFrontEngine()) t = t->First();
 
			UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner);
 
			t->load_unload_time_rem = 0;
 
			ClrBit(t->flags, VRF_TOGGLE_REVERSE);
 
			TrainConsistChanged(t, true);
 
			break;
 
		}
 

	
 
		case VEH_ROAD:
 
			InvalidateWindowClasses(WC_ROADVEH_LIST);
 
			if (!IsRoadVehFront(v)) v = v->First();
 
			break;
 

	
 
		case VEH_SHIP:
 
			InvalidateWindowClasses(WC_SHIPS_LIST);
 
			Ship::From(v)->state = TRACK_BIT_DEPOT;
 
			RecalcShipStuff(v);
 
			break;
 

	
 
		case VEH_AIRCRAFT:
 
			InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 
			HandleAircraftEnterHangar(Aircraft::From(v));
 
			break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	if (v->type != VEH_TRAIN) {
 
		/* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
 
		 * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
	}
src/vehicle_cmd.cpp
Show inline comments
 
@@ -329,85 +329,85 @@ static void CloneVehicleName(const Vehic
 
 * @param p2 1 = shared orders, else copied orders
 
 */
 
CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	CommandCost total_cost(EXPENSES_NEW_VEHICLES);
 
	uint32 build_argument = 2;
 

	
 
	Vehicle *v = Vehicle::GetIfValid(p1);
 
	if (v == NULL) return CMD_ERROR;
 
	Vehicle *v_front = v;
 
	Vehicle *w = NULL;
 
	Vehicle *w_front = NULL;
 
	Vehicle *w_rear = NULL;
 

	
 
	/*
 
	 * v_front is the front engine in the original vehicle
 
	 * v is the car/vehicle of the original vehicle, that is currently being copied
 
	 * w_front is the front engine of the cloned vehicle
 
	 * w is the car/vehicle currently being cloned
 
	 * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains
 
	 */
 

	
 
	if (!CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if (v->type == VEH_TRAIN && (!IsFrontEngine(v) || Train::From(v)->crash_anim_pos >= 4400)) return CMD_ERROR;
 
	if (v->type == VEH_TRAIN && (!Train::From(v)->IsFrontEngine() || Train::From(v)->crash_anim_pos >= 4400)) return CMD_ERROR;
 

	
 
	/* check that we can allocate enough vehicles */
 
	if (!(flags & DC_EXEC)) {
 
		int veh_counter = 0;
 
		do {
 
			veh_counter++;
 
		} while ((v = v->Next()) != NULL);
 

	
 
		if (!Vehicle::CanAllocateItem(veh_counter)) {
 
			return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
		}
 
	}
 

	
 
	v = v_front;
 

	
 
	do {
 
		if (v->type == VEH_TRAIN && IsRearDualheaded(v)) {
 
			/* we build the rear ends of multiheaded trains with the front ones */
 
			continue;
 
		}
 

	
 
		CommandCost cost = DoCommand(tile, v->engine_type, build_argument, flags, GetCmdBuildVeh(v));
 
		build_argument = 3; // ensure that we only assign a number to the first engine
 

	
 
		if (CmdFailed(cost)) return cost;
 

	
 
		total_cost.AddCost(cost);
 

	
 
		if (flags & DC_EXEC) {
 
			w = Vehicle::Get(_new_vehicle_id);
 

	
 
			if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) {
 
				SetBit(Train::From(w)->flags, VRF_REVERSE_DIRECTION);
 
			}
 

	
 
			if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
 
			if (v->type == VEH_TRAIN && !Train::From(v)->IsFrontEngine()) {
 
				/* this s a train car
 
				 * add this unit to the end of the train */
 
				CommandCost result = DoCommand(0, (w_rear->index << 16) | w->index, 1, flags, CMD_MOVE_RAIL_VEHICLE);
 
				if (CmdFailed(result)) {
 
					/* The train can't be joined to make the same consist as the original.
 
					 * Sell what we already made (clean up) and return an error.           */
 
					DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
 
					DoCommand(w_front->tile, w->index,       1, flags, GetCmdSellVeh(w));
 
					return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE
 
				}
 
			} else {
 
				/* this is a front engine or not a train. */
 
				w_front = w;
 
				w->service_interval = v->service_interval;
 
			}
 
			w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop
 
		}
 
	} while (v->type == VEH_TRAIN && (v = GetNextVehicle(Train::From(v))) != NULL);
 

	
 
	if ((flags & DC_EXEC) && v_front->type == VEH_TRAIN) {
 
		/* for trains this needs to be the front engine due to the callback function */
 
		_new_vehicle_id = w_front->index;
 
	}
 

	
src/water_cmd.cpp
Show inline comments
 
@@ -777,60 +777,62 @@ static void FloodVehicle(Vehicle *v)
 

	
 
		if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_AIRCRAFT) {
 
			if (v->type == VEH_AIRCRAFT) {
 
				/* Crashing aircraft are always at z_pos == 1, never on z_pos == 0,
 
				 * because that's always the shadow. Except for the heliport, because
 
				 * that station has a big z_offset for the aircraft. */
 
				if (!IsTileType(v->tile, MP_STATION) || !IsAirport(v->tile) || GetTileMaxZ(v->tile) != 0) return;
 
				const Station *st = Station::GetByTile(v->tile);
 
				const AirportFTAClass *airport = st->Airport();
 

	
 
				if (v->z_pos != airport->delta_z + 1) return;
 
			}
 

	
 
			if (v->type != VEH_AIRCRAFT) v = v->First();
 

	
 
			/* crash all wagons, and count passengers */
 
			for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
				if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
 
				u->vehstatus |= VS_CRASHED;
 
				MarkSingleVehicleDirty(u);
 
			}
 

	
 
			switch (v->type) {
 
				default: NOT_REACHED();
 
				case VEH_TRAIN:
 
					if (IsFrontEngine(v)) {
 
				case VEH_TRAIN: {
 
					Train *t = Train::From(v);
 
					if (t->IsFrontEngine()) {
 
						pass += 4; // driver
 
						/* FreeTrainTrackReservation() calls GetVehicleTrackdir() that doesn't like crashed vehicles.
 
						 * In this case, v->direction matches v->u.rail.track, so we can do this (it wasn't crashed before) */
 
						v->vehstatus &= ~VS_CRASHED;
 
						FreeTrainTrackReservation(Train::From(v));
 
						v->vehstatus |= VS_CRASHED;
 
						t->vehstatus &= ~VS_CRASHED;
 
						FreeTrainTrackReservation(t);
 
						t->vehstatus |= VS_CRASHED;
 
					}
 
					Train::From(v)->crash_anim_pos = 4000; // max 4440, disappear pretty fast
 
					t->crash_anim_pos = 4000; // max 4440, disappear pretty fast
 
					InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
					break;
 
				}
 

	
 
				case VEH_ROAD:
 
					if (IsRoadVehFront(v)) pass += 1; // driver
 
					RoadVehicle::From(v)->crashed_ctr = 2000; // max 2220, disappear pretty fast
 
					InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
					break;
 

	
 
				case VEH_AIRCRAFT:
 
					pass += 2; // driver
 
					Aircraft::From(v)->crashed_counter = 9000; // max 10000, disappear pretty fast
 
					InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 
					break;
 
			}
 
		} else {
 
			return;
 
		}
 

	
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 

	
 
		AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_FLOODED));
 
		SetDParam(0, pass);
 
		AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE,
 
			NS_ACCIDENT,
0 comments (0 inline, 0 general)