Changeset - r11980:193f7a6b6e37
[Not reviewed]
src/ai/api/ai_vehicle.cpp
Show inline comments
 
@@ -20,25 +20,25 @@
 
/* static */ bool AIVehicle::IsValidVehicle(VehicleID vehicle_id)
 
{
 
	const Vehicle *v = ::Vehicle::GetIfValid(vehicle_id);
 
	return v != NULL && v->owner == _current_company && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::IsFreeWagon(v)));
 
}
 

	
 
/* static */ int32 AIVehicle::GetNumWagons(VehicleID vehicle_id)
 
{
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 

	
 
	int num = 1;
 
	if (::Vehicle::Get(vehicle_id)->type == VEH_TRAIN) {
 
		const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
		const Train *v = (Train *)::Vehicle::Get(vehicle_id);
 
		while ((v = GetNextUnit(v)) != NULL) num++;
 
	}
 

	
 
	return num;
 
}
 

	
 
/* static */ int AIVehicle::GetLength(VehicleID vehicle_id)
 
{
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	switch (v->type) {
 
@@ -76,29 +76,29 @@
 

	
 
	/* In case of test-mode, we return VehicleID 0 */
 
	return 0;
 
}
 

	
 
/* static */ bool AIVehicle::_MoveWagonInternal(VehicleID source_vehicle_id, int source_wagon, bool move_attached_wagons, int dest_vehicle_id, int dest_wagon)
 
{
 
	EnforcePrecondition(false, IsValidVehicle(source_vehicle_id) && source_wagon < GetNumWagons(source_vehicle_id));
 
	EnforcePrecondition(false, dest_vehicle_id == -1 || (IsValidVehicle(dest_vehicle_id) && dest_wagon < GetNumWagons(dest_vehicle_id)));
 
	EnforcePrecondition(false, ::Vehicle::Get(source_vehicle_id)->type == VEH_TRAIN);
 
	EnforcePrecondition(false, dest_vehicle_id == -1 || ::Vehicle::Get(dest_vehicle_id)->type == VEH_TRAIN);
 

	
 
	const Vehicle *v = ::Vehicle::Get(source_vehicle_id);
 
	const Train *v = (Train *)::Vehicle::Get(source_vehicle_id);
 
	while (source_wagon-- > 0) v = GetNextUnit(v);
 
	const Vehicle *w = NULL;
 
	const Train *w = NULL;
 
	if (dest_vehicle_id != -1) {
 
		w = ::Vehicle::Get(dest_vehicle_id);
 
		w = (Train *)::Vehicle::Get(dest_vehicle_id);
 
		while (dest_wagon-- > 0) w = GetNextUnit(w);
 
	}
 

	
 
	return AIObject::DoCommand(0, v->index | ((w == NULL ? INVALID_VEHICLE : w->index) << 16), move_attached_wagons ? 1 : 0, CMD_MOVE_RAIL_VEHICLE);
 
}
 

	
 
/* static */ bool AIVehicle::MoveWagon(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon)
 
{
 
	return _MoveWagonInternal(source_vehicle_id, source_wagon, false, dest_vehicle_id, dest_wagon);
 
}
 

	
 
/* static */ bool AIVehicle::MoveWagonChain(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon)
 
@@ -127,25 +127,25 @@
 
{
 
	EnforcePrecondition(false, IsValidVehicle(vehicle_id));
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	return AIObject::DoCommand(0, vehicle_id, v->type == VEH_TRAIN ? 1 : 0, GetCmdSellVeh(v));
 
}
 

	
 
/* static */ bool AIVehicle::_SellWagonInternal(VehicleID vehicle_id, int wagon, bool sell_attached_wagons)
 
{
 
	EnforcePrecondition(false, IsValidVehicle(vehicle_id) && wagon < GetNumWagons(vehicle_id));
 
	EnforcePrecondition(false, ::Vehicle::Get(vehicle_id)->type == VEH_TRAIN);
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	const Train *v = (Train *)::Vehicle::Get(vehicle_id);
 
	while (wagon-- > 0) v = GetNextUnit(v);
 

	
 
	return AIObject::DoCommand(0, v->index, sell_attached_wagons ? 1 : 0, CMD_SELL_RAIL_WAGON);
 
}
 

	
 
/* static */ bool AIVehicle::SellWagon(VehicleID vehicle_id, int wagon)
 
{
 
	return _SellWagonInternal(vehicle_id, wagon, false);
 
}
 

	
 
/* static */ bool AIVehicle::SellWagonChain(VehicleID vehicle_id, int wagon)
 
{
 
@@ -234,25 +234,25 @@
 
	if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
 

	
 
	return ::Vehicle::Get(vehicle_id)->engine_type;
 
}
 

	
 
/* static */ EngineID AIVehicle::GetWagonEngineType(VehicleID vehicle_id, int wagon)
 
{
 
	if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE;
 
	if (wagon >= GetNumWagons(vehicle_id)) return INVALID_ENGINE;
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	if (v->type == VEH_TRAIN) {
 
		while (wagon-- > 0) v = GetNextUnit(v);
 
		while (wagon-- > 0) v = GetNextUnit((Train *)v);
 
	}
 
	return v->engine_type;
 
}
 

	
 
/* static */ int32 AIVehicle::GetUnitNumber(VehicleID vehicle_id)
 
{
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 

	
 
	return ::Vehicle::Get(vehicle_id)->unitnumber;
 
}
 

	
 
/* static */ char *AIVehicle::GetName(VehicleID vehicle_id)
 
@@ -272,25 +272,25 @@
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 

	
 
	return ::Vehicle::Get(vehicle_id)->age;
 
}
 

	
 
/* static */ int32 AIVehicle::GetWagonAge(VehicleID vehicle_id, int wagon)
 
{
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 
	if (wagon >= GetNumWagons(vehicle_id)) return -1;
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	if (v->type == VEH_TRAIN) {
 
		while (wagon-- > 0) v = GetNextUnit(v);
 
		while (wagon-- > 0) v = GetNextUnit((Train *)v);
 
	}
 
	return v->age;
 
}
 

	
 
/* static */ int32 AIVehicle::GetMaxAge(VehicleID vehicle_id)
 
{
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 

	
 
	return ::Vehicle::Get(vehicle_id)->max_age;
 
}
 

	
 
/* static */ int32 AIVehicle::GetAgeLeft(VehicleID vehicle_id)
src/articulated_vehicles.cpp
Show inline comments
 
@@ -199,25 +199,25 @@ bool IsArticulatedVehicleCarryingDiffere
 

	
 
	do {
 
		if (v->cargo_cap > 0 && v->cargo_type != CT_INVALID) {
 
			if (first_cargo == CT_INVALID) first_cargo = v->cargo_type;
 
			if (first_cargo != v->cargo_type) {
 
				if (cargo_type != NULL) *cargo_type = CT_INVALID;
 
				return true;
 
			}
 
		}
 

	
 
		switch (v->type) {
 
			case VEH_TRAIN:
 
				v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
 
				v = (EngineHasArticPart((Train *)v) ? GetNextArticPart((Train *)v) : NULL);
 
				break;
 

	
 
			case VEH_ROAD:
 
				v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
 
				break;
 

	
 
			default:
 
				v = NULL;
 
				break;
 
		}
 
	} while (v != NULL);
 

	
 
@@ -247,25 +247,25 @@ void CheckConsistencyOfArticulatedVehicl
 
	memset(real_default_capacity, 0, sizeof(real_default_capacity));
 

	
 
	do {
 
		uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, v->type, true);
 
		real_refit_union |= refit_mask;
 
		if (refit_mask != 0) real_refit_intersection &= refit_mask;
 

	
 
		assert(v->cargo_type < NUM_CARGO);
 
		real_default_capacity[v->cargo_type] += v->cargo_cap;
 

	
 
		switch (v->type) {
 
			case VEH_TRAIN:
 
				v = (EngineHasArticPart(v) ? GetNextArticPart(v) : NULL);
 
				v = (EngineHasArticPart((Train *)v) ? GetNextArticPart((Train *)v) : NULL);
 
				break;
 

	
 
			case VEH_ROAD:
 
				v = (RoadVehHasArticPart(v) ? v->Next() : NULL);
 
				break;
 

	
 
			default:
 
				v = NULL;
 
				break;
 
		}
 
	} while (v != NULL);
 

	
 
@@ -298,43 +298,45 @@ void AddArticulatedParts(Vehicle *first,
 
		/* In the (very rare) case the GRF reported wrong number of articulated parts
 
		 * and we run out of available vehicles, bail out. */
 
		if (!Vehicle::CanAllocateItem()) return;
 

	
 
		EngineID engine_type = GetNewEngineID(GetEngineGRF(v->engine_type), type, GB(callback, 0, 7));
 
		bool flip_image = HasBit(callback, 7);
 

	
 
		Vehicle *previous = u;
 
		const Engine *e_artic = Engine::Get(engine_type);
 
		switch (type) {
 
			default: NOT_REACHED();
 

	
 
			case VEH_TRAIN:
 
				u = new Train();
 
				u->subtype = 0;
 
				previous->SetNext(u);
 
				u->u.rail.track = v->u.rail.track;
 
				u->u.rail.railtype = v->u.rail.railtype;
 
				u->u.rail.first_engine = v->engine_type;
 
			case VEH_TRAIN: {
 
				Train *front = (Train *)v;
 
				Train *t = new Train();
 
				t->subtype = 0;
 
				previous->SetNext(t);
 
				t->u.rail.track = front->u.rail.track;
 
				t->u.rail.railtype = front->u.rail.railtype;
 
				t->u.rail.first_engine = front->engine_type;
 

	
 
				u->spritenum = e_artic->u.rail.image_index;
 
				t->spritenum = e_artic->u.rail.image_index;
 
				if (e_artic->CanCarryCargo()) {
 
					u->cargo_type = e_artic->GetDefaultCargoType();
 
					u->cargo_cap = e_artic->u.rail.capacity;  // Callback 36 is called when the consist is finished
 
					t->cargo_type = e_artic->GetDefaultCargoType();
 
					t->cargo_cap = e_artic->u.rail.capacity;  // Callback 36 is called when the consist is finished
 
				} else {
 
					u->cargo_type = v->cargo_type; // Needed for livery selection
 
					u->cargo_cap = 0;
 
					t->cargo_type = front->cargo_type; // Needed for livery selection
 
					t->cargo_cap = 0;
 
				}
 

	
 
				SetArticulatedPart(u);
 
				break;
 
				SetArticulatedPart(t);
 
				u = t;
 
			} break;
 

	
 
			case VEH_ROAD: {
 
				RoadVehicle *front = (RoadVehicle *)v;
 
				RoadVehicle *rv = new RoadVehicle();
 
				rv->subtype = 0;
 
				previous->SetNext(u);
 
				rv->first_engine = front->engine_type;
 
				rv->cached_veh_length = 8; // Callback is called when the consist is finished
 
				rv->state = RVSB_IN_DEPOT;
 

	
 
				rv->roadtype = front->roadtype;
 
				rv->compatible_roadtypes = front->compatible_roadtypes;
src/autoreplace_cmd.cpp
Show inline comments
 
@@ -83,49 +83,49 @@ bool CheckAutoreplaceValidity(EngineID f
 
}
 

	
 
/** Transfer cargo from a single (articulated )old vehicle to the new vehicle chain
 
 * @param old_veh Old vehicle that will be sold
 
 * @param new_head Head of the completely constructed new vehicle chain
 
 * @param part_of_chain The vehicle is part of a train
 
 */
 
static void TransferCargo(Vehicle *old_veh, Vehicle *new_head, bool part_of_chain)
 
{
 
	assert(!part_of_chain || new_head->IsPrimaryVehicle());
 
	/* Loop through source parts */
 
	for (Vehicle *src = old_veh; src != NULL; src = src->Next()) {
 
		if (!part_of_chain && src->type == VEH_TRAIN && src != old_veh && src != old_veh->u.rail.other_multiheaded_part && !IsArticulatedPart(src)) {
 
		if (!part_of_chain && src->type == VEH_TRAIN && src != old_veh && src != ((Train *)old_veh)->u.rail.other_multiheaded_part && !IsArticulatedPart(src)) {
 
			/* Skip vehicles, which do not belong to old_veh */
 
			src = GetLastEnginePart(src);
 
			src = GetLastEnginePart((Train *)src);
 
			continue;
 
		}
 
		if (src->cargo_type >= NUM_CARGO || src->cargo.Count() == 0) continue;
 

	
 
		/* Find free space in the new chain */
 
		for (Vehicle *dest = new_head; dest != NULL && src->cargo.Count() > 0; dest = dest->Next()) {
 
			if (!part_of_chain && dest->type == VEH_TRAIN && dest != new_head && dest != new_head->u.rail.other_multiheaded_part && !IsArticulatedPart(dest)) {
 
			if (!part_of_chain && dest->type == VEH_TRAIN && dest != new_head && dest != ((Train *)new_head)->u.rail.other_multiheaded_part && !IsArticulatedPart(dest)) {
 
				/* Skip vehicles, which do not belong to new_head */
 
				dest = GetLastEnginePart(dest);
 
				dest = GetLastEnginePart((Train *)dest);
 
				continue;
 
			}
 
			if (dest->cargo_type != src->cargo_type) continue;
 

	
 
			uint amount = min(src->cargo.Count(), dest->cargo_cap - dest->cargo.Count());
 
			if (amount <= 0) continue;
 

	
 
			src->cargo.MoveTo(&dest->cargo, amount);
 
		}
 
	}
 

	
 
	/* Update train weight etc., the old vehicle will be sold anyway */
 
	if (part_of_chain && new_head->type == VEH_TRAIN) TrainConsistChanged(new_head, true);
 
	if (part_of_chain && new_head->type == VEH_TRAIN) TrainConsistChanged((Train *)new_head, true);
 
}
 

	
 
/**
 
 * Tests whether refit orders that applied to v will also apply to the new vehicle type
 
 * @param v The vehicle to be replaced
 
 * @param engine_type The type we want to replace with
 
 * @return true iff all refit orders stay valid
 
 */
 
static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_type)
 
{
 
	const Order *o;
 
	const Vehicle *u;
 
@@ -260,25 +260,25 @@ static CommandCost BuildReplacementVehic
 
	if (cost.Failed()) return cost;
 

	
 
	Vehicle *new_veh = Vehicle::Get(_new_vehicle_id);
 
	*new_vehicle = new_veh;
 

	
 
	/* Refit the vehicle if needed */
 
	if (refit_cargo != CT_NO_REFIT) {
 
		cost.AddCost(DoCommand(0, new_veh->index, refit_cargo, DC_EXEC, GetCmdRefitVeh(new_veh)));
 
		assert(cost.Succeeded()); // This should be ensured by GetNewCargoTypeForReplace()
 
	}
 

	
 
	/* Try to reverse the vehicle, but do not care if it fails as the new type might not be reversible */
 
	if (new_veh->type == VEH_TRAIN && HasBit(old_veh->u.rail.flags, VRF_REVERSE_DIRECTION)) {
 
	if (new_veh->type == VEH_TRAIN && HasBit(((Train *)old_veh)->u.rail.flags, VRF_REVERSE_DIRECTION)) {
 
		DoCommand(0, new_veh->index, true, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
 
	}
 

	
 
	return cost;
 
}
 

	
 
/** Issue a start/stop command
 
 * @param v a vehicle
 
 * @param evaluate_callback shall the start/stop callback be evaluated?
 
 * @return success or error
 
 */
 
static inline CommandCost StartStopVehicle(const Vehicle *v, bool evaluate_callback)
 
@@ -397,62 +397,62 @@ static CommandCost ReplaceFreeUnit(Vehic
 
static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon_removal, bool *nothing_to_do)
 
{
 
	Vehicle *old_head = *chain;
 
	assert(old_head->IsPrimaryVehicle());
 

	
 
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
 

	
 
	if (old_head->type == VEH_TRAIN) {
 
		/* Store the length of the old vehicle chain, rounded up to whole tiles */
 
		uint16 old_total_length = (old_head->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE;
 

	
 
		int num_units = 0; ///< Number of units in the chain
 
		for (Vehicle *w = old_head; w != NULL; w = GetNextUnit(w)) num_units++;
 
		for (Train *w = (Train *)old_head; w != NULL; w = GetNextUnit(w)) num_units++;
 

	
 
		Vehicle **old_vehs = CallocT<Vehicle *>(num_units); ///< Will store vehicles of the old chain in their order
 
		Vehicle **new_vehs = CallocT<Vehicle *>(num_units); ///< New vehicles corresponding to old_vehs or NULL if no replacement
 
		Money *new_costs = MallocT<Money>(num_units);       ///< Costs for buying and refitting the new vehicles
 
		Train **old_vehs = CallocT<Train *>(num_units); ///< Will store vehicles of the old chain in their order
 
		Train **new_vehs = CallocT<Train *>(num_units); ///< New vehicles corresponding to old_vehs or NULL if no replacement
 
		Money *new_costs = MallocT<Money>(num_units);   ///< Costs for buying and refitting the new vehicles
 

	
 
		/* Collect vehicles and build replacements
 
		 * Note: The replacement vehicles can only successfully build as long as the old vehicles are still in their chain */
 
		int i;
 
		Vehicle *w;
 
		for (w = old_head, i = 0; w != NULL; w = GetNextUnit(w), i++) {
 
		Train *w;
 
		for (w = (Train *)old_head, i = 0; w != NULL; w = GetNextUnit(w), i++) {
 
			assert(i < num_units);
 
			old_vehs[i] = w;
 

	
 
			CommandCost ret = BuildReplacementVehicle(old_vehs[i], &new_vehs[i], true);
 
			CommandCost ret = BuildReplacementVehicle(old_vehs[i], (Vehicle**)&new_vehs[i], true);
 
			cost.AddCost(ret);
 
			if (cost.Failed()) break;
 

	
 
			new_costs[i] = ret.GetCost();
 
			if (new_vehs[i] != NULL) *nothing_to_do = false;
 
		}
 
		Vehicle *new_head = (new_vehs[0] != NULL ? new_vehs[0] : old_vehs[0]);
 
		Train *new_head = (new_vehs[0] != NULL ? new_vehs[0] : old_vehs[0]);
 

	
 
		/* Note: When autoreplace has already failed here, old_vehs[] is not completely initialized. But it is also not needed. */
 
		if (cost.Succeeded()) {
 
			/* Separate the head, so we can start constructing the new chain */
 
			Vehicle *second = GetNextUnit(old_head);
 
			Train *second = GetNextUnit((Train *)old_head);
 
			if (second != NULL) cost.AddCost(MoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true));
 

	
 
			assert(GetNextUnit(new_head) == NULL);
 

	
 
			/* Append engines to the new chain
 
			 * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time.
 
			 * OTOH the vehicle attach callback is more expensive this way :s */
 
			Vehicle *last_engine = NULL; ///< Shall store the last engine unit after this step
 
			Train *last_engine = NULL; ///< Shall store the last engine unit after this step
 
			if (cost.Succeeded()) {
 
				for (int i = num_units - 1; i > 0; i--) {
 
					Vehicle *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]);
 
					Train *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]);
 

	
 
					if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) continue;
 

	
 
					if (last_engine == NULL) last_engine = append;
 
					cost.AddCost(MoveVehicle(append, new_head, DC_EXEC, false));
 
					if (cost.Failed()) break;
 
				}
 
				if (last_engine == NULL) last_engine = new_head;
 
			}
 

	
 
			/* When wagon removal is enabled and the new engines without any wagons are already longer than the old, we have to fail */
 
			if (cost.Succeeded() && wagon_removal && new_head->u.rail.cached_total_length > old_total_length) cost = CommandCost(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT);
 
@@ -529,28 +529,28 @@ static CommandCost ReplaceChain(Vehicle 
 
					if ((flags & DC_EXEC) != 0) {
 
						old_vehs[i] = NULL;
 
						if (i == 0) old_head = NULL;
 
					}
 
				}
 
			}
 

	
 
			/* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles.
 
			 * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time.
 
			 * Note: The vehicle attach callback is disabled here :) */
 
			if ((flags & DC_EXEC) == 0) {
 
				/* Separate the head, so we can reattach the old vehicles */
 
				Vehicle *second = GetNextUnit(old_head);
 
				Train *second = GetNextUnit((Train *)old_head);
 
				if (second != NULL) MoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true);
 

	
 
				assert(GetNextUnit(old_head) == NULL);
 
				assert(GetNextUnit((Train *)old_head) == NULL);
 

	
 
				for (int i = num_units - 1; i > 0; i--) {
 
					CommandCost ret = MoveVehicle(old_vehs[i], old_head, DC_EXEC | DC_AUTOREPLACE, false);
 
					assert(ret.Succeeded());
 
				}
 
			}
 
		}
 

	
 
		/* Finally undo buying of new vehicles */
 
		if ((flags & DC_EXEC) == 0) {
 
			for (int i = num_units - 1; i >= 0; i--) {
 
				if (new_vehs[i] != NULL) {
 
@@ -623,25 +623,25 @@ CommandCost CmdAutoreplaceVehicle(TileIn
 
	} 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(w) : NULL);
 
		w = (!free_wagon && w->type == VEH_TRAIN ? GetNextUnit((Train *)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());
 

	
 
		/* We have to construct the new vehicle chain to test whether it is valid.
src/elrail.cpp
Show inline comments
 
@@ -546,39 +546,43 @@ bool SettingsDisableElrail(int32 p1)
 
		RailVehicleInfo *rv_info = &e->u.rail;
 
		/* 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_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN && v->u.rail.railtype == RAILTYPE_ELECTRIC) {
 
			if (v->type != VEH_TRAIN) continue;
 

	
 
			Train *t = (Train *)v;
 
			if (t->u.rail.railtype == RAILTYPE_ELECTRIC) {
 
				/* this railroad vehicle is now compatible only with elrail,
 
				 *  so add there also normal rail compatibility */
 
				v->u.rail.compatible_railtypes |= RAILTYPES_RAIL;
 
				v->u.rail.railtype = RAILTYPE_RAIL;
 
				SetBit(v->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL);
 
				t->u.rail.compatible_railtypes |= RAILTYPES_RAIL;
 
				t->u.rail.railtype = RAILTYPE_RAIL;
 
				SetBit(t->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL);
 
			}
 
		}
 
	}
 

	
 
	/* Fix the total power and acceleration for trains */
 
	FOR_ALL_VEHICLES(v) {
 
		/* power and acceleration is cached only for front engines */
 
		if (v->type == VEH_TRAIN && IsFrontEngine(v)) {
 
			TrainPowerChanged(v);
 
			UpdateTrainAcceleration(v);
 
			Train *t = (Train *)v;
 
			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/newgrf_engine.cpp
Show inline comments
 
@@ -659,33 +659,34 @@ static uint32 VehicleGetVariable(const R
 
				uint count = 0;
 
				for (; v != NULL; v = v->Next()) {
 
					if (Engine::Get(v->engine_type)->internal_id == parameter) count++;
 
				}
 
				return count;
 
			}
 

	
 
		case 0xFE:
 
		case 0xFF: {
 
			uint16 modflags = 0;
 

	
 
			if (v->type == VEH_TRAIN) {
 
				const Vehicle *u = IsTrainWagon(v) && HasBit(v->vehicle_flags, VRF_POWEREDWAGON) ? v->First() : v;
 
				const Train *t = (const Train *)v;
 
				const Train *u = IsTrainWagon(v) && HasBit(v->vehicle_flags, VRF_POWEREDWAGON) ? t->First() : t;
 
				RailType railtype = GetRailType(v->tile);
 
				bool powered = IsTrainEngine(v) || (IsTrainWagon(v) && HasBit(v->vehicle_flags, VRF_POWEREDWAGON));
 
				bool has_power = powered && HasPowerOnRail(u->u.rail.railtype, railtype);
 
				bool is_electric = powered && u->u.rail.railtype == RAILTYPE_ELECTRIC;
 

	
 
				if (has_power) SetBit(modflags, 5);
 
				if (is_electric && !has_power) SetBit(modflags, 6);
 
				if (HasBit(v->u.rail.flags, VRF_TOGGLE_REVERSE)) SetBit(modflags, 8);
 
				if (HasBit(t->u.rail.flags, VRF_TOGGLE_REVERSE)) SetBit(modflags, 8);
 
			}
 
			if (HasBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE)) SetBit(modflags, 10);
 

	
 
			return variable == 0xFE ? modflags : GB(modflags, 8, 8);
 
		}
 
	}
 

	
 
	/* General vehicle properties */
 
	switch (variable - 0x80) {
 
		case 0x00: return v->type;
 
		case 0x01: return MapOldSubType(v);
 
		case 0x04: return v->index;
 
@@ -726,25 +727,25 @@ static uint32 VehicleGetVariable(const R
 
		case 0x3E: return v->cargo.Source();
 
		case 0x3F: return v->cargo.DaysInTransit();
 
		case 0x40: return v->age;
 
		case 0x41: return GB(v->age, 8, 8);
 
		case 0x42: return v->max_age;
 
		case 0x43: return GB(v->max_age, 8, 8);
 
		case 0x44: return Clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR;
 
		case 0x45: return v->unitnumber;
 
		case 0x46: return Engine::Get(v->engine_type)->internal_id;
 
		case 0x47: return GB(Engine::Get(v->engine_type)->internal_id, 8, 8);
 
		case 0x48:
 
			if (v->type != VEH_TRAIN || v->spritenum != 0xFD) return v->spritenum;
 
			return HasBit(v->u.rail.flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD;
 
			return HasBit(((Train *)v)->u.rail.flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD;
 

	
 
		case 0x49: return v->day_counter;
 
		case 0x4A: return v->breakdowns_since_last_service;
 
		case 0x4B: return v->breakdown_ctr;
 
		case 0x4C: return v->breakdown_delay;
 
		case 0x4D: return v->breakdown_chance;
 
		case 0x4E: return v->reliability;
 
		case 0x4F: return GB(v->reliability, 8, 8);
 
		case 0x50: return v->reliability_spd_dec;
 
		case 0x51: return GB(v->reliability_spd_dec, 8, 8);
 
		case 0x52: return ClampToI32(v->GetDisplayProfitThisYear());
 
		case 0x53: return GB(ClampToI32(v->GetDisplayProfitThisYear()),  8, 24);
 
@@ -757,38 +758,39 @@ static uint32 VehicleGetVariable(const R
 
		case 0x5A: return v->Next() == NULL ? INVALID_VEHICLE : v->Next()->index;
 
		case 0x5C: return ClampToI32(v->value);
 
		case 0x5D: return GB(ClampToI32(v->value),  8, 24);
 
		case 0x5E: return GB(ClampToI32(v->value), 16, 16);
 
		case 0x5F: return GB(ClampToI32(v->value), 24,  8);
 
		case 0x72: return v->cargo_subtype;
 
		case 0x7A: return v->random_bits;
 
		case 0x7B: return v->waiting_triggers;
 
	}
 

	
 
	/* Vehicle specific properties */
 
	switch (v->type) {
 
		case VEH_TRAIN:
 
		case VEH_TRAIN: {
 
			Train *t = (Train *)v;
 
			switch (variable - 0x80) {
 
				case 0x62: return v->u.rail.track;
 
				case 0x66: return v->u.rail.railtype;
 
				case 0x73: return v->u.rail.cached_veh_length;
 
				case 0x74: return v->u.rail.cached_power;
 
				case 0x75: return GB(v->u.rail.cached_power,  8, 24);
 
				case 0x76: return GB(v->u.rail.cached_power, 16, 16);
 
				case 0x77: return GB(v->u.rail.cached_power, 24,  8);
 
				case 0x7C: return v->First()->index;
 
				case 0x7D: return GB(v->First()->index, 8, 8);
 
				case 0x62: return t->u.rail.track;
 
				case 0x66: return t->u.rail.railtype;
 
				case 0x73: return t->u.rail.cached_veh_length;
 
				case 0x74: return t->u.rail.cached_power;
 
				case 0x75: return GB(t->u.rail.cached_power,  8, 24);
 
				case 0x76: return GB(t->u.rail.cached_power, 16, 16);
 
				case 0x77: return GB(t->u.rail.cached_power, 24,  8);
 
				case 0x7C: return t->First()->index;
 
				case 0x7D: return GB(t->First()->index, 8, 8);
 
				case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
 
			}
 
			break;
 
		} break;
 

	
 
		case VEH_ROAD: {
 
			RoadVehicle *rv = (RoadVehicle *)v;
 
			switch (variable - 0x80) {
 
				case 0x62: return rv->state;
 
				case 0x64: return rv->blocked_ctr;
 
				case 0x65: return GB(rv->blocked_ctr, 8, 8);
 
				case 0x66: return rv->overtaking;
 
				case 0x67: return rv->overtaking_ctr;
 
				case 0x68: return rv->crashed_ctr;
 
				case 0x69: return GB(rv->crashed_ctr, 8, 8);
 
			}
src/npf.cpp
Show inline comments
 
@@ -7,24 +7,25 @@
 
#include "debug.h"
 
#include "landscape.h"
 
#include "depot_base.h"
 
#include "depot_map.h"
 
#include "network/network.h"
 
#include "tunnelbridge_map.h"
 
#include "functions.h"
 
#include "vehicle_base.h"
 
#include "tunnelbridge.h"
 
#include "pbs.h"
 
#include "settings_type.h"
 
#include "pathfind.h"
 
#include "train.h"
 

	
 
static AyStar _npf_aystar;
 

	
 
/* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH,
 
 * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071
 
 */
 
#define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH)
 
static const uint _trackdir_length[TRACKDIR_END] = {
 
	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH,
 
	0, 0,
 
	NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH
 
};
 
@@ -415,25 +416,25 @@ static int32 NPFRailPathCost(AyStar *as,
 
/* Will find any depot */
 
static int32 NPFFindDepot(AyStar *as, OpenListNode *current)
 
{
 
	/* It's not worth caching the result with NPF_FLAG_IS_TARGET here as below,
 
	 * since checking the cache not that much faster than the actual check */
 
	return IsDepotTypeTile(current->path.node.tile, (TransportType)as->user_data[NPF_TYPE]) ?
 
		AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
 
}
 

	
 
/** Find any safe and free tile. */
 
static int32 NPFFindSafeTile(AyStar *as, OpenListNode *current)
 
{
 
	const Vehicle *v = ((NPFFindStationOrTileData*)as->user_target)->v;
 
	const Train *v = (Train *)((NPFFindStationOrTileData*)as->user_target)->v;
 

	
 
	return
 
		IsSafeWaitingPosition(v, current->path.node.tile, current->path.node.direction, true, _settings_game.pf.forbid_90_deg) &&
 
		IsWaitingPositionFree(v, current->path.node.tile, current->path.node.direction, _settings_game.pf.forbid_90_deg) ?
 
			AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
 
}
 

	
 
/* Will find a station identified using the NPFFindStationOrTileData */
 
static int32 NPFFindStationOrTile(AyStar *as, OpenListNode *current)
 
{
 
	NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
 
	AyStarNode *node = &current->path.node;
 
@@ -449,25 +450,25 @@ static int32 NPFFindStationOrTile(AyStar
 
	} else {
 
		return AYSTAR_DONE;
 
	}
 
}
 

	
 
/**
 
 * Find the node containing the first signal on the path.
 
 *
 
 * If the first signal is on the very first two tiles of the path,
 
 * the second signal is returnd. If no suitable signal is present, the
 
 * last node of the path is returned.
 
 */
 
static const PathNode *FindSafePosition(PathNode *path, const Vehicle *v)
 
static const PathNode *FindSafePosition(PathNode *path, const Train *v)
 
{
 
	/* If there is no signal, reserve the whole path. */
 
	PathNode *sig = path;
 

	
 
	for(; path->parent != NULL; path = path->parent) {
 
		if (IsSafeWaitingPosition(v, path->node.tile, path->node.direction, true, _settings_game.pf.forbid_90_deg)) {
 
			sig = path;
 
		}
 
	}
 

	
 
	return sig;
 
}
 
@@ -496,25 +497,25 @@ static void ClearPathReservation(const P
 
 */
 
static void NPFSaveTargetData(AyStar *as, OpenListNode *current)
 
{
 
	NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path;
 
	ftd->best_trackdir = (Trackdir)current->path.node.user_data[NPF_TRACKDIR_CHOICE];
 
	ftd->best_path_dist = current->g;
 
	ftd->best_bird_dist = 0;
 
	ftd->node = current->path.node;
 
	ftd->res_okay = false;
 

	
 
	if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && as->user_data[NPF_TYPE] == TRANSPORT_RAIL) {
 
		/* Path reservation is requested. */
 
		const Vehicle  *v = ((NPFFindStationOrTileData*)as->user_target)->v;
 
		const Train *v = (Train *)((NPFFindStationOrTileData*)as->user_target)->v;
 

	
 
		const PathNode *target = FindSafePosition(&current->path, v);
 
		ftd->node = target->node;
 

	
 
		/* If the target is a station skip to platform end. */
 
		if (IsRailwayStationTile(target->node.tile)) {
 
			DiagDirection dir = TrackdirToExitdir(target->node.direction);
 
			uint len = GetStationByTile(target->node.tile)->GetPlatformLength(target->node.tile, dir);
 
			TileIndex end_tile = TILE_ADD(target->node.tile, (len - 1) * TileOffsByDiagDir(dir));
 

	
 
			/* Update only end tile, trackdir of a station stays the same. */
 
			ftd->node.tile = end_tile;
 
@@ -1044,25 +1045,25 @@ NPFFoundTargetData NPFRouteToDepotTrialE
 
		assert(r != AYSTAR_STILL_BUSY);
 

	
 
		/* This depot is closer */
 
		if (result.best_path_dist < best_result.best_path_dist)
 
			best_result = result;
 
	}
 
	if (result.best_bird_dist != 0) {
 
		DEBUG(npf, 1, "Could not find route to any depot from tile 0x%X.", tile);
 
	}
 
	return best_result;
 
}
 

	
 
NPFFoundTargetData NPFRouteToSafeTile(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool override_railtype)
 
NPFFoundTargetData NPFRouteToSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype)
 
{
 
	assert(v->type == VEH_TRAIN);
 

	
 
	NPFFindStationOrTileData fstd;
 
	fstd.v = v;
 
	fstd.reserve_path = true;
 

	
 
	AyStarNode start1;
 
	start1.tile = tile;
 
	/* We set this in case the target is also the start tile, we will just
 
	 * return a not found then */
 
	start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR;
src/npf.h
Show inline comments
 
@@ -106,25 +106,25 @@ NPFFoundTargetData NPFRouteToDepotBreadt
 
 * orginated. All pathfs from the second node will have the given
 
 * reverse_penalty applied (NPF_TILE_LENGTH is the equivalent of one full
 
 * tile).
 
 */
 
NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, bool ignore_start_tile1, TileIndex tile2, Trackdir trackdir2, bool ignore_start_tile2, TransportType type, uint sub_type, Owner owner, RailTypes railtypes, uint reverse_penalty);
 
/* Search by trying each depot in order of Manhattan Distance. Good for lots
 
 * of choices and accurate heuristics, such as water. */
 
NPFFoundTargetData NPFRouteToDepotTrialError(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, TransportType type, uint sub_type, Owner owner, RailTypes railtypes);
 

	
 
/**
 
 * Search for any safe tile using a breadth first search and try to reserve a path.
 
 */
 
NPFFoundTargetData NPFRouteToSafeTile(const Vehicle *v, TileIndex tile, Trackdir trackdir,bool override_railtype);
 
NPFFoundTargetData NPFRouteToSafeTile(const struct Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype);
 

	
 

	
 
void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, Vehicle *v, bool reserve_path = false);
 

	
 

	
 
/*
 
 * Functions to manipulate the various NPF related flags on an AyStarNode.
 
 */
 

	
 
/**
 
 * Returns the current value of the given flag on the given AyStarNode.
 
 */
src/openttd.cpp
Show inline comments
 
@@ -22,24 +22,25 @@
 
#include "sound_func.h"
 
#include "window_func.h"
 

	
 
#include "saveload/saveload.h"
 
#include "landscape.h"
 
#include "company_func.h"
 
#include "command_func.h"
 
#include "news_func.h"
 
#include "fileio_func.h"
 
#include "fios.h"
 
#include "aircraft.h"
 
#include "roadveh.h"
 
#include "train.h"
 
#include "console_func.h"
 
#include "screenshot.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "signs_base.h"
 
#include "ai/ai.hpp"
 
#include "ai/ai_config.hpp"
 
#include "settings_func.h"
 
#include "genworld.h"
 
#include "group.h"
 
#include "strings_func.h"
 
#include "date_func.h"
 
@@ -1123,25 +1124,25 @@ void StateGameLoop()
 
							DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber);
 
						}
 
					} break;
 

	
 
					case VEH_TRAIN: {
 
						uint length = 0;
 
						for (Vehicle *u = v; u != NULL; u = u->Next()) length++;
 

	
 
						VehicleRail *wagons = MallocT<VehicleRail>(length);
 
						length = 0;
 
						for (Vehicle *u = v; u != NULL; u = u->Next()) wagons[length++] = u->u.rail;
 

	
 
						TrainConsistChanged(v, true);
 
						TrainConsistChanged((Train *)v, true);
 

	
 
						length = 0;
 
						for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
							if (memcmp(&wagons[length], &u->u.rail, sizeof(VehicleRail)) != 0) {
 
								DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i, wagon %i\n", v->index, (int)v->owner, v->unitnumber, length);
 
							}
 
							length++;
 
						}
 

	
 
						free(wagons);
 
					} break;
 

	
src/pbs.cpp
Show inline comments
 
@@ -213,77 +213,80 @@ static PBSTileInfo FollowReservation(Own
 
		/* Non-pbs signal? Reservation can't continue. */
 
		if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
 
	}
 

	
 
	return PBSTileInfo(tile, trackdir, false);
 
}
 

	
 
/**
 
 * Helper struct for finding the best matching vehicle on a specific track.
 
 */
 
struct FindTrainOnTrackInfo {
 
	PBSTileInfo res; ///< Information about the track.
 
	Vehicle *best;   ///< The currently "best" vehicle we have found.
 
	Train *best;     ///< The currently "best" vehicle we have found.
 

	
 
	/** Init the best location to NULL always! */
 
	FindTrainOnTrackInfo() : best(NULL) {}
 
};
 

	
 
/** Callback for Has/FindVehicleOnPos to find a train on a specific track. */
 
static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
 
{
 
	FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data;
 

	
 
	if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info->res.trackdir))) {
 
		v = v->First();
 
	if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
 

	
 
	Train *t = (Train *)v;
 
	if (HasBit((TrackBits)t->u.rail.track, TrackdirToTrack(info->res.trackdir))) {
 
		t = t->First();
 

	
 
		/* ALWAYS return the lowest ID (anti-desync!) */
 
		if (info->best == NULL || v->index < info->best->index) info->best = v;
 
		return v;
 
		if (info->best == NULL || t->index < info->best->index) info->best = t;
 
		return t;
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/**
 
 * Follow a train reservation to the last tile.
 
 *
 
 * @param v the vehicle
 
 * @param train_on_res Is set to a train we might encounter
 
 * @returns The last tile of the reservation or the current train tile if no reservation present.
 
 */
 
PBSTileInfo FollowTrainReservation(const Vehicle *v, bool *train_on_res)
 
PBSTileInfo FollowTrainReservation(const Train *v, bool *train_on_res)
 
{
 
	assert(v->type == VEH_TRAIN);
 

	
 
	TileIndex tile = v->tile;
 
	Trackdir  trackdir = v->GetVehicleTrackdir();
 

	
 
	if (IsRailDepotTile(tile) && !GetRailDepotReservation(tile)) return PBSTileInfo(tile, trackdir, false);
 

	
 
	FindTrainOnTrackInfo ftoti;
 
	ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir);
 
	ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
 
	if (train_on_res != NULL) *train_on_res = HasVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum);
 
	return ftoti.res;
 
}
 

	
 
/**
 
 * Find the train which has reserved a specific path.
 
 *
 
 * @param tile A tile on the path.
 
 * @param track A reserved track on the tile.
 
 * @return The vehicle holding the reservation or NULL if the path is stray.
 
 */
 
Vehicle *GetTrainForReservation(TileIndex tile, Track track)
 
Train *GetTrainForReservation(TileIndex tile, Track track)
 
{
 
	assert(HasReservedTracks(tile, TrackToTrackBits(track)));
 
	Trackdir  trackdir = TrackToTrackdir(track);
 

	
 
	RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes;
 

	
 
	/* Follow the path from tile to both ends, one of the end tiles should
 
	 * have a train on it. We need FollowReservation to ignore one-way signals
 
	 * here, as one of the two search directions will be the "wrong" way. */
 
	for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) {
 
		FindTrainOnTrackInfo ftoti;
 
		ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true);
 
@@ -311,25 +314,25 @@ Vehicle *GetTrainForReservation(TileInde
 
}
 

	
 
/**
 
 * Determine whether a certain track on a tile is a safe position to end a path.
 
 *
 
 * @param v the vehicle to test for
 
 * @param tile The tile
 
 * @param trackdir The trackdir to test
 
 * @param include_line_end Should end-of-line tiles be considered safe?
 
 * @param forbid_90def Don't allow trains to make 90 degree turns
 
 * @return True if it is a safe position
 
 */
 
bool IsSafeWaitingPosition(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
 
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg)
 
{
 
	if (IsRailDepotTile(tile)) return true;
 

	
 
	if (IsTileType(tile, MP_RAILWAY)) {
 
		/* For non-pbs signals, stop on the signal tile. */
 
		if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
 
	}
 

	
 
	/* Check next tile. For perfomance reasons, we check for 90 degree turns ourself. */
 
	CFollowTrackRail ft(v, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes);
 

	
 
	/* End of track? */
 
@@ -351,25 +354,25 @@ bool IsSafeWaitingPosition(const Vehicle
 
	return false;
 
}
 

	
 
/**
 
 * Check if a safe position is free.
 
 *
 
 * @param v the vehicle to test for
 
 * @param tile The tile
 
 * @param trackdir The trackdir to test
 
 * @param forbid_90def Don't allow trains to make 90 degree turns
 
 * @return True if the position is free
 
 */
 
bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
 
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg)
 
{
 
	Track     track = TrackdirToTrack(trackdir);
 
	TrackBits reserved = GetReservedTrackbits(tile);
 

	
 
	/* Tile reserved? Can never be a free waiting position. */
 
	if (TrackOverlapsTracks(reserved, track)) return false;
 

	
 
	/* Not reserved and depot or not a pbs signal -> free. */
 
	if (IsRailDepotTile(tile)) return true;
 
	if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true;
 

	
 
	/* Check the next tile, if it's a PBS signal, it has to be free as well. */
src/pbs.h
Show inline comments
 
@@ -18,29 +18,29 @@ bool TryReserveRailTrack(TileIndex tile,
 
void UnreserveRailTrack(TileIndex tile, Track t);
 

	
 
/** This struct contains information about the end of a reserved path. */
 
struct PBSTileInfo {
 
	TileIndex tile;      ///< Tile the path ends, INVALID_TILE if no valid path was found.
 
	Trackdir  trackdir;  ///< The reserved trackdir on the tile.
 
	bool      okay;      ///< True if tile is a safe waiting position, false otherwise.
 

	
 
	PBSTileInfo() : tile(INVALID_TILE), trackdir(INVALID_TRACKDIR), okay(false) {}
 
	PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {}
 
};
 

	
 
PBSTileInfo FollowTrainReservation(const Vehicle *v, bool *train_on_res = NULL);
 
bool IsSafeWaitingPosition(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false);
 
bool IsWaitingPositionFree(const Vehicle *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false);
 
PBSTileInfo FollowTrainReservation(const Train *v, bool *train_on_res = NULL);
 
bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false);
 
bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false);
 

	
 
Vehicle *GetTrainForReservation(TileIndex tile, Track track);
 
Train *GetTrainForReservation(TileIndex tile, Track track);
 

	
 
/**
 
 * Check whether some of tracks is reserved on a tile.
 
 *
 
 * @param tile the tile
 
 * @param tracks the tracks to test
 
 * @return true if at least on of tracks is reserved
 
 */
 
static inline bool HasReservedTracks(TileIndex tile, TrackBits tracks)
 
{
 
	return (GetReservedTrackbits(tile) & tracks) != TRACK_BIT_NONE;
 
}
src/rail_cmd.cpp
Show inline comments
 
@@ -83,25 +83,26 @@ const byte _track_sloped_sprites[14] = {
 
 *               01abcdef => rail w/ signals
 
 *               10uuuuuu => unused
 
 *               11uuuudd => rail depot
 
 */
 

	
 

	
 
Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
 
{
 
	TrackBits rail_bits = *(TrackBits *)data;
 

	
 
	if (v->type != VEH_TRAIN) return NULL;
 

	
 
	if ((v->u.rail.track != rail_bits) && !TracksOverlap(v->u.rail.track | rail_bits)) return NULL;
 
	Train *t = (Train *)v;
 
	if ((t->u.rail.track != rail_bits) && !TracksOverlap(t->u.rail.track | rail_bits)) return NULL;
 

	
 
	_error_message = VehicleInTheWayErrMsg(v);
 
	return v;
 
}
 

	
 
/**
 
 * Tests if a vehicle interacts with the specified track.
 
 * All track bits interact except parallel TRACK_BIT_HORZ or TRACK_BIT_VERT.
 
 *
 
 * @param tile The tile.
 
 * @param track The track.
 
 */
 
@@ -447,25 +448,25 @@ CommandCost CmdRemoveSingleRail(TileInde
 
	CommandCost cost(EXPENSES_CONSTRUCTION, _price.remove_rail );
 
	bool crossing = false;
 

	
 
	if (!ValParamTrackOrientation((Track)p2)) return CMD_ERROR;
 
	trackbit = TrackToTrackBits(track);
 

	
 
	/* Need to read tile owner now because it may change when the rail is removed
 
	 * Also, in case of floods, _current_company != owner
 
	 * There may be invalid tiletype even in exec run (when removing long track),
 
	 * so do not call GetTileOwner(tile) in any case here */
 
	Owner owner = INVALID_OWNER;
 

	
 
	Vehicle *v = NULL;
 
	Train *v = NULL;
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_ROAD: {
 
			if (!IsLevelCrossing(tile) ||
 
					GetCrossingRailBits(tile) != trackbit ||
 
					(_current_company != OWNER_WATER && !CheckTileOwnership(tile)) ||
 
					(!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile))) {
 
				return CMD_ERROR;
 
			}
 

	
 
			if (flags & DC_EXEC) {
 
				if (HasReservedTracks(tile, trackbit)) {
 
@@ -868,25 +869,25 @@ CommandCost CmdBuildSingleSignal(TileInd
 
			} else {
 
				/* it is free to change signal type: normal-pre-exit-combo */
 
				cost = CommandCost();
 
			}
 

	
 
		} else {
 
			/* it is free to change orientation/pre-exit-combo signals */
 
			cost = CommandCost();
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		Vehicle *v = NULL;
 
		Train *v = NULL;
 
		/* The new/changed signal could block our path. As this can lead to
 
		 * stale reservations, we clear the path reservation here and try
 
		 * to redo it later on. */
 
		if (HasReservedTracks(tile, TrackToTrackBits(track))) {
 
			v = GetTrainForReservation(tile, track);
 
			if (v != NULL) FreeTrainTrackReservation(v);
 
		}
 

	
 
		if (!HasSignals(tile)) {
 
			/* there are no signals at all on this tile yet */
 
			SetHasSignals(tile, true);
 
			SetSignalStates(tile, 0xF); // all signals are on
 
@@ -1175,25 +1176,25 @@ CommandCost CmdRemoveSingleSignal(TileIn
 
			!IsPlainRailTile(tile) ||
 
			!HasTrack(tile, track) ||
 
			!EnsureNoTrainOnTrack(tile, track) ||
 
			!HasSignalOnTrack(tile, track)) {
 
		return CMD_ERROR;
 
	}
 

	
 
	/* Only water can remove signals from anyone */
 
	if (_current_company != OWNER_WATER && !CheckTileOwnership(tile)) return CMD_ERROR;
 

	
 
	/* Do it? */
 
	if (flags & DC_EXEC) {
 
		Vehicle *v = NULL;
 
		Train *v = NULL;
 
		if (HasReservedTracks(tile, TrackToTrackBits(track))) {
 
			v = GetTrainForReservation(tile, track);
 
		}
 
		SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track));
 

	
 
		/* removed last signal from tile? */
 
		if (GetPresentSignals(tile) == 0) {
 
			SetSignalStates(tile, 0);
 
			SetHasSignals(tile, false);
 
			SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC); // remove any possible semaphores
 
		}
 

	
 
@@ -1225,25 +1226,25 @@ CommandCost CmdRemoveSingleSignal(TileIn
 
CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text); // bit 5 is remove bit
 
}
 

	
 
/** Update power of train under which is the railtype being converted */
 
Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data)
 
{
 
	/* Similiar checks as in TrainPowerChanged() */
 

	
 
	if (v->type == VEH_TRAIN && !IsArticulatedPart(v)) {
 
		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
 
		if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged(v->First());
 
		if (GetVehicleProperty(v, 0x0B, rvi->power) != 0) TrainPowerChanged((Train *)v->First());
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/** Convert one rail type to the other. You can convert normal rail to
 
 * monorail/maglev easily or vice-versa.
 
 * @param tile end tile of rail conversion drag
 
 * @param flags operation to perform
 
 * @param p1 start tile of drag
 
 * @param p2 new railtype to convert to
 
 */
 
@@ -1287,35 +1288,35 @@ CommandCost CmdConvertRail(TileIndex til
 
				default: continue;
 
			}
 

	
 
			/* Original railtype we are converting from */
 
			RailType type = GetRailType(tile);
 

	
 
			/* Converting to the same type or converting 'hidden' elrail -> rail */
 
			if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue;
 

	
 
			/* Trying to convert other's rail */
 
			if (!CheckTileOwnership(tile)) continue;
 

	
 
			SmallVector<Vehicle*, 2> vehicles_affected;
 
			SmallVector<Train *, 2> vehicles_affected;
 

	
 
			/* Vehicle on the tile when not converting Rail <-> ElRail
 
			 * Tunnels and bridges have special check later */
 
			if (tt != MP_TUNNELBRIDGE) {
 
				if (!IsCompatibleRail(type, totype) && !EnsureNoVehicleOnGround(tile)) continue;
 
				if (flags & DC_EXEC) { // we can safely convert, too
 
					TrackBits reserved = GetReservedTrackbits(tile);
 
					Track     track;
 
					while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
 
						Vehicle *v = GetTrainForReservation(tile, track);
 
						Train *v = GetTrainForReservation(tile, track);
 
						if (v != NULL && !HasPowerOnRail(v->u.rail.railtype, totype)) {
 
							/* No power on new rail type, reroute. */
 
							FreeTrainTrackReservation(v);
 
							*vehicles_affected.Append() = v;
 
						}
 
					}
 

	
 
					SetRailType(tile, totype);
 
					MarkTileDirtyByTile(tile);
 
					/* update power of train engines on this tile */
 
					FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
 
				}
 
@@ -1363,25 +1364,25 @@ CommandCost CmdConvertRail(TileIndex til
 
					/* If both ends of tunnel/bridge are in the range, do not try to convert twice -
 
					 * it would cause assert because of different test and exec runs */
 
					if (endtile < tile && TileX(endtile) >= sx && TileX(endtile) <= ex &&
 
							TileY(endtile) >= sy && TileY(endtile) <= ey) continue;
 

	
 
					/* When not coverting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */
 
					if (!IsCompatibleRail(GetRailType(tile), totype) &&
 
							HasVehicleOnTunnelBridge(tile, endtile)) continue;
 

	
 
					if (flags & DC_EXEC) {
 
						Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
 
						if (GetTunnelBridgeReservation(tile)) {
 
							Vehicle *v = GetTrainForReservation(tile, track);
 
							Train *v = GetTrainForReservation(tile, track);
 
							if (v != NULL && !HasPowerOnRail(v->u.rail.railtype, totype)) {
 
								/* No power on new rail type, reroute. */
 
								FreeTrainTrackReservation(v);
 
								*vehicles_affected.Append() = v;
 
							}
 
						}
 
						SetRailType(tile, totype);
 
						SetRailType(endtile, totype);
 

	
 
						FindVehicleOnPos(tile, NULL, &UpdateTrainPowerProc);
 
						FindVehicleOnPos(endtile, NULL, &UpdateTrainPowerProc);
 

	
 
@@ -1423,25 +1424,25 @@ CommandCost CmdConvertRail(TileIndex til
 
static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags)
 
{
 
	if (!CheckTileOwnership(tile) && _current_company != OWNER_WATER)
 
		return CMD_ERROR;
 

	
 
	if (!EnsureNoVehicleOnGround(tile))
 
		return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		/* read variables before the depot is removed */
 
		DiagDirection dir = GetRailDepotDirection(tile);
 
		Owner owner = GetTileOwner(tile);
 
		Vehicle *v = NULL;
 
		Train *v = NULL;
 

	
 
		if (GetDepotWaypointReservation(tile)) {
 
			v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir));
 
			if (v != NULL) FreeTrainTrackReservation(v);
 
		}
 

	
 
		DoClearSquare(tile);
 
		delete GetDepotByTile(tile);
 
		AddSideToSignalBuffer(tile, dir, owner);
 
		YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
 
		if (v != NULL) TryPathReserve(v, true);
 
	}
 
@@ -2441,33 +2442,35 @@ int TicksToLeaveDepot(const Vehicle *v)
 
		case DIAGDIR_NE: return  ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
 
		case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4)   + (length + 1)));
 
		case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1)));
 
		default:
 
		case DIAGDIR_NW: return  ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4)   - (length + 1)));
 
	}
 

	
 
	return 0; // make compilers happy
 
}
 

	
 
/** Tile callback routine when vehicle enters tile
 
 * @see vehicle_enter_tile_proc */
 
static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
 
static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y)
 
{
 
	byte fract_coord;
 
	byte fract_coord_leave;
 
	DiagDirection dir;
 
	int length;
 

	
 
	/* this routine applies only to trains in depot tiles */
 
	if (v->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
 
	if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE;
 

	
 
	Train *v = (Train *)u;
 

	
 
	/* depot direction */
 
	dir = GetRailDepotDirection(tile);
 

	
 
	/* calculate the point where the following wagon should be activated
 
	 * this depends on the length of the current vehicle */
 
	length = v->u.rail.cached_veh_length;
 

	
 
	fract_coord_leave =
 
		((_fractcoords_enter[dir] & 0x0F) + // x
 
			(length + 1) * _deltacoord_leaveoffset[dir]) +
 
		(((_fractcoords_enter[dir] >> 4) +  // y
src/saveload/afterload.cpp
Show inline comments
 
@@ -903,41 +903,41 @@ bool AfterLoadGame()
 
					default: NOT_REACHED();
 
					case DIAGDIR_NE: if ((v->x_pos & 0xF) !=  0)            continue; break;
 
					case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break;
 
					case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break;
 
					case DIAGDIR_NW: if ((v->y_pos & 0xF) !=  0)            continue; break;
 
				}
 
			} else if (v->z_pos > GetSlopeZ(v->x_pos, v->y_pos)) {
 
				v->tile = GetNorthernBridgeEnd(v->tile);
 
			} else {
 
				continue;
 
			}
 
			if (v->type == VEH_TRAIN) {
 
				v->u.rail.track = TRACK_BIT_WORMHOLE;
 
				((Train *)v)->u.rail.track = TRACK_BIT_WORMHOLE;
 
			} else {
 
				((RoadVehicle *)v)->state = RVSB_WORMHOLE;
 
			}
 
		}
 
	}
 

	
 
	/* Elrails got added in rev 24 */
 
	if (CheckSavegameVersion(24)) {
 
		Vehicle *v;
 
		RailType min_rail = RAILTYPE_ELECTRIC;
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN) {
 
				RailType rt = RailVehInfo(v->engine_type)->railtype;
 

	
 
				v->u.rail.railtype = rt;
 
				((Train *)v)->u.rail.railtype = rt;
 
				if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
 
			}
 
		}
 

	
 
		/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			switch (GetTileType(t)) {
 
				case MP_RAILWAY:
 
					SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					break;
 

	
 
				case MP_ROAD:
 
@@ -955,25 +955,25 @@ bool AfterLoadGame()
 
				case MP_TUNNELBRIDGE:
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
 
						SetRailType(t, UpdateRailType(GetRailType(t), min_rail));
 
					}
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged(v, true);
 
			if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) TrainConsistChanged((Train *)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
 
@@ -1691,27 +1691,28 @@ bool AfterLoadGame()
 

	
 
				case MP_TUNNELBRIDGE: // Clear PBS reservation on tunnels/birdges
 
					if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false);
 
					break;
 

	
 
				default: break;
 
			}
 
		}
 
	}
 

	
 
	/* Reserve all tracks trains are currently on. */
 
	if (CheckSavegameVersion(101)) {
 
		Vehicle *v;
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN) {
 
		Vehicle *u;
 
		FOR_ALL_VEHICLES(u) {
 
			if (u->type == VEH_TRAIN) {
 
				Train *v = (Train *)u;
 
				if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
 
					TryReserveRailTrack(v->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(v->tile)));
 
				} else if ((v->u.rail.track & TRACK_BIT_MASK) != TRACK_BIT_NONE) {
 
					TryReserveRailTrack(v->tile, TrackBitsToTrack(v->u.rail.track));
 
				}
 
			}
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(102)) {
 
		for (TileIndex t = 0; t < map_size; t++) {
 
			/* Now all crossings should be in correct state */
src/saveload/oldloader_sl.cpp
Show inline comments
 
@@ -1306,25 +1306,25 @@ bool LoadOldVehicle(LoadgameState *ls, i
 
			}
 
			v->cur_image = sprite;
 

	
 
			switch (v->type) {
 
				case VEH_TRAIN: {
 
					static const byte spriteset_rail[] = {
 
						  0,   2,   4,   4,   8,  10,  12,  14,  16,  18,  20,  22,  40,  42,  44,  46,
 
						 48,  52,  54,  66,  68,  70,  72,  74,  76,  78,  80,  82,  84,  86, 120, 122,
 
						124, 126, 128, 130, 132, 134, 136, 138, 140
 
					};
 
					if (v->spritenum / 2 >= lengthof(spriteset_rail)) return false;
 
					v->spritenum = spriteset_rail[v->spritenum / 2]; // adjust railway sprite set offset
 
					v->u.rail.railtype = type == 0x25 ? 1 : 0; // monorail / rail
 
					((Train *)v)->u.rail.railtype = type == 0x25 ? 1 : 0; // monorail / rail
 
					break;
 
				}
 

	
 
				case VEH_ROAD:
 
					if (v->spritenum >= 22) v->spritenum += 12;
 
					break;
 

	
 
				case VEH_SHIP:
 
					v->spritenum += 2;
 

	
 
					switch (v->spritenum) {
 
						case 2: // oil tanker && cargo type != oil
src/saveload/vehicle_sl.cpp
Show inline comments
 
@@ -15,58 +15,58 @@
 
#include <map>
 

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

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN) {
 
			v->u.rail.other_multiheaded_part = NULL;
 
			((Train *)v)->u.rail.other_multiheaded_part = NULL;
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && (IsFrontEngine(v) || 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);
 

	
 
			for (Vehicle *u = v; u != NULL; u = GetNextVehicle(u)) {
 
			for (Train *u = (Train *)v; u != NULL; u = (Train *)GetNextVehicle(u)) {
 
				if (u->u.rail.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;
 
					Vehicle *w;
 
					Train *w;
 
					if (sequential_matching) {
 
						for (w = GetNextVehicle(u); w != NULL; w = GetNextVehicle(w)) {
 
							if (w->engine_type != eid || w->u.rail.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;
 
						}
 
					} else {
 
@@ -309,26 +309,26 @@ void AfterLoadVehicles(bool part_of_load
 
			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)) v->u.rail.last_speed = v->cur_speed; // update displayed train speed
 
			TrainConsistChanged(v, false);
 
			if (IsFrontEngine(v)) ((Train *)v)->u.rail.last_speed = v->cur_speed; // update displayed train speed
 
			TrainConsistChanged((Train *)v, false);
 
		} else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
 
			RoadVehUpdateCache((RoadVehicle *)v);
 
		}
 
	}
 

	
 
	/* Stop non-front engines */
 
	if (CheckSavegameVersion(112)) {
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
 
				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 */
src/settings.cpp
Show inline comments
 
@@ -688,25 +688,25 @@ static bool InvalidateTownViewWindow(int
 

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

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

	
 
/* Check service intervals of vehicles, p1 is value of % or day based servicing */
 
static bool CheckInterval(int32 p1)
 
{
 
	VehicleSettings *ptc = (_game_mode == GM_MENU) ? &_settings_newgame.vehicle : &_settings_game.vehicle;
 

	
 
	if (p1) {
 
		ptc->servint_trains   = 50;
 
		ptc->servint_roadveh  = 50;
 
@@ -738,25 +738,25 @@ static bool EngineRenewMonthsUpdate(int3
 

	
 
static bool EngineRenewMoneyUpdate(int32 p1)
 
{
 
	DoCommandP(0, 2, _settings_client.company.engine_renew_money, CMD_SET_AUTOREPLACE);
 
	return true;
 
}
 

	
 
static bool TrainAccelerationModelChanged(int32 p1)
 
{
 
	Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && IsFrontEngine(v)) UpdateTrainAcceleration(v);
 
		if (v->type == VEH_TRAIN && IsFrontEngine(v)) UpdateTrainAcceleration((Train *)v);
 
	}
 

	
 
	return true;
 
}
 

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

	
 
	return true;
 
}
 

	
src/signal.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file signal.cpp functions related to rail signals updating */
 

	
 
#include "stdafx.h"
 
#include "debug.h"
 
#include "station_map.h"
 
#include "tunnelbridge_map.h"
 
#include "vehicle_func.h"
 
#include "vehicle_base.h"
 
#include "functions.h"
 
#include "train.h"
 

	
 

	
 
/** these are the maximums used for updating signal blocks */
 
enum {
 
	SIG_TBU_SIZE    =  64, ///< number of signals entering to block
 
	SIG_TBD_SIZE    = 256, ///< number of intersections - open nodes in current block
 
	SIG_GLOB_SIZE   = 128, ///< number of open blocks (block can be opened more times until detected)
 
	SIG_GLOB_UPDATE =  64, ///< how many items need to be in _globset to force update
 
};
 

	
 
/* need to typecast to compile with MorphOS */
 
assert_compile((int)SIG_GLOB_UPDATE <= (int)SIG_GLOB_SIZE);
 
@@ -176,25 +176,25 @@ public:
 
		return true;
 
	}
 
};
 

	
 
static SmallSet<Trackdir, SIG_TBU_SIZE> _tbuset("_tbuset");         ///< set of signals that will be updated
 
static SmallSet<DiagDirection, SIG_TBD_SIZE> _tbdset("_tbdset");    ///< set of open nodes in current signal block
 
static SmallSet<DiagDirection, SIG_GLOB_SIZE> _globset("_globset"); ///< set of places to be updated in following runs
 

	
 

	
 
/** Check whether there is a train on rail, not in a depot */
 
static Vehicle *TrainOnTileEnum(Vehicle *v, void *)
 
{
 
	if (v->type != VEH_TRAIN || v->u.rail.track == TRACK_BIT_DEPOT) return NULL;
 
	if (v->type != VEH_TRAIN || ((Train *)v)->u.rail.track == TRACK_BIT_DEPOT) return NULL;
 

	
 
	return v;
 
}
 

	
 

	
 
/**
 
 * Perform some operations before adding data into Todo set
 
 * The new and reverse direction is removed from _globset, because we are sure
 
 * it doesn't need to be checked again
 
 * Also, remove reverse direction from _tbdset
 
 * This is the 'core' part so the graph seaching won't enter any tile twice
 
 *
src/station_cmd.cpp
Show inline comments
 
@@ -1006,33 +1006,33 @@ CommandCost CmdBuildRailroadStation(Tile
 
			 * in the station's cached copy. */
 
			st->cached_anim_triggers |= statspec->anim_triggers;
 
		}
 

	
 
		tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
 
		track = AxisToTrack(axis);
 

	
 
		layout_ptr = AllocaM(byte, numtracks * plat_len);
 
		GetStationLayout(layout_ptr, numtracks, plat_len, statspec);
 

	
 
		numtracks_orig = numtracks;
 

	
 
		SmallVector<Vehicle*, 4> affected_vehicles;
 
		SmallVector<Train*, 4> affected_vehicles;
 
		do {
 
			TileIndex tile = tile_org;
 
			int w = plat_len;
 
			do {
 
				byte layout = *layout_ptr++;
 
				if (IsRailwayStationTile(tile) && GetRailwayStationReservation(tile)) {
 
					/* Check for trains having a reservation for this tile. */
 
					Vehicle *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile)));
 
					Train *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile)));
 
					if (v != NULL) {
 
						FreeTrainTrackReservation(v);
 
						*affected_vehicles.Append() = v;
 
						if (IsRailwayStationTile(v->tile)) SetRailwayStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), false);
 
						for (; v->Next() != NULL; v = v->Next()) ;
 
						if (IsRailwayStationTile(v->tile)) SetRailwayStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), false);
 
					}
 
				}
 

	
 
				byte old_specindex = IsTileType(tile, MP_STATION) ? GetCustomStationSpecIndex(tile) : 0;
 
				MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, (RailType)GB(p1, 0, 4));
 
				/* Free the spec if we overbuild something */
 
@@ -1054,25 +1054,25 @@ CommandCost CmdBuildRailroadStation(Tile
 
					StationAnimationTrigger(st, tile, STAT_ANIM_BUILT);
 
				}
 

	
 
				tile += tile_delta;
 
			} while (--w);
 
			AddTrackToSignalBuffer(tile_org, track, _current_company);
 
			YapfNotifyTrackLayoutChange(tile_org, track);
 
			tile_org += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta
 
		} while (--numtracks);
 

	
 
		for (uint i = 0; i < affected_vehicles.Length(); ++i) {
 
			/* Restore reservations of trains. */
 
			Vehicle *v = affected_vehicles[i];
 
			Train *v = affected_vehicles[i];
 
			if (IsRailwayStationTile(v->tile)) SetRailwayStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true);
 
			TryPathReserve(v, true, true);
 
			for (; v->Next() != NULL; v = v->Next()) ;
 
			if (IsRailwayStationTile(v->tile)) SetRailwayStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true);
 
		}
 

	
 
		st->MarkTilesDirty(false);
 
		UpdateStationVirtCoordDirty(st);
 
		UpdateStationAcceptance(st, false);
 
		InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
@@ -1187,25 +1187,25 @@ CommandCost CmdRemoveFromRailroadStation
 
		 * The check must be here to give correct error message
 
		 */
 
		if (!_settings_game.station.nonuniform_stations) return_cmd_error(STR_NONUNIFORM_STATIONS_DISALLOWED);
 

	
 
		/* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
 
		quantity++;
 

	
 
		if (flags & DC_EXEC) {
 
			/* read variables before the station tile is removed */
 
			uint specindex = GetCustomStationSpecIndex(tile2);
 
			Track track = GetRailStationTrack(tile2);
 
			Owner owner = GetTileOwner(tile2);
 
			Vehicle *v = NULL;
 
			Train *v = NULL;
 

	
 
			if (GetRailwayStationReservation(tile2)) {
 
				v = GetTrainForReservation(tile2, track);
 
				if (v != NULL) {
 
					/* Free train reservation. */
 
					FreeTrainTrackReservation(v);
 
					if (IsRailwayStationTile(v->tile)) SetRailwayStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), false);
 
					Vehicle *temp = v;
 
					for (; temp->Next() != NULL; temp = temp->Next()) ;
 
					if (IsRailwayStationTile(temp->tile)) SetRailwayStationPlatformReservation(temp->tile, TrackdirToExitdir(ReverseTrackdir(temp->GetVehicleTrackdir())), false);
 
				}
 
			}
 
@@ -1271,25 +1271,25 @@ static CommandCost RemoveRailroadStation
 
	do {
 
		int w_bak = w;
 
		do {
 
			/* for nonuniform stations, only remove tiles that are actually train station tiles */
 
			if (st->TileBelongsToRailStation(tile)) {
 
				if (!EnsureNoVehicleOnGround(tile))
 
					return CMD_ERROR;
 
				cost.AddCost(_price.remove_rail_station);
 
				if (flags & DC_EXEC) {
 
					/* read variables before the station tile is removed */
 
					Track track = GetRailStationTrack(tile);
 
					Owner owner = GetTileOwner(tile); // _current_company can be OWNER_WATER
 
					Vehicle *v = NULL;
 
					Train *v = NULL;
 
					if (GetRailwayStationReservation(tile)) {
 
						v = GetTrainForReservation(tile, track);
 
						if (v != NULL) FreeTrainTrackReservation(v);
 
					}
 
					DoClearSquare(tile);
 
					AddTrackToSignalBuffer(tile, track, owner);
 
					YapfNotifyTrackLayoutChange(tile, track);
 
					if (v != NULL) TryPathReserve(v, true);
 
				}
 
			}
 
			tile += TileDiffXY(1, 0);
 
		} while (--w);
 
@@ -2612,25 +2612,25 @@ static bool ClickTile_Station(TileIndex 
 
}
 

	
 
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;
 

	
 
		int station_ahead;
 
		int station_length;
 
		int stop = GetTrainStopLocation(station_id, tile, v, &station_ahead, &station_length);
 
		int stop = GetTrainStopLocation(station_id, tile, (Train *)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;
 

	
src/train.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file train.h Base for the train class. */
 

	
 
#ifndef TRAIN_H
 
#define TRAIN_H
 

	
 
#include "stdafx.h"
 
#include "core/bitmath_func.hpp"
 
#include "vehicle_base.h"
 

	
 
struct Train;
 

	
 
/** 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
 
@@ -193,123 +194,52 @@ static inline void ClearMultiheaded(Vehi
 
}
 

	
 
/** Check if an engine has an articulated part.
 
 * @param v Vehicle.
 
 * @return True if the engine has an articulated part.
 
 */
 
static inline bool EngineHasArticPart(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	return (v->Next() != NULL && IsArticulatedPart(v->Next()));
 
}
 

	
 
/**
 
 * 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 Vehicle *GetNextArticPart(const Vehicle *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 Vehicle *GetLastEnginePart(Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	while (EngineHasArticPart(v)) v = GetNextArticPart(v);
 
	return v;
 
}
 

	
 
/** Tell if we are dealing with the rear end of a multiheaded engine.
 
 * @param v Vehicle.
 
 * @return True if the engine is the rear part of a dualheaded engine.
 
 */
 
static inline bool IsRearDualheaded(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	return (IsMultiheaded(v) && !IsTrainEngine(v));
 
}
 

	
 
/** Get the next real (non-articulated part) vehicle in the consist.
 
 * @param v Vehicle.
 
 * @return Next vehicle in the consist.
 
 */
 
static inline Vehicle *GetNextVehicle(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	while (EngineHasArticPart(v)) v = GetNextArticPart(v);
 

	
 
	/* v now contains the last artic part in the engine */
 
	return v->Next();
 
}
 

	
 
/** Get the previous real (non-articulated part) vehicle in the consist.
 
 * @param w Vehicle.
 
 * @return Previous vehicle in the consist.
 
 */
 
static inline Vehicle *GetPrevVehicle(const Vehicle *w)
 
{
 
	assert(w->type == VEH_TRAIN);
 

	
 
	Vehicle *v = w->Previous();
 
	while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
 

	
 
	return v;
 
}
 

	
 
/** Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist.
 
 * @param v Vehicle.
 
 * @return Next vehicle in the consist.
 
 */
 
static inline Vehicle *GetNextUnit(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	Vehicle *w = GetNextVehicle(v);
 
	if (w != NULL && IsRearDualheaded(w)) w = GetNextVehicle(w);
 

	
 
	return w;
 
}
 

	
 
/** Get the previous real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist.
 
 * @param v Vehicle.
 
 * @return Previous vehicle in the consist.
 
 */
 
static inline Vehicle *GetPrevUnit(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	Vehicle *w = GetPrevVehicle(v);
 
	if (w != NULL && IsRearDualheaded(w)) w = GetPrevVehicle(w);
 

	
 
	return w;
 
}
 

	
 
void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2);
 
void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2);
 

	
 
byte FreightWagonMult(CargoID cargo);
 

	
 
int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped);
 
int CheckTrainStoppedInDepot(const Vehicle *v);
 
void UpdateTrainAcceleration(Vehicle *v);
 
int CheckTrainInDepot(const Train *v, bool needs_to_be_stopped);
 
int CheckTrainStoppedInDepot(const Train *v);
 
void UpdateTrainAcceleration(Train *v);
 
void CheckTrainsLengths();
 

	
 
void FreeTrainTrackReservation(const Vehicle *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
 
bool TryPathReserve(Vehicle *v, bool mark_as_stuck = false, bool first_tile_okay = false);
 
void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
 
bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);
 

	
 
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Vehicle *v, int *station_ahead, int *station_length);
 
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);
 

	
 
void TrainConsistChanged(Train *v, bool same_length);
 
void TrainPowerChanged(Train *v);
 
Money GetTrainRunningCost(const Train *v);
 

	
 
/**
 
 * This class 'wraps' Vehicle; you do not actually instantiate this class.
 
 * You create a Vehicle using AllocateVehicle, so it is added to the pool
 
 * and you reinitialize that to a Train using:
 
 *   v = new (v) Train();
 
 *
 
 * As side-effect the vehicle type is set correctly.
 
 */
 
struct Train : public Vehicle {
 
	/** Initializes the Vehicle to a train */
 
	Train() { this->type = VEH_TRAIN; }
 
@@ -325,15 +255,96 @@ struct Train : public Vehicle {
 
	bool IsPrimaryVehicle() const { return IsFrontEngine(this); }
 
	SpriteID GetImage(Direction direction) const;
 
	int GetDisplaySpeed() const { return this->u.rail.last_speed; }
 
	int GetDisplayMaxSpeed() const { return this->u.rail.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);
 
	Train *First() { return (Train *)this->Vehicle::First(); }
 
	Train *First() const { return (Train *)this->Vehicle::First(); }
 
	Train *Next() { return (Train *)this->Vehicle::Next(); }
 
	Train *Next() const { return (Train *)this->Vehicle::Next(); }
 
	Train *Previous() { return (Train *)this->Vehicle::Previous(); }
 
	Train *Previous() const { return (Train *)this->Vehicle::Previous(); }
 
};
 

	
 
/**
 
 * 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;
 
}
 

	
 
/** Get the next real (non-articulated part) vehicle in the consist.
 
 * @param v Vehicle.
 
 * @return Next vehicle in the consist.
 
 */
 
static inline Train *GetNextVehicle(const Train *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	while (EngineHasArticPart(v)) v = GetNextArticPart(v);
 

	
 
	/* v now contains the last artic part in the engine */
 
	return v->Next();
 
}
 

	
 
/** Get the previous real (non-articulated part) vehicle in the consist.
 
 * @param w Vehicle.
 
 * @return Previous vehicle in the consist.
 
 */
 
static inline Train *GetPrevVehicle(const Train *w)
 
{
 
	assert(w->type == VEH_TRAIN);
 

	
 
	Train *v = w->Previous();
 
	while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
 

	
 
	return v;
 
}
 

	
 
/** Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist.
 
 * @param v Vehicle.
 
 * @return Next vehicle in the consist.
 
 */
 
static inline Train *GetNextUnit(const Train *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	Train *w = GetNextVehicle(v);
 
	if (w != NULL && IsRearDualheaded(w)) w = GetNextVehicle(w);
 

	
 
	return w;
 
}
 

	
 
/** Get the previous real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist.
 
 * @param v Vehicle.
 
 * @return Previous vehicle in the consist.
 
 */
 
static inline Train *GetPrevUnit(const Train *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	Train *w = GetPrevVehicle(v);
 
	if (w != NULL && IsRearDualheaded(w)) w = GetPrevVehicle(w);
 

	
 
	return w;
 
}
 

	
 
#endif /* TRAIN_H */
src/train_cmd.cpp
Show inline comments
 
@@ -28,30 +28,30 @@
 
#include "variables.h"
 
#include "autoreplace_gui.h"
 
#include "gfx_func.h"
 
#include "ai/ai.hpp"
 
#include "newgrf_station.h"
 
#include "effectvehicle_func.h"
 
#include "gamelog.h"
 
#include "network/network.h"
 

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

	
 
static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
 
static bool TrainCheckIfLineEnds(Vehicle *v);
 
static void TrainController(Vehicle *v, Vehicle *nomove);
 
static TileIndex TrainApproachingCrossingTile(const Vehicle *v);
 
static void CheckIfTrainNeedsService(Vehicle *v);
 
static void CheckNextTrainTile(Vehicle *v);
 
static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
 
static bool TrainCheckIfLineEnds(Train *v);
 
static void TrainController(Train *v, Vehicle *nomove);
 
static TileIndex TrainApproachingCrossingTile(const Train *v);
 
static void CheckIfTrainNeedsService(Train *v);
 
static void CheckNextTrainTile(Train *v);
 

	
 
static const byte _vehicle_initial_x_fract[4] = {10, 8, 4,  8};
 
static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
 

	
 

	
 
/**
 
 * Determine the side in which the train will leave the tile
 
 *
 
 * @param direction vehicle direction
 
 * @param track vehicle track bits
 
 * @return side of tile the train will leave
 
 */
 
@@ -76,30 +76,30 @@ static inline DiagDirection TrainExitDir
 
 */
 
byte FreightWagonMult(CargoID cargo)
 
{
 
	if (!GetCargo(cargo)->is_freight) return 1;
 
	return _settings_game.vehicle.freight_trains;
 
}
 

	
 

	
 
/**
 
 * Recalculates the cached total power of a train. Should be called when the consist is changed
 
 * @param v First vehicle of the consist.
 
 */
 
void TrainPowerChanged(Vehicle *v)
 
void TrainPowerChanged(Train *v)
 
{
 
	uint32 total_power = 0;
 
	uint32 max_te = 0;
 

	
 
	for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (const Train *u = v; u != NULL; u = u->Next()) {
 
		RailType railtype = GetRailType(u->tile);
 

	
 
		/* Power is not added for articulated parts */
 
		if (!IsArticulatedPart(u)) {
 
			bool engine_has_power = HasPowerOnRail(u->u.rail.railtype, railtype);
 

	
 
			const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type);
 

	
 
			if (engine_has_power) {
 
				uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
 
				if (power != 0) {
 
					/* Halve power for multiheaded parts */
 
@@ -125,29 +125,29 @@ void TrainPowerChanged(Vehicle *v)
 
		v->u.rail.cached_max_te = max_te;
 
		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 
}
 

	
 

	
 
/**
 
 * Recalculates the cached weight of a train and its vehicles. Should be called each time the cargo on
 
 * the consist changes.
 
 * @param v First vehicle of the consist.
 
 */
 
static void TrainCargoChanged(Vehicle *v)
 
static void TrainCargoChanged(Train *v)
 
{
 
	uint32 weight = 0;
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (Train *u = v; u != NULL; u = u->Next()) {
 
		uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16;
 

	
 
		/* Vehicle weight is not added for articulated parts. */
 
		if (!IsArticulatedPart(u)) {
 
			/* vehicle weight is the sum of the weight of the vehicle and the weight of its cargo */
 
			vweight += GetVehicleProperty(u, 0x16, RailVehInfo(u->engine_type)->weight);
 
		}
 

	
 
		/* powered wagons have extra weight added */
 
		if (HasBit(u->u.rail.flags, VRF_POWEREDWAGON)) {
 
			vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
 
		}
 
@@ -162,104 +162,104 @@ static void TrainCargoChanged(Vehicle *v
 
	/* store consist weight in cache */
 
	v->u.rail.cached_weight = weight;
 

	
 
	/* Now update train power (tractive effort is dependent on weight) */
 
	TrainPowerChanged(v);
 
}
 

	
 

	
 
/** Logs a bug in GRF and shows a warning message if this
 
 * is for the first time this happened.
 
 * @param u first vehicle of chain
 
 */
 
static void RailVehicleLengthChanged(const Vehicle *u)
 
static void RailVehicleLengthChanged(const Train *u)
 
{
 
	/* show a warning once for each engine in whole game and once for each GRF after each game load */
 
	const Engine *engine = Engine::Get(u->engine_type);
 
	uint32 grfid = engine->grffile->grfid;
 
	GRFConfig *grfconfig = GetGRFConfig(grfid);
 
	if (GamelogGRFBugReverse(grfid, engine->internal_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) {
 
		ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true);
 
	}
 
}
 

	
 
/** Checks if lengths of all rail vehicles are valid. If not, shows an error message. */
 
void CheckTrainsLengths()
 
{
 
	const Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && v->First() == v && !(v->vehstatus & VS_CRASHED)) {
 
			for (const Vehicle *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) {
 
			for (const Train *u = (Train *)v, *w = (Train *)v->Next(); w != NULL; u = w, w = w->Next()) {
 
				if (u->u.rail.track != TRACK_BIT_DEPOT) {
 
					if ((w->u.rail.track != TRACK_BIT_DEPOT &&
 
							max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->u.rail.cached_veh_length) ||
 
							(w->u.rail.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);
 

	
 
						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(Vehicle *v, bool same_length)
 
void TrainConsistChanged(Train *v, bool same_length)
 
{
 
	uint16 max_speed = UINT16_MAX;
 

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

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

	
 
	bool train_can_tilt = true;
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
	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->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
 
		u->u.rail.railtype = rvi_u->railtype;
 

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

	
 
		/* Set user defined data to its default value */
 
		u->u.rail.user_def_data = rvi_u->user_def_data;
 
		u->cache_valid = 0;
 
	}
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (Train *u = v; u != NULL; u = u->Next()) {
 
		/* Update user defined data (must be done before other properties) */
 
		u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, u->u.rail.user_def_data);
 
		u->cache_valid = 0;
 
	}
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (Train *u = v; u != NULL; u = u->Next()) {
 
		const Engine *e_u = Engine::Get(u->engine_type);
 
		const RailVehicleInfo *rvi_u = &e_u->u.rail;
 

	
 
		if (!HasBit(EngInfo(u->engine_type)->misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
 

	
 
		/* Cache wagon override sprite group. NULL is returned if there is none */
 
		u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
 

	
 
		/* Reset colour map */
 
		u->colourmap = PAL_NONE;
 

	
 
		if (rvi_u->visual_effect != 0) {
 
@@ -355,25 +355,25 @@ enum AccelType {
 
};
 

	
 
/**
 
 * 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 Vehicle *v, int *station_ahead, int *station_length)
 
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;
 
	*station_length = st->GetPlatformLength(tile) * TILE_SIZE;
 

	
 
	/* Default to the middle of the station for stations stops that are not in
 
	 * the order list like intermediate stations when non-stop is disabled */
 
	OrderStopLocation osl = OSL_PLATFORM_MIDDLE;
 
	if (v->u.rail.cached_total_length >= *station_length) {
 
		/* The train is longer than the station, make it stop at the far end of the platform */
 
		osl = OSL_PLATFORM_FAR_END;
 
	} else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) {
 
@@ -395,25 +395,25 @@ int GetTrainStopLocation(StationID stati
 

	
 
		case OSL_PLATFORM_FAR_END:
 
			stop = *station_length;
 
			break;
 
	}
 

	
 
	/* Substract half the front vehicle length of the train so we get the real
 
	 * stop location of the train. */
 
	return stop - (v->u.rail.cached_veh_length + 1) / 2;
 
}
 

	
 
/** new acceleration*/
 
static int GetTrainAcceleration(Vehicle *v, bool mode)
 
static int GetTrainAcceleration(Train *v, bool mode)
 
{
 
	static const int absolute_max_speed = UINT16_MAX;
 
	int max_speed = absolute_max_speed;
 
	int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
 
	int curvecount[2] = {0, 0};
 

	
 
	/* first find the curve speed limit */
 
	int numcurve = 0;
 
	int sum = 0;
 
	int pos = 0;
 
	int lastpos = -1;
 
	for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) {
 
@@ -487,25 +487,25 @@ static int GetTrainAcceleration(Vehicle 
 
				max_speed = min(max_speed, st_max_speed);
 
			}
 
		}
 
	}
 

	
 
	int mass = v->u.rail.cached_weight;
 
	int power = v->u.rail.cached_power * 746;
 
	max_speed = min(max_speed, v->u.rail.cached_max_speed);
 

	
 
	int num = 0; // number of vehicles, change this into the number of axles later
 
	int incl = 0;
 
	int drag_coeff = 20; //[1e-4]
 
	for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (const Train *u = v; u != NULL; u = u->Next()) {
 
		num++;
 
		drag_coeff += 3;
 

	
 
		if (u->u.rail.track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61);
 

	
 
		if (HasBit(u->u.rail.flags, VRF_GOINGUP)) {
 
			incl += u->u.rail.cached_veh_weight * 60; // 3% slope, quite a bit actually
 
		} else if (HasBit(u->u.rail.flags, VRF_GOINGDOWN)) {
 
			incl -= u->u.rail.cached_veh_weight * 60;
 
		}
 
	}
 

	
 
@@ -547,25 +547,25 @@ static int GetTrainAcceleration(Vehicle 
 
		/* "kickoff" acceleration */
 
		force = (mode == AM_ACCEL && v->u.rail.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(Vehicle *v)
 
void UpdateTrainAcceleration(Train *v)
 
{
 
	assert(IsFrontEngine(v));
 

	
 
	v->max_speed = v->u.rail.cached_max_speed;
 

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

	
 
SpriteID Train::GetImage(Direction direction) const
 
@@ -651,25 +651,25 @@ static CommandCost CmdBuildRailWagon(Eng
 

	
 
		Vehicle *w;
 
		FOR_ALL_VEHICLES(w) {
 
			/* do not connect new wagon with crashed/flooded consists */
 
			if (w->type == VEH_TRAIN && w->tile == tile &&
 
					IsFreeWagon(w) && w->engine_type == engine &&
 
					!HASBITS(w->vehstatus, VS_CRASHED)) {
 
				u = GetLastVehicleInChain(w);
 
				break;
 
			}
 
		}
 

	
 
		Vehicle *v = new Train();
 
		Train *v = new Train();
 
		v->spritenum = rvi->image_index;
 

	
 
		v->engine_type = engine;
 

	
 
		DiagDirection dir = GetRailDepotDirection(tile);
 

	
 
		v->direction = DiagDirToDir(dir);
 
		v->tile = tile;
 

	
 
		int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir];
 
		int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir];
 

	
 
@@ -716,42 +716,42 @@ static CommandCost CmdBuildRailWagon(Eng
 
		if (IsLocalCompany()) {
 
			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
 
		}
 
		Company::Get(_current_company)->num_engines[engine]++;
 

	
 
		CheckConsistencyOfArticulatedVehicle(v);
 
	}
 

	
 
	return value;
 
}
 

	
 
/** Move all free vehicles in the depot to the train */
 
static void NormalizeTrainVehInDepot(const Vehicle *u)
 
static void NormalizeTrainVehInDepot(const Train *u)
 
{
 
	const Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && IsFreeWagon(v) &&
 
				v->tile == u->tile &&
 
				v->u.rail.track == TRACK_BIT_DEPOT) {
 
				((Train *)v)->u.rail.track == TRACK_BIT_DEPOT) {
 
			if (CmdFailed(DoCommand(0, v->index | (u->index << 16), 1, DC_EXEC,
 
					CMD_MOVE_RAIL_VEHICLE)))
 
				break;
 
		}
 
	}
 
}
 

	
 
static void AddRearEngineToMultiheadedTrain(Vehicle *v)
 
static void AddRearEngineToMultiheadedTrain(Train *v)
 
{
 
	Vehicle *u = new Train();
 
	Train *u = new Train();
 
	v->value >>= 1;
 
	u->value = v->value;
 
	u->direction = v->direction;
 
	u->owner = v->owner;
 
	u->tile = v->tile;
 
	u->x_pos = v->x_pos;
 
	u->y_pos = v->y_pos;
 
	u->z_pos = v->z_pos;
 
	u->u.rail.track = TRACK_BIT_DEPOT;
 
	u->vehstatus = v->vehstatus & ~VS_STOPPED;
 
//	u->subtype = 0;
 
	u->spritenum = v->spritenum + 1;
 
@@ -814,25 +814,25 @@ CommandCost CmdBuildRailVehicle(TileInde
 
	}
 

	
 
	UnitID unit_num = (flags & DC_AUTOREPLACE) ? 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) {
 
		DiagDirection dir = GetRailDepotDirection(tile);
 
		int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
 
		int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
 

	
 
		Vehicle *v = new Train();
 
		Train *v = new Train();
 
		v->unitnumber = unit_num;
 
		v->direction = DiagDirToDir(dir);
 
		v->tile = tile;
 
		v->owner = _current_company;
 
		v->x_pos = x;
 
		v->y_pos = y;
 
		v->z_pos = GetSlopeZ(x, y);
 
//		v->running_ticks = 0;
 
		v->u.rail.track = TRACK_BIT_DEPOT;
 
		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 
		v->spritenum = rvi->image_index;
 
		v->cargo_type = e->GetDefaultCargoType();
 
@@ -892,193 +892,196 @@ CommandCost CmdBuildRailVehicle(TileInde
 

	
 
		Company::Get(_current_company)->num_engines[p1]++;
 

	
 
		CheckConsistencyOfArticulatedVehicle(v);
 
	}
 

	
 
	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 Vehicle *v, bool needs_to_be_stopped)
 
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->u.rail.track != TRACK_BIT_DEPOT || v->tile != tile ||
 
				(IsFrontEngine(v) && 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 Vehicle *v)
 
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 Vehicle *v)
 
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.
 
 */
 
static Vehicle *UnlinkWagon(Vehicle *v, Vehicle *first)
 
static Train *UnlinkWagon(Train *v, Train *first)
 
{
 
	/* unlinking the first vehicle of the chain? */
 
	if (v == first) {
 
		v = GetNextVehicle(v);
 
		if (v == NULL) return NULL;
 

	
 
		if (IsTrainWagon(v)) SetFreeWagon(v);
 

	
 
		/* First can be an articulated engine, meaning GetNextVehicle() isn't
 
		 * v->Next(). Thus set the next vehicle of the last articulated part
 
		 * and the last articulated part is just before the next vehicle (v). */
 
		v->Previous()->SetNext(NULL);
 

	
 
		return v;
 
	}
 

	
 
	Vehicle *u;
 
	Train *u;
 
	for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {}
 
	GetLastEnginePart(u)->SetNext(GetNextVehicle(v));
 
	return first;
 
}
 

	
 
static Vehicle *FindGoodVehiclePos(const Vehicle *src)
 
static Train *FindGoodVehiclePos(const Train *src)
 
{
 
	Vehicle *dst;
 
	EngineID eng = src->engine_type;
 
	TileIndex tile = src->tile;
 

	
 
	FOR_ALL_VEHICLES(dst) {
 
		if (dst->type == VEH_TRAIN && IsFreeWagon(dst) && dst->tile == tile && !HASBITS(dst->vehstatus, VS_CRASHED)) {
 
			/* check so all vehicles in the line have the same engine. */
 
			Vehicle *v = dst;
 

	
 
			while (v->engine_type == eng) {
 
				v = v->Next();
 
				if (v == NULL) return dst;
 
				if (v == NULL) return (Train *)dst;
 
			}
 
		}
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/*
 
 * add a vehicle v behind vehicle dest
 
 * use this function since it sets flags as needed
 
 */
 
static void AddWagonToConsist(Vehicle *v, Vehicle *dest)
 
static void AddWagonToConsist(Train *v, Train *dest)
 
{
 
	UnlinkWagon(v, v->First());
 
	if (dest == NULL) return;
 

	
 
	Vehicle *next = dest->Next();
 
	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(Vehicle *v)
 
static void NormaliseTrainConsist(Train *v)
 
{
 
	if (IsFreeWagon(v)) return;
 

	
 
	assert(IsFrontEngine(v));
 

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

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

	
 
		if (u == v->u.rail.other_multiheaded_part) continue;
 
		AddWagonToConsist(v->u.rail.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)
 
{
 
	VehicleID s = GB(p1, 0, 16);
 
	VehicleID d = GB(p1, 16, 16);
 

	
 
	Vehicle *src = Vehicle::GetIfValid(s);
 
	if (src == NULL || src->type != VEH_TRAIN || !CheckOwnership(src->owner)) return CMD_ERROR;
 
	Vehicle *src_v = Vehicle::GetIfValid(s);
 
	if (src_v == NULL || src_v->type != VEH_TRAIN || !CheckOwnership(src_v->owner)) return CMD_ERROR;
 

	
 
	/* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */
 
	if (HASBITS(src->vehstatus, VS_CRASHED)) return CMD_ERROR;
 
	if (HASBITS(src_v->vehstatus, VS_CRASHED)) return CMD_ERROR;
 

	
 
	Train *src = (Train *)src_v;
 

	
 
	/* if nothing is selected as destination, try and find a matching vehicle to drag to. */
 
	Vehicle *dst;
 
	Train *dst;
 
	if (d == INVALID_VEHICLE) {
 
		dst = IsTrainEngine(src) ? NULL : FindGoodVehiclePos(src);
 
	} else {
 
		dst = Vehicle::GetIfValid(d);
 
		if (dst == NULL || dst->type != VEH_TRAIN || !CheckOwnership(dst->owner)) return CMD_ERROR;
 
		Vehicle *dst_v = Vehicle::GetIfValid(d);
 
		if (dst_v == NULL || dst_v->type != VEH_TRAIN || !CheckOwnership(dst_v->owner)) return CMD_ERROR;
 

	
 
		/* Do not allow appending to crashed vehicles, too */
 
		if (HASBITS(dst->vehstatus, VS_CRASHED)) return CMD_ERROR;
 
		if (HASBITS(dst_v->vehstatus, VS_CRASHED)) return CMD_ERROR;
 
		dst = (Train *)dst_v;
 
	}
 

	
 
	/* if an articulated part is being handled, deal with its parent vehicle */
 
	while (IsArticulatedPart(src)) src = src->Previous();
 
	if (dst != NULL) {
 
		while (IsArticulatedPart(dst)) dst = dst->Previous();
 
	}
 

	
 
	/* don't move the same vehicle.. */
 
	if (src == dst) return CommandCost();
 

	
 
	/* locate the head of the two chains */
 
	Vehicle *src_head = src->First();
 
	Vehicle *dst_head;
 
	Train *src_head = src->First();
 
	Train *dst_head;
 
	if (dst != NULL) {
 
		dst_head = dst->First();
 
		if (dst_head->tile != src_head->tile) return CMD_ERROR;
 
		/* Now deal with articulated part of destination wagon */
 
		dst = GetLastEnginePart(dst);
 
	} else {
 
		dst_head = NULL;
 
	}
 

	
 
	if (IsRearDualheaded(src)) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
 

	
 
	/* when moving all wagons, we can't have the same src_head and dst_head */
 
@@ -1096,25 +1099,25 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
		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 Vehicle *u;
 
				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);
 
				/* 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);
 
@@ -1142,50 +1145,50 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
			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 (Vehicle *v = dst_head; !src_in_dst && v != NULL; v = v->Next()) src_in_dst = v == src;
 
	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).
 
	 */
 
	if (dst_head != NULL && !src_in_dst && (flags & DC_AUTOREPLACE) == 0) {
 
		/*
 
		 * When performing the 'allow wagon attach' callback, we have to check
 
		 * that for each and every wagon, not only the first one. This means
 
		 * that we have to test one wagon, attach it to the train and then test
 
		 * the next wagon till we have reached the end. We have to restore it
 
		 * to the state it was before we 'tried' attaching the train when the
 
		 * attaching fails or succeeds because we are not 'only' doing this
 
		 * in the DC_EXEC state.
 
		 */
 
		Vehicle *dst_tail = dst_head;
 
		Train *dst_tail = dst_head;
 
		while (dst_tail->Next() != NULL) dst_tail = dst_tail->Next();
 

	
 
		Vehicle *orig_tail = dst_tail;
 
		Vehicle *next_to_attach = src;
 
		Vehicle *src_previous = src->Previous();
 
		Train *orig_tail = dst_tail;
 
		Train *next_to_attach = src;
 
		Train *src_previous = src->Previous();
 

	
 
		while (next_to_attach != NULL) {
 
			/* Don't check callback for articulated or rear dual headed parts */
 
			if (!IsArticulatedPart(next_to_attach) && !IsRearDualheaded(next_to_attach)) {
 
				/* Back up and clear the first_engine data to avoid using wagon override group */
 
				EngineID first_engine = next_to_attach->u.rail.first_engine;
 
				next_to_attach->u.rail.first_engine = INVALID_ENGINE;
 

	
 
				uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, next_to_attach, dst_head);
 

	
 
				/* Restore original first_engine data */
 
				next_to_attach->u.rail.first_engine = first_engine;
 
@@ -1215,25 +1218,25 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
				}
 
			}
 

	
 
			/* Only check further wagons if told to move the chain */
 
			if (!HasBit(p2, 0)) break;
 

	
 
			/*
 
			 * Adding a next wagon to the chain so we can test the other wagons.
 
			 * First 'take' the first wagon from 'next_to_attach' and move it
 
			 * to the next wagon. Then add that to the tail of the destination
 
			 * train and update the tail with the new vehicle.
 
			 */
 
			Vehicle *to_add = next_to_attach;
 
			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
 
@@ -1250,25 +1253,25 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
		if (IsFrontEngine(src) && !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) {
 
				Vehicle *v = 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);
 
@@ -1309,25 +1312,25 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
				RemoveVehicleFromGroup(src);
 
			}
 

	
 
			if (IsFrontEngine(src) || 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. */
 
			{
 
				Vehicle *v;
 
				Train *v;
 

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

	
 
		if (src->u.rail.other_multiheaded_part != NULL) {
 
			if (src->u.rail.other_multiheaded_part == src_head) {
 
				src_head = src_head->Next();
 
			}
 
			AddWagonToConsist(src->u.rail.other_multiheaded_part, src);
 
@@ -1382,32 +1385,33 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
 * @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;
 

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

	
 
	if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
 

	
 
	if (HASBITS(vt->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
 

	
 
	Train *v = (Train *)vt;
 
	while (IsArticulatedPart(v)) v = v->Previous();
 
	Vehicle *first = v->First();
 
	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)) {
 
			DeleteWindowById(WC_VEHICLE_VIEW, first->index);
 
			DeleteWindowById(WC_VEHICLE_ORDERS, first->index);
 
@@ -1417,39 +1421,39 @@ CommandCost CmdSellRailWagon(TileIndex t
 
		}
 
		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) */
 
			Vehicle *rear = (IsMultiheaded(v) &&
 
			Train *rear = (IsMultiheaded(v) &&
 
				IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
 

	
 
			if (rear != NULL) {
 
				cost.AddCost(-rear->value);
 
				if (flags & DC_EXEC) {
 
					UnlinkWagon(rear, first);
 
					delete rear;
 
				}
 
			}
 

	
 
			/* 2. We are selling the front vehicle, some special action might be required
 
			 * here, so take attention */
 
			if (v == first) {
 
				Vehicle *new_f = GetNextVehicle(first);
 
				Train *new_f = GetNextVehicle(first);
 

	
 
				/* 2.2 If there are wagons present after the deleted front engine, check
 
				 * if the second wagon (which will be first) is an engine. If it is one,
 
				 * promote it as a new train, retaining the unitnumber, orders */
 
				if (new_f != NULL && IsTrainEngine(new_f)) {
 
					if (IsTrainEngine(first)) {
 
						/* Let the new front engine take over the setup of the old engine */
 
						switch_engine = true;
 

	
 
						if (flags & DC_EXEC) {
 
							/* Make sure the group counts stay correct. */
 
							new_f->group_id        = first->group_id;
 
@@ -1491,31 +1495,31 @@ CommandCost CmdSellRailWagon(TileIndex t
 
					NormaliseTrainConsist(first);
 
					TrainConsistChanged(first, false);
 
					UpdateTrainGroupID(first);
 
					if (IsFrontEngine(first)) 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 (Vehicle *tmp; v != NULL; v = tmp) {
 
			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 */
 
						Vehicle *rear = v->u.rail.other_multiheaded_part;
 
						Train *rear = v->u.rail.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
 
							 * loop never sees the rear part. */
 
							if (tmp == rear) tmp = GetNextVehicle(tmp);
 

	
 
@@ -1563,44 +1567,44 @@ void Train::UpdateDeltaXY(Direction dire
 
		MKIT(7, 3, -3, -1),
 
	};
 
#undef MKIT
 

	
 
	uint32 x = _delta_xy_table[direction];
 
	this->x_offs        = GB(x,  0, 8);
 
	this->y_offs        = GB(x,  8, 8);
 
	this->x_extent      = GB(x, 16, 8);
 
	this->y_extent      = GB(x, 24, 8);
 
	this->z_extent      = 6;
 
}
 

	
 
static void UpdateVarsAfterSwap(Vehicle *v)
 
static void UpdateVarsAfterSwap(Train *v)
 
{
 
	v->UpdateDeltaXY(v->direction);
 
	v->cur_image = v->GetImage(v->direction);
 
	VehicleMove(v, true);
 
}
 

	
 
static inline void SetLastSpeed(Vehicle *v, int spd)
 
static inline void SetLastSpeed(Train *v, int spd)
 
{
 
	int old = v->u.rail.last_speed;
 
	if (spd != old) {
 
		v->u.rail.last_speed = spd;
 
		if (_settings_client.gui.vehicle_speed || (old == 0) != (spd == 0)) {
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		}
 
	}
 
}
 

	
 
/** Mark a train as stuck and stop it if it isn't stopped right now. */
 
static void MarkTrainAsStuck(Vehicle *v)
 
static void MarkTrainAsStuck(Train *v)
 
{
 
	if (!HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
 
		/* It is the first time the problem occured, set the "train stuck" flag. */
 
		SetBit(v->u.rail.flags, VRF_TRAIN_STUCK);
 
		v->load_unload_time_rem = 0;
 

	
 
		/* Stop train */
 
		v->cur_speed = 0;
 
		v->subspeed = 0;
 
		SetLastSpeed(v, 0);
 

	
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
@@ -1622,27 +1626,27 @@ static void SwapTrainFlags(uint16 *swap_
 
	if (HasBit(flag1, VRF_GOINGUP)) {
 
		SetBit(*swap_flag2, VRF_GOINGDOWN);
 
	} else if (HasBit(flag1, VRF_GOINGDOWN)) {
 
		SetBit(*swap_flag2, VRF_GOINGUP);
 
	}
 
	if (HasBit(flag2, VRF_GOINGUP)) {
 
		SetBit(*swap_flag1, VRF_GOINGDOWN);
 
	} else if (HasBit(flag2, VRF_GOINGDOWN)) {
 
		SetBit(*swap_flag1, VRF_GOINGUP);
 
	}
 
}
 

	
 
static void ReverseTrainSwapVeh(Vehicle *v, int l, int r)
 
static void ReverseTrainSwapVeh(Train *v, int l, int r)
 
{
 
	Vehicle *a, *b;
 
	Train *a, *b;
 

	
 
	/* locate vehicles to swap */
 
	for (a = v; l != 0; l--) a = a->Next();
 
	for (b = v; r != 0; r--) b = b->Next();
 

	
 
	if (a != b) {
 
		/* swap the hidden bits */
 
		{
 
			uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus&VS_HIDDEN);
 
			b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus&VS_HIDDEN);
 
			a->vehstatus = tmp;
 
		}
 
@@ -1695,25 +1699,25 @@ static Vehicle *TrainOnTileEnum(Vehicle 
 
 * 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(v) != tile) return NULL;
 
	if (TrainApproachingCrossingTile((Train *)v) != tile) return NULL;
 

	
 
	return v;
 
}
 

	
 

	
 
/**
 
 * 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)
 
@@ -1766,78 +1770,78 @@ static inline void MaybeBarCrossingWithS
 
		BarCrossing(tile);
 
		SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
 
		MarkTileDirtyByTile(tile);
 
	}
 
}
 

	
 

	
 
/**
 
 * Advances wagons for train reversing, needed for variable length wagons.
 
 * This one is called before the train is reversed.
 
 * @param v First vehicle in chain
 
 */
 
static void AdvanceWagonsBeforeSwap(Vehicle *v)
 
static void AdvanceWagonsBeforeSwap(Train *v)
 
{
 
	Vehicle *base = v;
 
	Vehicle *first = base;                    // first vehicle to move
 
	Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
 
	Train *base = v;
 
	Train *first = base; // first vehicle to move
 
	Train *last = (Train *)GetLastVehicleInChain(v); // last vehicle to move
 
	uint length = CountVehiclesInChain(v);
 

	
 
	while (length > 2) {
 
		last = last->Previous();
 
		first = first->Next();
 

	
 
		int differential = base->u.rail.cached_veh_length - last->u.rail.cached_veh_length;
 

	
 
		/* do not update images now
 
		 * negative differential will be handled in AdvanceWagonsAfterSwap() */
 
		for (int i = 0; i < differential; i++) TrainController(first, last->Next());
 

	
 
		base = first; // == base->Next()
 
		length -= 2;
 
	}
 
}
 

	
 

	
 
/**
 
 * Advances wagons for train reversing, needed for variable length wagons.
 
 * This one is called after the train is reversed.
 
 * @param v First vehicle in chain
 
 */
 
static void AdvanceWagonsAfterSwap(Vehicle *v)
 
static void AdvanceWagonsAfterSwap(Train *v)
 
{
 
	/* first of all, fix the situation when the train was entering a depot */
 
	Vehicle *dep = v; // last vehicle in front of just left depot
 
	Train *dep = v; // last vehicle in front of just left depot
 
	while (dep->Next() != NULL && (dep->u.rail.track == TRACK_BIT_DEPOT || dep->Next()->u.rail.track != TRACK_BIT_DEPOT)) {
 
		dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot
 
	}
 

	
 
	Vehicle *leave = dep->Next(); // first vehicle in a depot we are leaving now
 
	Train *leave = dep->Next(); // first vehicle in a depot we are leaving now
 

	
 
	if (leave != NULL) {
 
		/* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */
 
		int d = TicksToLeaveDepot(dep);
 

	
 
		if (d <= 0) {
 
			leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
 
			leave->u.rail.track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
 
			for (int i = 0; i >= d; i--) TrainController(leave, NULL); // maybe move it, and maybe let another wagon leave
 
		}
 
	} else {
 
		dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot
 
	}
 

	
 
	Vehicle *base = v;
 
	Vehicle *first = base;                    // first vehicle to move
 
	Vehicle *last = GetLastVehicleInChain(v); // last vehicle to move
 
	Train *base = v;
 
	Train *first = base; // first vehicle to move
 
	Train *last = (Train *)GetLastVehicleInChain(v); // last vehicle to move
 
	uint length = CountVehiclesInChain(v);
 

	
 
	/* we have to make sure all wagons that leave a depot because of train reversing are moved coorectly
 
	 * they have already correct spacing, so we have to make sure they are moved how they should */
 
	bool nomove = (dep == NULL); // if there is no vehicle leaving a depot, limit the number of wagons moved immediatelly
 

	
 
	while (length > 2) {
 
		/* we reached vehicle (originally) in front of a depot, stop now
 
		 * (we would move wagons that are alredy moved with new wagon length) */
 
		if (base == dep) break;
 

	
 
		/* the last wagon was that one leaving a depot, so do not move it anymore */
 
@@ -1848,25 +1852,25 @@ static void AdvanceWagonsAfterSwap(Vehic
 

	
 
		int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
 

	
 
		/* do not update images now */
 
		for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL));
 

	
 
		base = first; // == base->Next()
 
		length -= 2;
 
	}
 
}
 

	
 

	
 
static void ReverseTrainDirection(Vehicle *v)
 
static void ReverseTrainDirection(Train *v)
 
{
 
	if (IsRailDepotTile(v->tile)) {
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
	}
 

	
 
	/* Clear path reservation in front. */
 
	FreeTrainTrackReservation(v);
 

	
 
	/* Check if we were approaching a rail/road-crossing */
 
	TileIndex crossing = TrainApproachingCrossingTile(v);
 

	
 
	/* count number of vehicles */
 
@@ -1937,35 +1941,37 @@ static void ReverseTrainDirection(Vehicl
 
		v->load_unload_time_rem = 0;
 
	}
 
}
 

	
 
/** Reverse train.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 train to reverse
 
 * @param p2 if true, reverse a unit in a train (needs to be in a depot)
 
 */
 
CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Vehicle *v = Vehicle::GetIfValid(p1);
 
	if (v == NULL || v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
 
	Vehicle *vt = Vehicle::GetIfValid(p1);
 
	if (vt == NULL || vt->type != VEH_TRAIN || !CheckOwnership(vt->owner)) return CMD_ERROR;
 

	
 
	Train *v = (Train *)vt;
 

	
 
	if (p2 != 0) {
 
		/* turn a single unit around */
 

	
 
		if (IsMultiheaded(v) || HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_ARTIC_ENGINE)) {
 
			return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT);
 
		}
 

	
 
		Vehicle *front = v->First();
 
		Train *front = v->First();
 
		/* make sure the vehicle is stopped in the depot */
 
		if (CheckTrainStoppedInDepot(front) < 0) {
 
			return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			ToggleBit(v->u.rail.flags, VRF_REVERSE_DIRECTION);
 
			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
		}
 
	} else {
 
		/* turn the whole train around */
 
@@ -1998,47 +2004,49 @@ CommandCost CmdReverseTrainDirection(Til
 

	
 
/** Force a train through a red signal
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 train to ignore the red signal
 
 * @param p2 unused
 
 */
 
CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Vehicle *v = Vehicle::GetIfValid(p1);
 
	if (v == NULL || v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) v->u.rail.force_proceed = 0x50;
 
	if (flags & DC_EXEC) ((Train *)v)->u.rail.force_proceed = 0x50;
 

	
 
	return CommandCost();
 
}
 

	
 
/** Refits a train to the specified cargo type.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 vehicle ID of the train to refit
 
 * param p2 various bitstuffed elements
 
 * - p2 = (bit 0-7) - the new cargo type to refit to
 
 * - p2 = (bit 8-15) - the new cargo subtype to refit to
 
 * - p2 = (bit 16) - refit only this vehicle
 
 * @return cost of refit or error
 
 */
 
CommandCost CmdRefitRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	CargoID new_cid = GB(p2, 0, 8);
 
	byte new_subtype = GB(p2, 8, 8);
 
	bool only_this = HasBit(p2, 16);
 

	
 
	Vehicle *v = Vehicle::GetIfValid(p1);
 
	if (v == NULL || v->type != VEH_TRAIN || !CheckOwnership(v->owner)) return CMD_ERROR;
 
	Vehicle *vt = Vehicle::GetIfValid(p1);
 
	if (vt == NULL || vt->type != VEH_TRAIN || !CheckOwnership(vt->owner)) return CMD_ERROR;
 

	
 
	Train *v = (Train *)vt;
 
	if (CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
 
	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE);
 

	
 
	/* Check cargo */
 
	if (new_cid >= NUM_CARGO) return CMD_ERROR;
 

	
 
	CommandCost cost(EXPENSES_TRAIN_RUN);
 
	uint num = 0;
 

	
 
	do {
 
		/* XXX: We also refit all the attached wagons en-masse if they
 
		 * can be refitted. This is how TTDPatch does it.  TODO: Have
 
@@ -2094,25 +2102,25 @@ CommandCost CmdRefitRailVehicle(TileInde
 
				v->cargo_cap = amount;
 
				v->cargo_subtype = new_subtype;
 
				InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
				InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
				InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
			}
 
		}
 
	} while ((v = v->Next()) != NULL && !only_this);
 

	
 
	_returned_refit_capacity = num;
 

	
 
	/* Update the train's cached variables */
 
	if (flags & DC_EXEC) TrainConsistChanged(Vehicle::Get(p1)->First(), false);
 
	if (flags & DC_EXEC) TrainConsistChanged((Train *)Vehicle::Get(p1)->First(), false);
 

	
 
	return cost;
 
}
 

	
 
struct TrainFindDepotData {
 
	uint best_length;
 
	TileIndex tile;
 
	Owner owner;
 
	/**
 
	 * true if reversing is necessary for the train to get to this depot
 
	 * This value is unused when new depot finding and NPF are both disabled
 
	 */
 
@@ -2126,25 +2134,25 @@ static bool NtpCallbFindDepot(TileIndex 
 
			IsRailDepot(tile)) {
 
		/* approximate number of tiles by dividing by DIAG_FACTOR */
 
		tfdd->best_length = length / DIAG_FACTOR;
 
		tfdd->tile = tile;
 
		return true;
 
	}
 

	
 
	return false;
 
}
 

	
 
/** returns the tile of a depot to goto to. The given vehicle must not be
 
 * crashed! */
 
static TrainFindDepotData FindClosestTrainDepot(Vehicle *v, int max_distance)
 
static TrainFindDepotData FindClosestTrainDepot(Train *v, int max_distance)
 
{
 
	assert(!(v->vehstatus & VS_CRASHED));
 

	
 
	TrainFindDepotData tfdd;
 
	tfdd.owner = v->owner;
 
	tfdd.reverse = false;
 

	
 
	if (IsRailDepotTile(v->tile)) {
 
		tfdd.tile = v->tile;
 
		tfdd.best_length = 0;
 
		return tfdd;
 
	}
 
@@ -2238,33 +2246,33 @@ CommandCost CmdSendTrainToDepot(TileInde
 
}
 

	
 

	
 
void OnTick_Train()
 
{
 
	_age_cargo_skip_counter = (_age_cargo_skip_counter == 0) ? 184 : (_age_cargo_skip_counter - 1);
 
}
 

	
 
static const int8 _vehicle_smoke_pos[8] = {
 
	1, 1, 1, 0, -1, -1, -1, 0
 
};
 

	
 
static void HandleLocomotiveSmokeCloud(const Vehicle *v)
 
static void HandleLocomotiveSmokeCloud(const Train *v)
 
{
 
	bool sound = false;
 

	
 
	if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2) {
 
		return;
 
	}
 

	
 
	const Vehicle *u = v;
 
	const Train *u = v;
 

	
 
	do {
 
		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
 
		int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8;
 
		byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
 
		bool disable_effect = HasBit(v->u.rail.cached_vis_effect, 6);
 

	
 
		/* no smoke? */
 
		if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
 
				disable_effect ||
 
				v->vehstatus & VS_HIDDEN) {
 
			continue;
 
@@ -2332,25 +2340,25 @@ void Train::PlayLeaveStationSound() cons
 
		SND_0A_TRAIN_HORN,
 
		SND_47_MAGLEV_2,
 
		SND_41_MAGLEV
 
	};
 

	
 
	if (PlayVehicleSound(this, VSE_START)) return;
 

	
 
	EngineID engtype = this->engine_type;
 
	SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this);
 
}
 

	
 
/** Check if the train is on the last reserved tile and try to extend the path then. */
 
static void CheckNextTrainTile(Vehicle *v)
 
static void CheckNextTrainTile(Train *v)
 
{
 
	/* Don't do any look-ahead if path_backoff_interval is 255. */
 
	if (_settings_game.pf.path_backoff_interval == 255) return;
 

	
 
	/* Exit if we reached our destination depot or are inside a depot. */
 
	if ((v->tile == v->dest_tile && v->current_order.IsType(OT_GOTO_DEPOT)) || v->u.rail.track & TRACK_BIT_DEPOT) return;
 
	/* Exit if we are on a station tile and are going to stop. */
 
	if (IsRailwayStationTile(v->tile) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) return;
 
	/* Exit if the current order doesn't have a destination, but the train has orders. */
 
	if ((v->current_order.IsType(OT_NOTHING) || v->current_order.IsType(OT_LEAVESTATION) || v->current_order.IsType(OT_LOADING)) && v->GetNumOrders() > 0) return;
 

	
 
	Trackdir td = v->GetVehicleTrackdir();
 
@@ -2369,28 +2377,28 @@ static void CheckNextTrainTile(Vehicle *
 
			if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) {
 
				/* If the next tile is a PBS signal, try to make a reservation. */
 
				TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits);
 
				if (_settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg) {
 
					tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.m_old_td));
 
				}
 
				ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false);
 
			}
 
		}
 
	}
 
}
 

	
 
static bool CheckTrainStayInDepot(Vehicle *v)
 
static bool CheckTrainStayInDepot(Train *v)
 
{
 
	/* bail out if not all wagons are in the same depot or not in a depot at all */
 
	for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (const Train *u = v; u != NULL; u = u->Next()) {
 
		if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false;
 
	}
 

	
 
	/* if the train got no power, then keep it in the depot */
 
	if (v->u.rail.cached_power == 0) {
 
		v->vehstatus |= VS_STOPPED;
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		return true;
 
	}
 

	
 
	SigSegState seg_state;
 

	
 
@@ -2445,25 +2453,25 @@ static bool CheckTrainStayInDepot(Vehicl
 

	
 
	v->UpdateDeltaXY(v->direction);
 
	v->cur_image = v->GetImage(v->direction);
 
	VehicleMove(v, false);
 
	UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
 
	UpdateTrainAcceleration(v);
 
	InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 

	
 
	return false;
 
}
 

	
 
/** Clear the reservation of a tile that was just left by a wagon on track_dir. */
 
static void ClearPathReservation(const Vehicle *v, TileIndex tile, Trackdir track_dir)
 
static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
 
{
 
	DiagDirection dir = TrackdirToExitdir(track_dir);
 

	
 
	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
		/* Are we just leaving a tunnel/bridge? */
 
		if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
 
			TileIndex end = GetOtherTunnelBridgeEnd(tile);
 

	
 
			if (!HasVehicleOnTunnelBridge(tile, end, v)) {
 
				/* Free the reservation only if no other train is on the tiles. */
 
				SetTunnelBridgeReservation(tile, false);
 
				SetTunnelBridgeReservation(end, false);
 
@@ -2479,25 +2487,25 @@ static void ClearPathReservation(const V
 
		/* 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 Vehicle *v, TileIndex origin, Trackdir orig_td)
 
void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_td)
 
{
 
	assert(IsFrontEngine(v));
 

	
 
	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->u.rail.railtype)->compatible_railtypes);
 
@@ -2604,25 +2612,25 @@ static const byte _pick_track_table[6] =
 
/**
 
 * Perform pathfinding for a train.
 
 *
 
 * @param v The train
 
 * @param tile The tile the train is about to enter
 
 * @param enterdir Diagonal direction the train is coming from
 
 * @param tracks Usable tracks on the new tile
 
 * @param path_not_found [out] Set to false if the pathfinder couldn't find a way to the destination
 
 * @param do_track_reservation Path reservation is requested
 
 * @param dest [out] State and destination of the requested path
 
 * @return The best track the train should follow
 
 */
 
static Track DoTrainPathfind(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool do_track_reservation, PBSTileInfo *dest)
 
static Track DoTrainPathfind(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool do_track_reservation, PBSTileInfo *dest)
 
{
 
	Track best_track;
 

	
 
#ifdef PF_BENCHMARK
 
	TIC()
 
#endif
 

	
 
	if (path_not_found) *path_not_found = false;
 

	
 
	uint8 pathfinder = _settings_game.pf.pathfinder_for_trains;
 
	if (do_track_reservation && pathfinder == VPF_NTP) pathfinder = VPF_NPF;
 

	
 
@@ -2705,25 +2713,25 @@ static Track DoTrainPathfind(Vehicle *v,
 
#ifdef PF_BENCHMARK
 
	TOC("PF time = ", 1)
 
#endif
 

	
 
	return best_track;
 
}
 

	
 
/**
 
 * Extend a train path as far as possible. Stops on encountering a safe tile,
 
 * another reservation or a track choice.
 
 * @return INVALID_TILE indicates that the reservation failed.
 
 */
 
static PBSTileInfo ExtendTrainReservation(const Vehicle *v, TrackBits *new_tracks, DiagDirection *enterdir)
 
static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir)
 
{
 
	bool no_90deg_turns = _settings_game.pf.pathfinder_for_trains != VPF_NTP && _settings_game.pf.forbid_90_deg;
 
	PBSTileInfo origin = FollowTrainReservation(v);
 

	
 
	CFollowTrackRail ft(v);
 

	
 
	TileIndex tile = origin.tile;
 
	Trackdir  cur_td = origin.trackdir;
 
	while (ft.Follow(tile, cur_td)) {
 
		if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
 
			/* Possible signal tile. */
 
			if (HasOnewaySignalBlockingTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) break;
 
@@ -2798,25 +2806,25 @@ static PBSTileInfo ExtendTrainReservatio
 
}
 

	
 
/**
 
 * Try to reserve any path to a safe tile, ignoring the vehicle's destination.
 
 * Safe tiles are tiles in front of a signal, depots and station tiles at end of line.
 
 *
 
 * @param v The vehicle.
 
 * @param tile The tile the search should start from.
 
 * @param td The trackdir the search should start from.
 
 * @param override_tailtype Whether all physically compatible railtypes should be followed.
 
 * @return True if a path to a safe stopping tile could be reserved.
 
 */
 
static bool TryReserveSafeTrack(const Vehicle *v, TileIndex tile, Trackdir td, bool override_tailtype)
 
static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_tailtype)
 
{
 
	if (_settings_game.pf.pathfinder_for_trains == VPF_YAPF) {
 
		return YapfRailFindNearestSafeTile(v, tile, td, override_tailtype);
 
	} else {
 
		return NPFRouteToSafeTile(v, tile, td, override_tailtype).res_okay;
 
	}
 
}
 

	
 
/** This class will save the current order of a vehicle and restore it on destruction. */
 
class VehicleOrderSaver
 
{
 
private:
 
@@ -2887,25 +2895,25 @@ public:
 
					break;
 
			}
 
			/* Don't increment inside the while because otherwise conditional
 
			 * orders can lead to an infinite loop. */
 
			++this->index;
 
		} while (this->index != this->v->cur_order_index);
 

	
 
		return false;
 
	}
 
};
 

	
 
/* choose a track */
 
static Track ChooseTrainTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
 
static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck)
 
{
 
	Track best_track = INVALID_TRACK;
 
	bool do_track_reservation = _settings_game.pf.reserve_paths || force_res;
 
	bool changed_signal = false;
 

	
 
	assert((tracks & ~TRACK_BIT_MASK) == 0);
 

	
 
	if (got_reservation != NULL) *got_reservation = false;
 

	
 
	/* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */
 
	TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir));
 
	/* Do we have a suitable reserved track? */
 
@@ -3066,25 +3074,25 @@ static Track ChooseTrainTrack(Vehicle *v
 

	
 
	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(Vehicle *v, bool mark_as_stuck, bool first_tile_okay)
 
bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
 
{
 
	assert(v->type == VEH_TRAIN && IsFrontEngine(v));
 

	
 
	/* 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->u.rail.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. */
 
@@ -3146,25 +3154,25 @@ bool TryPathReserve(Vehicle *v, bool mar
 
		return false;
 
	}
 

	
 
	if (HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
 
		v->load_unload_time_rem = 0;
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 
	ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
 
	return true;
 
}
 

	
 

	
 
static bool CheckReverseTrain(Vehicle *v)
 
static bool CheckReverseTrain(Train *v)
 
{
 
	if (_settings_game.difficulty.line_reverse_mode != 0 ||
 
			v->u.rail.track == TRACK_BIT_DEPOT || v->u.rail.track == TRACK_BIT_WORMHOLE ||
 
			!(v->direction & 1)) {
 
		return false;
 
	}
 

	
 
	uint reverse_best = 0;
 

	
 
	assert(v->u.rail.track);
 

	
 
	switch (_settings_game.pf.pathfinder_for_trains) {
 
@@ -3286,25 +3294,25 @@ void Train::MarkDirty()
 
}
 

	
 
/**
 
 * This function looks at the vehicle and updates it's speed (cur_speed
 
 * and subspeed) variables. Furthermore, it returns the distance that
 
 * the train can drive this tick. This distance is expressed as 256 * n,
 
 * where n is the number of straight (long) tracks the train can
 
 * traverse. This means that moving along a straight track costs 256
 
 * "speed" and a diagonal track costs 192 "speed".
 
 * @param v The vehicle to update the speed of.
 
 * @return distance to drive.
 
 */
 
static int UpdateTrainSpeed(Vehicle *v)
 
static int UpdateTrainSpeed(Train *v)
 
{
 
	uint accel;
 

	
 
	if (v->vehstatus & VS_STOPPED || HasBit(v->u.rail.flags, VRF_REVERSING) || HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
 
		switch (_settings_game.vehicle.train_acceleration_model) {
 
			default: NOT_REACHED();
 
			case TAM_ORIGINAL:  accel = v->acceleration * -4; break;
 
			case TAM_REALISTIC: accel = GetTrainAcceleration(v, AM_BRAKE); break;
 
		}
 
	} else {
 
		switch (_settings_game.vehicle.train_acceleration_model) {
 
			default: NOT_REACHED();
 
@@ -3331,48 +3339,48 @@ static int UpdateTrainSpeed(Vehicle *v)
 
	 *
 
	 * The scaling is done in this direction and not by multiplying the amount
 
	 * to be subtracted by 4/3 so that the leftover speed can be saved in a
 
	 * byte in v->progress.
 
	 */
 
	int scaled_spd = spd * 3 >> 2;
 

	
 
	scaled_spd += v->progress;
 
	v->progress = 0; // set later in TrainLocoHandler or TrainController
 
	return scaled_spd;
 
}
 

	
 
static void TrainEnterStation(Vehicle *v, StationID station)
 
static void TrainEnterStation(Train *v, StationID station)
 
{
 
	v->last_station_visited = station;
 

	
 
	/* check if a train ever visited this station before */
 
	Station *st = Station::Get(station);
 
	if (!(st->had_vehicle_of_type & HVOT_TRAIN)) {
 
		st->had_vehicle_of_type |= HVOT_TRAIN;
 
		SetDParam(0, st->index);
 
		AddNewsItem(
 
			STR_NEWS_FIRST_TRAIN_ARRIVAL,
 
			v->owner == _local_company ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
 
			v->index,
 
			st->index
 
		);
 
		AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
 
	}
 

	
 
	v->BeginLoading();
 

	
 
	StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES);
 
}
 

	
 
static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
 
static byte AfterSetTrainPos(Train *v, bool new_tile)
 
{
 
	byte old_z = v->z_pos;
 
	v->z_pos = GetSlopeZ(v->x_pos, v->y_pos);
 

	
 
	if (new_tile) {
 
		ClrBit(v->u.rail.flags, VRF_GOINGUP);
 
		ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
 

	
 
		if (v->u.rail.track == TRACK_BIT_X || v->u.rail.track == TRACK_BIT_Y) {
 
			/* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped.
 
			 * To check whether the current tile is sloped, and in which
 
			 * direction it is sloped, we get the 'z' at the center of
 
@@ -3387,61 +3395,61 @@ static byte AfterSetTrainPos(Vehicle *v,
 
			 * But they are not sloped... */
 
			if (middle_z != v->z_pos && !IsTunnelTile(TileVirtXY(v->x_pos, v->y_pos))) {
 
				SetBit(v->u.rail.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 Vehicle *v, TileIndex tile)
 
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
 
{
 
	return
 
		IsTileOwner(tile, v->owner) && (
 
			!IsFrontEngine(v) ||
 
			HasBit(v->u.rail.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 turn */
 
static inline void AffectSpeedByDirChange(Vehicle *v, Direction new_dir)
 
static inline void AffectSpeedByDirChange(Train *v, Direction new_dir)
 
{
 
	if (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL) return;
 

	
 
	DirDiff diff = DirDifference(v->direction, new_dir);
 
	if (diff == DIRDIFF_SAME) return;
 

	
 
	const RailtypeSlowdownParams *rsp = &_railtype_slowdown[v->u.rail.railtype];
 
	v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
 
}
 

	
 
/** Modify the speed of the vehicle due to a change in altitude */
 
static inline void AffectSpeedByZChange(Vehicle *v, byte old_z)
 
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->u.rail.railtype];
 

	
 
	if (old_z < v->z_pos) {
 
		v->cur_speed -= (v->cur_speed * rsp->z_up >> 8);
 
	} else {
 
		uint16 spd = v->cur_speed + rsp->z_down;
 
		if (spd <= v->max_speed) v->cur_speed = spd;
 
	}
 
}
 
@@ -3452,34 +3460,34 @@ static bool TrainMovedChangeSignals(Tile
 
			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(Vehicle *v)
 
static void SetVehicleCrashed(Train *v)
 
{
 
	if (v->u.rail.crash_anim_pos != 0) return;
 

	
 
	/* Free a possible path reservation and try to mark all tiles occupied by the train reserved. */
 
	if (IsFrontEngine(v)) {
 
		/* Remove all reservations, also the ones currently under the train
 
		 * and any railway station paltform reservation. */
 
		FreeTrainTrackReservation(v);
 
		for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
		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);
 

	
 
@@ -3494,42 +3502,42 @@ static void SetVehicleCrashed(Vehicle *v
 

	
 
	InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 

	
 
	for (; v != NULL; v = v->Next()) {
 
		v->vehstatus |= VS_CRASHED;
 
		MarkSingleVehicleDirty(v);
 
	}
 

	
 
	/* must be updated after the train has been marked crashed */
 
	if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
 
}
 

	
 
static uint CountPassengersInTrain(const Vehicle *v)
 
static uint CountPassengersInTrain(const Train *v)
 
{
 
	uint num = 0;
 

	
 
	for (; v != NULL; v = v->Next()) {
 
		if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
 
	}
 

	
 
	return num;
 
}
 

	
 
/**
 
 * Marks train as crashed and creates an AI event.
 
 * Doesn't do anything if the train is crashed already.
 
 * @param v first vehicle of chain
 
 * @return number of victims (including 2 drivers; zero if train was already crashed)
 
 */
 
static uint TrainCrashed(Vehicle *v)
 
static uint TrainCrashed(Train *v)
 
{
 
	/* do not crash train twice */
 
	if (v->vehstatus & VS_CRASHED) return 0;
 

	
 
	/* two drivers + passengers */
 
	uint num = 2 + CountPassengersInTrain(v);
 

	
 
	SetVehicleCrashed(v);
 
	AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_TRAIN));
 

	
 
	return num;
 
}
 
@@ -3540,60 +3548,60 @@ struct TrainCollideChecker {
 
};
 

	
 
static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
 
{
 
	TrainCollideChecker *tcc = (TrainCollideChecker*)data;
 

	
 
	if (v->type != VEH_TRAIN) return NULL;
 

	
 
	/* get first vehicle now to make most usual checks faster */
 
	Vehicle *coll = v->First();
 

	
 
	/* can't collide with own wagons && can't crash in depot && the same height level */
 
	if (coll != tcc->v && v->u.rail.track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) {
 
	if (coll != tcc->v && ((Train *)v)->u.rail.track != TRACK_BIT_DEPOT && abs(v->z_pos - tcc->v->z_pos) < 6) {
 
		int x_diff = v->x_pos - tcc->v->x_pos;
 
		int y_diff = v->y_pos - tcc->v->y_pos;
 

	
 
		/* needed to disable possible crash of competitor train in station by building diagonal track at its end */
 
		if (x_diff * x_diff + y_diff * y_diff > 25) return NULL;
 

	
 
		/* crash both trains */
 
		tcc->num += TrainCrashed(tcc->v);
 
		tcc->num += TrainCrashed(coll);
 
		tcc->num += TrainCrashed((Train *)tcc->v);
 
		tcc->num += TrainCrashed((Train *)coll);
 

	
 
		/* Try to reserve all tiles directly under the crashed trains.
 
		 * As there might be more than two trains involved, we have to do that for all vehicles */
 
		const Vehicle *u;
 
		FOR_ALL_VEHICLES(u) {
 
			if (u->type == VEH_TRAIN && HASBITS(u->vehstatus, VS_CRASHED) && (u->u.rail.track & TRACK_BIT_DEPOT) == TRACK_BIT_NONE) {
 
				TrackBits trackbits = u->u.rail.track;
 
			if (u->type == VEH_TRAIN && HASBITS(u->vehstatus, VS_CRASHED) && (((Train *)u)->u.rail.track & TRACK_BIT_DEPOT) == TRACK_BIT_NONE) {
 
				TrackBits trackbits = ((Train *)u)->u.rail.track;
 
				if ((trackbits & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
 
					/* Vehicle is inside a wormhole, v->u.rail.track contains no useful value then. */
 
					trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(u->tile));
 
				}
 
				TryReserveRailTrack(u->tile, TrackBitsToTrack(trackbits));
 
			}
 
		}
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/**
 
 * Checks whether the specified train has a collision with another vehicle. If
 
 * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front.
 
 * Reports the incident in a flashy news item, modifies station ratings and
 
 * plays a sound.
 
 */
 
static bool CheckTrainCollision(Vehicle *v)
 
static bool CheckTrainCollision(Train *v)
 
{
 
	/* can't collide in depot */
 
	if (v->u.rail.track == TRACK_BIT_DEPOT) return false;
 

	
 
	assert(v->u.rail.track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
 

	
 
	TrainCollideChecker tcc;
 
	tcc.v = v;
 
	tcc.num = 0;
 

	
 
	/* find colliding vehicles */
 
	if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
 
@@ -3614,34 +3622,34 @@ static bool CheckTrainCollision(Vehicle 
 
	);
 

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

	
 
static Vehicle *CheckVehicleAtSignal(Vehicle *v, void *data)
 
{
 
	DiagDirection exitdir = *(DiagDirection *)data;
 

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

	
 
	return NULL;
 
}
 

	
 
static void TrainController(Vehicle *v, Vehicle *nomove)
 
static void TrainController(Train *v, Vehicle *nomove)
 
{
 
	Vehicle *prev;
 
	Train *prev;
 

	
 
	/* 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->u.rail.track != TRACK_BIT_WORMHOLE) {
 
			/* Not inside tunnel */
 
			if (gp.old_tile == gp.new_tile) {
 
				/* Staying in the old tile */
 
				if (v->u.rail.track == TRACK_BIT_DEPOT) {
 
@@ -3913,50 +3921,50 @@ reverse_train_direction:
 
}
 

	
 
/** 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)
 
{
 
	TrackBits *trackbits = (TrackBits *)data;
 

	
 
	if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
 
		if ((v->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
 
		if ((((Train *)v)->u.rail.track & TRACK_BIT_WORMHOLE) == TRACK_BIT_WORMHOLE) {
 
			/* Vehicle is inside a wormhole, v->u.rail.track contains no useful value then. */
 
			*trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile));
 
		} else {
 
			*trackbits |= v->u.rail.track;
 
			*trackbits |= ((Train *)v)->u.rail.track;
 
		}
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/**
 
 * Deletes/Clears the last wagon of a crashed train. It takes the engine of the
 
 * train, then goes to the last wagon and deletes that. Each call to this function
 
 * will remove the last wagon of a crashed train. If this wagon was on a crossing,
 
 * or inside a tunnel/bridge, recalculate the signals as they might need updating
 
 * @param v the Vehicle of which last wagon is to be removed
 
 */
 
static void DeleteLastWagon(Vehicle *v)
 
static void DeleteLastWagon(Train *v)
 
{
 
	Vehicle *first = v->First();
 
	Train *first = v->First();
 

	
 
	/* Go to the last wagon and delete the link pointing there
 
	 * *u is then the one-before-last wagon, and *v the last
 
	 * one which will physicially be removed */
 
	Vehicle *u = v;
 
	Train *u = v;
 
	for (; v->Next() != NULL; v = v->Next()) u = v;
 
	u->SetNext(NULL);
 

	
 
	if (first != v) {
 
		/* Recalculate cached train properties */
 
		TrainConsistChanged(first, false);
 
		/* Update the depot window if the first vehicle is in depot -
 
		 * if v == first, then it is updated in PreDestructor() */
 
		if (first->u.rail.track == TRACK_BIT_DEPOT) {
 
			InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
 
		}
 
	}
 
@@ -3993,45 +4001,45 @@ static void DeleteLastWagon(Vehicle *v)
 

	
 
	/* check if the wagon was on a road/rail-crossing */
 
	if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
 

	
 
	/* Update signals */
 
	if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
 
		UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
 
	} else {
 
		SetSignalsOnBothDir(tile, track, owner);
 
	}
 
}
 

	
 
static void ChangeTrainDirRandomly(Vehicle *v)
 
static void ChangeTrainDirRandomly(Train *v)
 
{
 
	static const DirDiff delta[] = {
 
		DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
 
	};
 

	
 
	do {
 
		/* We don't need to twist around vehicles if they're not visible */
 
		if (!(v->vehstatus & VS_HIDDEN)) {
 
			v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
 
			v->UpdateDeltaXY(v->direction);
 
			v->cur_image = v->GetImage(v->direction);
 
			/* Refrain from updating the z position of the vehicle when on
 
			 * a bridge, because AfterSetTrainPos will put the vehicle under
 
			 * the bridge in that case */
 
			if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false);
 
		}
 
	} while ((v = v->Next()) != NULL);
 
}
 

	
 
static bool HandleCrashedTrain(Vehicle *v)
 
static bool HandleCrashedTrain(Train *v)
 
{
 
	int state = ++v->u.rail.crash_anim_pos;
 

	
 
	if (state == 4 && !(v->vehstatus & VS_HIDDEN)) {
 
		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
 
	}
 

	
 
	uint32 r;
 
	if (state <= 200 && Chance16R(1, 7, r)) {
 
		int index = (r * 10 >> 16);
 

	
 
		Vehicle *u = v;
 
@@ -4052,25 +4060,25 @@ static bool HandleCrashedTrain(Vehicle *
 
	if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v);
 

	
 
	if (state >= 4440 && !(v->tick_counter & 0x1F)) {
 
		bool ret = v->Next() != NULL;
 
		DeleteLastWagon(v);
 
		InvalidateWindow(WC_REPLACE_VEHICLE, (v->group_id << 16) | VEH_TRAIN);
 
		return ret;
 
	}
 

	
 
	return true;
 
}
 

	
 
static void HandleBrokenTrain(Vehicle *v)
 
static void HandleBrokenTrain(Train *v)
 
{
 
	if (v->breakdown_ctr != 1) {
 
		v->breakdown_ctr = 1;
 
		v->cur_speed = 0;
 

	
 
		if (v->breakdowns_since_last_service != 255)
 
			v->breakdowns_since_last_service++;
 

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

	
 
		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
 
@@ -4096,25 +4104,25 @@ static void HandleBrokenTrain(Vehicle *v
 
static const uint16 _breakdown_speeds[16] = {
 
	225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15
 
};
 

	
 

	
 
/**
 
 * Train is approaching line end, slow down and possibly reverse
 
 *
 
 * @param v front train engine
 
 * @param signal not line end, just a red signal
 
 * @return true iff we did NOT have to reverse
 
 */
 
static bool TrainApproachingLineEnd(Vehicle *v, bool signal)
 
static bool TrainApproachingLineEnd(Train *v, bool signal)
 
{
 
	/* Calc position within the current tile */
 
	uint x = v->x_pos & 0xF;
 
	uint y = v->y_pos & 0xF;
 

	
 
	/* for diagonal directions, 'x' will be 0..15 -
 
	 * for other directions, it will be 1, 3, 5, ..., 15 */
 
	switch (v->direction) {
 
		case DIR_N : x = ~x + ~y + 25; break;
 
		case DIR_NW: x = y;            // FALLTHROUGH
 
		case DIR_NE: x = ~x + 16;      break;
 
		case DIR_E : x = ~x + y + 9;   break;
 
@@ -4137,25 +4145,25 @@ static bool TrainApproachingLineEnd(Vehi
 
	uint16 break_speed = _breakdown_speeds[x & 0xF];
 
	if (break_speed < v->cur_speed) v->cur_speed = break_speed;
 

	
 
	return true;
 
}
 

	
 

	
 
/**
 
 * Determines whether train would like to leave the tile
 
 * @param v train to test
 
 * @return true iff vehicle is NOT entering or inside a depot or tunnel/bridge
 
 */
 
static bool TrainCanLeaveTile(const Vehicle *v)
 
static bool TrainCanLeaveTile(const Train *v)
 
{
 
	/* Exit if inside a tunnel/bridge or a depot */
 
	if (v->u.rail.track == TRACK_BIT_WORMHOLE || v->u.rail.track == TRACK_BIT_DEPOT) return false;
 

	
 
	TileIndex tile = v->tile;
 

	
 
	/* entering a tunnel/bridge? */
 
	if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
		DiagDirection dir = GetTunnelBridgeDirection(tile);
 
		if (DiagDirToDir(dir) == v->direction) return false;
 
	}
 

	
 
@@ -4167,25 +4175,25 @@ static bool TrainCanLeaveTile(const Vehi
 

	
 
	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 Vehicle *v)
 
static TileIndex TrainApproachingCrossingTile(const Train *v)
 
{
 
	assert(IsFrontEngine(v));
 
	assert(!(v->vehstatus & VS_CRASHED));
 

	
 
	if (!TrainCanLeaveTile(v)) return INVALID_TILE;
 

	
 
	DiagDirection dir = TrainExitDir(v->direction, v->u.rail.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)) {
 
@@ -4193,25 +4201,25 @@ static TileIndex TrainApproachingCrossin
 
	}
 

	
 
	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(Vehicle *v)
 
static bool TrainCheckIfLineEnds(Train *v)
 
{
 
	/* First, handle broken down train */
 

	
 
	int t = v->breakdown_ctr;
 
	if (t > 1) {
 
		v->vehstatus |= VS_TRAIN_SLOWING;
 

	
 
		uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)];
 
		if (break_speed < v->cur_speed) v->cur_speed = break_speed;
 
	} else {
 
		v->vehstatus &= ~VS_TRAIN_SLOWING;
 
	}
 
@@ -4244,25 +4252,25 @@ static bool TrainCheckIfLineEnds(Vehicle
 
	}
 

	
 
	/* approaching red signal */
 
	if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true);
 

	
 
	/* approaching a rail/road crossing? then make it red */
 
	if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile);
 

	
 
	return true;
 
}
 

	
 

	
 
static bool TrainLocoHandler(Vehicle *v, bool mode)
 
static bool TrainLocoHandler(Train *v, bool mode)
 
{
 
	/* train has crashed? */
 
	if (v->vehstatus & VS_CRASHED) {
 
		return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here
 
	}
 

	
 
	if (v->u.rail.force_proceed != 0) {
 
		v->u.rail.force_proceed--;
 
		ClrBit(v->u.rail.flags, VRF_TRAIN_STUCK);
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 

	
 
@@ -4372,43 +4380,43 @@ static bool TrainLocoHandler(Vehicle *v,
 
			if ((order_type == OT_GOTO_WAYPOINT &&
 
						v->dest_tile == v->tile) ||
 
					(order_type == OT_GOTO_STATION &&
 
						(v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
 
						IsTileType(v->tile, MP_STATION) &&
 
						v->current_order.GetDestination() == GetStationIndex(v->tile))) {
 
				ProcessOrders(v);
 
			}
 
		}
 
		SetLastSpeed(v, v->cur_speed);
 
	}
 

	
 
	for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
	for (Train *u = v; u != NULL; u = u->Next()) {
 
		if ((u->vehstatus & VS_HIDDEN) != 0) continue;
 

	
 
		uint16 old_image = u->cur_image;
 
		u->cur_image = u->GetImage(u->direction);
 
		if (old_image != u->cur_image) VehicleMove(u, true);
 
	}
 

	
 
	if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress
 

	
 
	return true;
 
}
 

	
 

	
 

	
 
Money Train::GetRunningCost() const
 
{
 
	Money cost = 0;
 
	const Vehicle *v = this;
 
	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);
 
@@ -4439,25 +4447,25 @@ bool Train::Tick()
 
		return TrainLocoHandler(this, true);
 
	} else if (IsFreeWagon(this) && HASBITS(this->vehstatus, VS_CRASHED)) {
 
		/* Delete flooded standalone wagon chain */
 
		if (++this->u.rail.crash_anim_pos >= 4400) {
 
			delete this;
 
			return false;
 
		}
 
	}
 

	
 
	return true;
 
}
 

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

	
 
	if (_settings_game.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
 
	if (v->IsInDepot()) {
 
		VehicleServiceInDepot(v);
 
		return;
 
	}
 

	
 
	TrainFindDepotData tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
 
	/* Only go to the depot if it is not too far out of our way. */
 
	if (tfdd.best_length == UINT_MAX || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
src/train_gui.cpp
Show inline comments
 
@@ -19,25 +19,25 @@
 
#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 Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_TRAIN && IsFrontEngine(v) &&
 
				v->tile == tile &&
 
				v->u.rail.track == TRACK_BIT_DEPOT) {
 
				((Train *)v)->u.rail.track == TRACK_BIT_DEPOT) {
 
			if (found != NULL) return; // must be exactly one.
 
			found = v;
 
		}
 
	}
 

	
 
	/* 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);
 
	}
src/tunnelbridge_cmd.cpp
Show inline comments
 
@@ -638,25 +638,25 @@ static CommandCost DoClearTunnel(TileInd
 
	 * you have a "Poor" (0) town rating */
 
	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
 
		ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
 
			/* We first need to request values before calling DoClearSquare */
 
			DiagDirection dir = GetTunnelBridgeDirection(tile);
 
			Track track = DiagDirToDiagTrack(dir);
 
			Owner owner = GetTileOwner(tile);
 

	
 
			Vehicle *v = NULL;
 
			Train *v = NULL;
 
			if (GetTunnelBridgeReservation(tile)) {
 
				v = GetTrainForReservation(tile, track);
 
				if (v != NULL) FreeTrainTrackReservation(v);
 
			}
 

	
 
			DoClearSquare(tile);
 
			DoClearSquare(endtile);
 

	
 
			/* cannot use INVALID_DIAGDIR for signal update because the tunnel doesn't exist anymore */
 
			AddSideToSignalBuffer(tile,    ReverseDiagDir(dir), owner);
 
			AddSideToSignalBuffer(endtile, dir,                 owner);
 

	
 
@@ -702,25 +702,25 @@ static CommandCost DoClearBridge(TileInd
 

	
 
	/* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until
 
	 * you have a "Poor" (0) town rating */
 
	if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) {
 
		ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		/* read this value before actual removal of bridge */
 
		bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
 
		Owner owner = GetTileOwner(tile);
 
		uint height = GetBridgeHeight(tile);
 
		Vehicle *v = NULL;
 
		Train *v = NULL;
 

	
 
		if (rail && GetTunnelBridgeReservation(tile)) {
 
			v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction));
 
			if (v != NULL) FreeTrainTrackReservation(v);
 
		}
 

	
 
		DoClearSquare(tile);
 
		DoClearSquare(endtile);
 
		for (TileIndex c = tile + delta; c != endtile; c += delta) {
 
			/* do not let trees appear from 'nowhere' after removing bridge */
 
			if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) {
 
				uint minz = GetTileMaxZ(c) + 3 * TILE_HEIGHT;
 
@@ -1376,49 +1376,50 @@ static const byte _tunnel_fractcoord_7[4
 
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 *)v;
 
			fc = (x & 0xF) + (y << 4);
 

	
 
			vdir = DirToDiagDir(v->direction);
 
			vdir = DirToDiagDir(t->direction);
 

	
 
			if (v->u.rail.track != TRACK_BIT_WORMHOLE && dir == vdir) {
 
				if (IsFrontEngine(v) && fc == _tunnel_fractcoord_1[dir]) {
 
					if (!PlayVehicleSound(v, VSE_TUNNEL) && RailVehInfo(v->engine_type)->engclass == 0) {
 
			if (t->u.rail.track != TRACK_BIT_WORMHOLE && dir == vdir) {
 
				if (IsFrontEngine(t) && 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]) {
 
					v->tile = tile;
 
					v->u.rail.track = TRACK_BIT_WORMHOLE;
 
					v->vehstatus |= VS_HIDDEN;
 
					t->tile = tile;
 
					t->u.rail.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 ?? */
 
				v->tile = tile;
 
				v->u.rail.track = (TrackBits)_exit_tunnel_track[dir];
 
				assert(v->u.rail.track);
 
				v->vehstatus &= ~VS_HIDDEN;
 
				t->tile = tile;
 
				t->u.rail.track = (TrackBits)_exit_tunnel_track[dir];
 
				assert(t->u.rail.track);
 
				t->vehstatus &= ~VS_HIDDEN;
 
				return VETSB_ENTERED_WORMHOLE;
 
			}
 
		} else if (v->type == VEH_ROAD) {
 
			RoadVehicle *rv = (RoadVehicle *)v;
 
			fc = (x & 0xF) + (y << 4);
 
			vdir = DirToDiagDir(v->direction);
 

	
 
			/* Enter tunnel? */
 
			if (rv->state != RVSB_WORMHOLE && dir == vdir) {
 
				if (fc == _tunnel_fractcoord_4[dir] ||
 
						fc == _tunnel_fractcoord_5[dir]) {
 
					rv->tile = tile;
 
@@ -1453,50 +1454,52 @@ static VehicleEnterTileStatus VehicleEnt
 
			if (v->cur_speed > spd) v->cur_speed = spd;
 
		}
 

	
 
		if (DirToDiagDir(v->direction) == dir) {
 
			switch (dir) {
 
				default: NOT_REACHED();
 
				case DIAGDIR_NE: if ((x & 0xF) != 0)             return VETSB_CONTINUE; break;
 
				case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
 
				case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
 
				case DIAGDIR_NW: if ((y & 0xF) != 0)             return VETSB_CONTINUE; break;
 
			}
 
			switch (v->type) {
 
				case VEH_TRAIN:
 
					v->u.rail.track = TRACK_BIT_WORMHOLE;
 
					ClrBit(v->u.rail.flags, VRF_GOINGUP);
 
					ClrBit(v->u.rail.flags, VRF_GOINGDOWN);
 
					break;
 
				case VEH_TRAIN: {
 
					Train *t = (Train *)v;
 
					t->u.rail.track = TRACK_BIT_WORMHOLE;
 
					ClrBit(t->u.rail.flags, VRF_GOINGUP);
 
					ClrBit(t->u.rail.flags, VRF_GOINGDOWN);
 
				} break;
 

	
 
				case VEH_ROAD:
 
					((RoadVehicle *)v)->state = RVSB_WORMHOLE;
 
					break;
 

	
 
				case VEH_SHIP:
 
					((Ship *)v)->state = TRACK_BIT_WORMHOLE;
 
					break;
 

	
 
				default: NOT_REACHED();
 
			}
 
			return VETSB_ENTERED_WORMHOLE;
 
		} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
 
			v->tile = tile;
 
			switch (v->type) {
 
				case VEH_TRAIN:
 
					if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
 
						v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
 
				case VEH_TRAIN: {
 
					Train *t = (Train *)v;
 
					if (t->u.rail.track == TRACK_BIT_WORMHOLE) {
 
						t->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
 
						return VETSB_ENTERED_WORMHOLE;
 
					}
 
					break;
 
				} break;
 

	
 
				case VEH_ROAD: {
 
					RoadVehicle *rv = (RoadVehicle *)v;
 
					if (rv->state == RVSB_WORMHOLE) {
 
						rv->state = _road_exit_tunnel_state[dir];
 
						rv->frame = 0;
 
						return VETSB_ENTERED_WORMHOLE;
 
					}
 
				} break;
 

	
 
				case VEH_SHIP: {
 
					Ship *ship = (Ship *)v;
src/vehicle.cpp
Show inline comments
 
@@ -973,26 +973,26 @@ uint8 CalcPercentVehicleFilled(const Veh
 
void VehicleEnterDepot(Vehicle *v)
 
{
 
	switch (v->type) {
 
		case VEH_TRAIN:
 
			InvalidateWindowClasses(WC_TRAINS_LIST);
 
			/* Clear path reservation */
 
			SetDepotWaypointReservation(v->tile, false);
 
			if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile);
 

	
 
			if (!IsFrontEngine(v)) v = v->First();
 
			UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
 
			v->load_unload_time_rem = 0;
 
			ClrBit(v->u.rail.flags, VRF_TOGGLE_REVERSE);
 
			TrainConsistChanged(v, true);
 
			ClrBit(((Train *)v)->u.rail.flags, VRF_TOGGLE_REVERSE);
 
			TrainConsistChanged((Train *)v, true);
 
			break;
 

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

	
 
		case VEH_SHIP:
 
			InvalidateWindowClasses(WC_SHIPS_LIST);
 
			static_cast<Ship*>(v)->state = TRACK_BIT_DEPOT;
 
			RecalcShipStuff(v);
 
			break;
 
@@ -1479,25 +1479,25 @@ void Vehicle::LeaveStation()
 
	st->loading_vehicles.remove(this);
 

	
 
	HideFillingPercent(&this->fill_percent_te_id);
 

	
 
	if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) {
 
		/* Trigger station animation (trains only) */
 
		if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(st, this->tile, STAT_ANIM_TRAIN_DEPARTS);
 

	
 
		/* Try to reserve a path when leaving the station as we
 
		 * might not be marked as wanting a reservation, e.g.
 
		 * when an overlength train gets turned around in a station. */
 
		if (UpdateSignalsOnSegment(this->tile, TrackdirToExitdir(this->GetVehicleTrackdir()), this->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
 
			TryPathReserve(this, true, true);
 
			TryPathReserve((Train *)this, true, true);
 
		}
 
	}
 
}
 

	
 

	
 
void Vehicle::HandleLoading(bool mode)
 
{
 
	switch (this->current_order.GetType()) {
 
		case OT_LOADING: {
 
			uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
 

	
 
			/* Not the first call for this tick, or still loading */
src/vehicle_base.h
Show inline comments
 
@@ -37,25 +37,25 @@ enum VehStatus {
 

	
 
enum VehicleFlags {
 
	VF_LOADING_FINISHED,
 
	VF_CARGO_UNLOADING,
 
	VF_BUILT_AS_PROTOTYPE,
 
	VF_TIMETABLE_STARTED,       ///< Whether the vehicle has started running on the timetable yet.
 
	VF_AUTOFILL_TIMETABLE,      ///< Whether the vehicle should fill in the timetable automatically.
 
	VF_AUTOFILL_PRES_WAIT_TIME, ///< Whether non-destructive auto-fill should preserve waiting times
 
};
 

	
 
struct VehicleRail {
 
	/* Link between the two ends of a multiheaded engine */
 
	Vehicle *other_multiheaded_part;
 
	Train *other_multiheaded_part;
 

	
 
	/* Cached wagon override spritegroup */
 
	const struct SpriteGroup *cached_override;
 

	
 
	uint16 last_speed; // NOSAVE: only used in UI
 
	uint16 crash_anim_pos;
 

	
 
	/* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
 
	uint32 cached_power;        ///< total power of the consist.
 
	uint16 cached_max_speed;    ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist)
 
	uint16 cached_total_length; ///< Length of the whole train, valid only for first engine.
 
	uint8 cached_veh_length;    ///< length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback
src/vehicle_cmd.cpp
Show inline comments
 
@@ -143,25 +143,25 @@ CommandCost CmdMassStartStopVehicle(Tile
 
	} else {
 
		/* Get the list of vehicles in the depot */
 
		BuildDepotVehicleList(vehicle_type, tile, &list, NULL);
 
	}
 

	
 
	for (uint i = 0; i < list.Length(); i++) {
 
		const Vehicle *v = list[i];
 

	
 
		if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
 

	
 
		if (!vehicle_list_window) {
 
			if (vehicle_type == VEH_TRAIN) {
 
				if (CheckTrainInDepot(v, false) == -1) continue;
 
				if (CheckTrainInDepot((Train *)v, false) == -1) continue;
 
			} else {
 
				if (!(v->vehstatus & VS_HIDDEN)) continue;
 
			}
 
		}
 

	
 
		CommandCost ret = DoCommand(tile, v->index, 0, flags, CMD_START_STOP_VEHICLE);
 

	
 
		if (CmdSucceeded(ret)) {
 
			return_value = CommandCost();
 
			/* We know that the command is valid for at least one vehicle.
 
			 * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
 
			if (!(flags & DC_EXEC)) break;
 
@@ -372,47 +372,47 @@ CommandCost CmdCloneVehicle(TileIndex ti
 
		}
 

	
 
		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(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
 
				SetBit(w->u.rail.flags, VRF_REVERSE_DIRECTION);
 
			if (v->type == VEH_TRAIN && HasBit(((Train *)v)->u.rail.flags, VRF_REVERSE_DIRECTION)) {
 
				SetBit(((Train *)w)->u.rail.flags, VRF_REVERSE_DIRECTION);
 
			}
 

	
 
			if (v->type == VEH_TRAIN && !IsFrontEngine(v)) {
 
				/* 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(v)) != NULL);
 
	} while (v->type == VEH_TRAIN && (v = GetNextVehicle((Train *)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;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		/* Cloned vehicles belong to the same group */
 
		DoCommand(0, v_front->group_id, w_front->index, flags, CMD_ADD_VEHICLE_GROUP);
 
	}
 

	
 

	
 
@@ -428,50 +428,50 @@ CommandCost CmdCloneVehicle(TileIndex ti
 
	 * vehicles in a different loop. */
 
	do {
 
		do {
 
			if (flags & DC_EXEC) {
 
				assert(w != NULL);
 

	
 
				if (w->cargo_type != v->cargo_type || w->cargo_subtype != v->cargo_subtype) {
 
					CommandCost cost = DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8) | 1U << 16 , flags, GetCmdRefitVeh(v));
 
					if (CmdSucceeded(cost)) total_cost.AddCost(cost);
 
				}
 

	
 
				if (w->type == VEH_TRAIN && EngineHasArticPart(w)) {
 
					w = GetNextArticPart(w);
 
					w = GetNextArticPart((Train *)w);
 
				} else if (w->type == VEH_ROAD && RoadVehHasArticPart(w)) {
 
					w = w->Next();
 
				} else {
 
					break;
 
				}
 
			} else {
 
				const Engine *e = Engine::Get(v->engine_type);
 
				CargoID initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
 

	
 
				if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) {
 
					total_cost.AddCost(GetRefitCost(v->engine_type));
 
				}
 
			}
 

	
 
			if (v->type == VEH_TRAIN && EngineHasArticPart(v)) {
 
				v = GetNextArticPart(v);
 
				v = GetNextArticPart((Train *)v);
 
			} else if (v->type == VEH_ROAD && RoadVehHasArticPart(v)) {
 
				v = v->Next();
 
			} else {
 
				break;
 
			}
 
		} while (v != NULL);
 

	
 
		if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = GetNextVehicle(w);
 
	} while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
 
		if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = GetNextVehicle((Train *)w);
 
	} while (v->type == VEH_TRAIN && (v = GetNextVehicle((Train *)v)) != NULL);
 

	
 
	if (flags & DC_EXEC) {
 
		/*
 
		 * Set the orders of the vehicle. Cannot do it earlier as we need
 
		 * the vehicle refitted before doing this, otherwise the moved
 
		 * cargo types might not match (passenger vs non-passenger)
 
		 */
 
		DoCommand(0, (v_front->index << 16) | w_front->index, p2 & 1 ? CO_SHARE : CO_COPY, flags, CMD_CLONE_ORDER);
 

	
 
		/* Now clone the vehicle's name, if it has one. */
 
		if (v_front->name != NULL) CloneVehicleName(v_front, w_front);
 
	}
src/vehicle_func.h
Show inline comments
 
@@ -50,28 +50,24 @@ StringID VehicleInTheWayErrMsg(const Veh
 
bool HasVehicleOnTunnelBridge(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL);
 

	
 
void DecreaseVehicleValue(Vehicle *v);
 
void CheckVehicleBreakdown(Vehicle *v);
 
void AgeVehicle(Vehicle *v);
 
void VehicleEnteredDepotThisTick(Vehicle *v);
 

	
 
void VehicleMove(Vehicle *v, bool update_viewport);
 
void MarkSingleVehicleDirty(const Vehicle *v);
 

	
 
UnitID GetFreeUnitNumber(VehicleType type);
 

	
 
void TrainConsistChanged(Vehicle *v, bool same_length);
 
void TrainPowerChanged(Vehicle *v);
 
Money GetTrainRunningCost(const Vehicle *v);
 

	
 
CommandCost SendAllVehiclesToDepot(VehicleType type, DoCommandFlag flags, bool service, Owner owner, uint16 vlw_flag, uint32 id);
 
void VehicleEnterDepot(Vehicle *v);
 

	
 
bool CanBuildVehicleInfrastructure(VehicleType type);
 

	
 
void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2);
 

	
 
/** Position information of a vehicle after it moved */
 
struct GetNewVehiclePosResult {
 
	int x, y;  ///< x and y position of the vehicle after moving
 
	TileIndex old_tile; ///< Current tile of the vehicle
 
	TileIndex new_tile; ///< Tile of the vehicle after moving
src/vehicle_gui.cpp
Show inline comments
 
@@ -9,24 +9,25 @@
 
#include "gui.h"
 
#include "window_gui.h"
 
#include "textbuf_gui.h"
 
#include "command_func.h"
 
#include "vehicle_gui.h"
 
#include "vehicle_gui_base.h"
 
#include "viewport_func.h"
 
#include "gfx_func.h"
 
#include "newgrf_engine.h"
 
#include "newgrf_text.h"
 
#include "station_map.h"
 
#include "roadveh.h"
 
#include "train.h"
 
#include "depot_base.h"
 
#include "group_gui.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "vehicle_func.h"
 
#include "autoreplace_gui.h"
 
#include "string_func.h"
 
#include "widgets/dropdown_func.h"
 
#include "timetable.h"
 
#include "vehiclelist.h"
 
#include "settings_type.h"
 
#include "articulated_vehicles.h"
 
@@ -1459,25 +1460,25 @@ struct VehicleDetailsWindow : Window {
 
		SetDParam(0, (v->age + DAYS_IN_YEAR < v->max_age) ? STR_AGE : STR_AGE_RED);
 
		SetDParam(2, v->max_age / DAYS_IN_LEAP_YEAR);
 
		SetDParam(3, v->GetDisplayRunningCost());
 
		DrawString(2, this->width - 2, 15, STR_VEHICLE_INFO_AGE_RUNNING_COST_YR);
 

	
 
		/* Draw max speed */
 
		switch (v->type) {
 
			case VEH_TRAIN:
 
				SetDParam(2, v->GetDisplayMaxSpeed());
 
				SetDParam(1, v->u.rail.cached_power);
 
				SetDParam(0, v->u.rail.cached_weight);
 
				SetDParam(3, v->u.rail.cached_max_te / 1000);
 
				DrawString(2, this->width - 2, 25, (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
 
				DrawString(2, this->width - 2, 25, (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && ((Train *)v)->u.rail.railtype != RAILTYPE_MAGLEV) ?
 
					STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
 
					STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED);
 
				break;
 

	
 
			case VEH_ROAD:
 
			case VEH_SHIP:
 
			case VEH_AIRCRAFT:
 
				SetDParam(0, v->GetDisplayMaxSpeed());
 
				DrawString(2, this->width - 2, 25, STR_VEHICLE_INFO_MAX_SPEED);
 
				break;
 

	
 
			default: NOT_REACHED();
 
@@ -1939,25 +1940,25 @@ struct VehicleViewWindow : Window {
 
					if (v->u.rail.cached_power == 0) {
 
						str = STR_TRAIN_NO_POWER;
 
					} else {
 
						str = STR_VEHICLE_STATUS_STOPPED;
 
					}
 
				} else {
 
					SetDParam(0, v->GetDisplaySpeed());
 
					str = STR_TRAIN_STOPPING + _settings_client.gui.vehicle_speed;
 
				}
 
			} else { // no train
 
				str = STR_VEHICLE_STATUS_STOPPED;
 
			}
 
		} else if (v->type == VEH_TRAIN && HasBit(v->u.rail.flags, VRF_TRAIN_STUCK)) {
 
		} else if (v->type == VEH_TRAIN && HasBit(((Train *)v)->u.rail.flags, VRF_TRAIN_STUCK)) {
 
			str = STR_TRAIN_STUCK;
 
		} else { // vehicle is in a "normal" state, show current order
 
			switch (v->current_order.GetType()) {
 
				case OT_GOTO_STATION: {
 
					SetDParam(0, v->current_order.GetDestination());
 
					SetDParam(1, v->GetDisplaySpeed());
 
					str = STR_HEADING_FOR_STATION + _settings_client.gui.vehicle_speed;
 
				} break;
 

	
 
				case OT_GOTO_DEPOT: {
 
					if (v->type == VEH_AIRCRAFT) {
 
						/* Aircrafts always go to a station, even if you say depot */
src/vehicle_type.h
Show inline comments
 
@@ -15,24 +15,28 @@ enum VehicleType {
 
	VEH_SHIP,
 
	VEH_AIRCRAFT,
 
	VEH_EFFECT,
 
	VEH_DISASTER,
 
	VEH_END,
 
	VEH_INVALID = 0xFF,
 
};
 
DECLARE_POSTFIX_INCREMENT(VehicleType);
 
template <> struct EnumPropsT<VehicleType> : MakeEnumPropsT<VehicleType, byte, VEH_TRAIN, VEH_END, VEH_INVALID> {};
 
typedef TinyEnumT<VehicleType> VehicleTypeByte;
 

	
 
struct Vehicle;
 
struct Train;
 
struct RoadVehicle;
 
struct Ship;
 
struct Aircraft;
 

	
 
struct BaseVehicle
 
{
 
	VehicleTypeByte type;    ///< Type of vehicle
 
};
 

	
 
static const VehicleID INVALID_VEHICLE = 0xFFFF;
 

	
 
/** Pathfinding option states */
 
enum {
 
	VPF_OPF  = 0, ///< The Original PathFinder
 
	VPF_NTP  = 0, ///< New Train Pathfinder, replacing OPF for trains
src/vehiclelist.cpp
Show inline comments
 
@@ -20,25 +20,25 @@ void BuildDepotVehicleList(VehicleType t
 
	engines->Clear();
 
	if (wagons != NULL && wagons != engines) wagons->Clear();
 

	
 
	const Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		/* General tests for all vehicle types */
 
		if (v->type != type) continue;
 
		if (v->tile != tile) continue;
 

	
 
		switch (type) {
 
			case VEH_TRAIN:
 
				if (IsArticulatedPart(v) || IsRearDualheaded(v)) continue;
 
				if (v->u.rail.track != TRACK_BIT_DEPOT) continue;
 
				if (((Train *)v)->u.rail.track != TRACK_BIT_DEPOT) continue;
 
				if (wagons != NULL && IsFreeWagon(v->First())) {
 
					if (individual_wagons || IsFreeWagon(v)) *wagons->Append() = v;
 
					continue;
 
				}
 
				break;
 

	
 
			default:
 
				if (!v->IsInDepot()) continue;
 
				break;
 
		}
 

	
 
		if (!v->IsPrimaryVehicle()) continue;
src/water_cmd.cpp
Show inline comments
 
@@ -804,25 +804,25 @@ static void FloodVehicle(Vehicle *v)
 
				u->vehstatus |= VS_CRASHED;
 
				MarkSingleVehicleDirty(u);
 
			}
 

	
 
			switch (v->type) {
 
				default: NOT_REACHED();
 
				case VEH_TRAIN:
 
					if (IsFrontEngine(v)) {
 
						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(v);
 
						FreeTrainTrackReservation((Train *)v);
 
						v->vehstatus |= VS_CRASHED;
 
					}
 
					v->u.rail.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 *)v)->crashed_ctr = 2000; // max 2220, disappear pretty fast
 
					InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
					break;
 

	
src/waypoint_cmd.cpp
Show inline comments
 
@@ -249,25 +249,25 @@ CommandCost RemoveTrainWaypoint(TileInde
 
			(!CheckTileOwnership(tile) && _current_company != OWNER_WATER) ||
 
			!EnsureNoVehicleOnGround(tile)) {
 
		return CMD_ERROR;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		Track track = GetRailWaypointTrack(tile);
 
		wp = GetWaypointByTile(tile);
 

	
 
		wp->deleted = 30; // let it live for this many days before we do the actual deletion.
 
		RedrawWaypointSign(wp);
 

	
 
		Vehicle *v = NULL;
 
		Train *v = NULL;
 
		if (justremove) {
 
			TrackBits tracks = GetRailWaypointBits(tile);
 
			bool reserved = GetDepotWaypointReservation(tile);
 
			MakeRailNormal(tile, wp->owner, tracks, GetRailType(tile));
 
			if (reserved) SetTrackReservation(tile, tracks);
 
			MarkTileDirtyByTile(tile);
 
		} else {
 
			if (GetDepotWaypointReservation(tile)) {
 
				v = GetTrainForReservation(tile, track);
 
				if (v != NULL) FreeTrainTrackReservation(v);
 
			}
 
			DoClearSquare(tile);
src/yapf/follow_track.hpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file follow_track.hpp Template function for track followers */
 

	
 
#ifndef  FOLLOW_TRACK_HPP
 
#define  FOLLOW_TRACK_HPP
 

	
 
#include "yapf.hpp"
 
#include "../depot_map.h"
 
#include "../roadveh.h"
 
#include "../train.h"
 

	
 
/** Track follower helper template class (can serve pathfinders and vehicle
 
 *  controllers). See 6 different typedefs below for 3 different transport
 
 *  types w/ or w/o 90-deg turns allowed */
 
template <TransportType Ttr_type_, bool T90deg_turns_allowed_ = true, bool Tmask_reserved_tracks = false>
 
struct CFollowTrackT
 
{
 
	enum ErrorCode {
 
		EC_NONE,
 
		EC_OWNER,
 
		EC_RAIL_TYPE,
 
		EC_90DEG,
 
@@ -45,25 +46,25 @@ struct CFollowTrackT
 
	}
 

	
 
	FORCEINLINE CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL)
 
	{
 
		m_veh = NULL;
 
		Init(o, railtype_override, pPerf);
 
	}
 

	
 
	FORCEINLINE void Init(const Vehicle *v, RailTypes railtype_override, CPerformanceTimer *pPerf)
 
	{
 
		assert(!IsRailTT() || (v != NULL && v->type == VEH_TRAIN));
 
		m_veh = v;
 
		Init(v != NULL ? v->owner : INVALID_OWNER, railtype_override == INVALID_RAILTYPES ? v->u.rail.compatible_railtypes : railtype_override, pPerf);
 
		Init(v != NULL ? v->owner : INVALID_OWNER, railtype_override == INVALID_RAILTYPES ? ((Train *)v)->u.rail.compatible_railtypes : railtype_override, pPerf);
 
	}
 

	
 
	FORCEINLINE void Init(Owner o, RailTypes railtype_override, CPerformanceTimer *pPerf)
 
	{
 
		assert((!IsRoadTT() || m_veh != NULL) && (!IsRailTT() || railtype_override != INVALID_RAILTYPES));
 
		m_veh_owner = o;
 
		m_pPerf = pPerf;
 
		/* don't worry, all is inlined so compiler should remove unnecessary initializations */
 
		m_new_tile = INVALID_TILE;
 
		m_new_td_bits = TRACKDIR_BIT_NONE;
 
		m_exitdir = INVALID_DIAGDIR;
 
		m_is_station = m_is_bridge = m_is_tunnel = false;
 
@@ -96,25 +97,25 @@ struct CFollowTrackT
 
			}
 
		}
 
		return INVALID_DIAGDIR;
 
	}
 

	
 
	/** main follower routine. Fills all members and return true on success.
 
	 *  Otherwise returns false if track can't be followed. */
 
	inline bool Follow(TileIndex old_tile, Trackdir old_td)
 
	{
 
		m_old_tile = old_tile;
 
		m_old_td = old_td;
 
		m_err = EC_NONE;
 
		assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), m_veh ? m_veh->u.road.compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
 
		assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), m_veh ? ((RoadVehicle *)m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
 
		       (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR)); // Disable the assertion for single tram bits
 
		m_exitdir = TrackdirToExitdir(m_old_td);
 
		if (ForcedReverse()) return true;
 
		if (!CanExitOldTile()) return false;
 
		FollowTileExit();
 
		if (!QueryNewTileTrackStatus()) return TryReverse();
 
		if (!CanEnterNewTile()) return false;
 
		m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir);
 
		if (m_new_td_bits == TRACKDIR_BIT_NONE) {
 
			m_err = EC_NO_WAY;
 
			return false;
 
		}
src/yapf/yapf_destrail.hpp
Show inline comments
 
@@ -82,26 +82,26 @@ public:
 
	}
 

	
 
	/** Called by YAPF to detect if node ends in the desired destination */
 
	FORCEINLINE bool PfDetectDestination(Node& n)
 
	{
 
		return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir());
 
	}
 

	
 
	/** Called by YAPF to detect if node ends in the desired destination */
 
	FORCEINLINE bool PfDetectDestination(TileIndex tile, Trackdir td)
 
	{
 
		return
 
			IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns()) &&
 
			IsWaitingPositionFree(Yapf().GetVehicle(), tile, td, !TrackFollower::Allow90degTurns());
 
			IsSafeWaitingPosition((Train *)Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns()) &&
 
			IsWaitingPositionFree((Train *)Yapf().GetVehicle(), tile, td, !TrackFollower::Allow90degTurns());
 
	}
 

	
 
	/** Called by YAPF to calculate cost estimate. Calculates distance to the destination
 
	 *  adds it to the actual cost from origin and stores the sum to the Node::m_estimate. */
 
	FORCEINLINE bool PfCalcEstimate(Node& n)
 
	{
 
		n.m_estimate = n.m_cost;
 
		return true;
 
	}
 
};
 

	
 
template <class Types>
src/yapf/yapf_rail.cpp
Show inline comments
 
@@ -45,25 +45,25 @@ protected:
 
		return *static_cast<Tpf*>(this);
 
	}
 

	
 
private:
 
	TileIndex m_res_dest;         ///< The reservation target tile
 
	Trackdir  m_res_dest_td;      ///< The reservation target trackdir
 
	Node      *m_res_node;        ///< The reservation target node
 
	TileIndex m_res_fail_tile;    ///< The tile where the reservation failed
 
	Trackdir  m_res_fail_td;      ///< The trackdir where the reservation failed
 

	
 
	bool FindSafePositionProc(TileIndex tile, Trackdir td)
 
	{
 
		if (IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns())) {
 
		if (IsSafeWaitingPosition((Train *)Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns())) {
 
			m_res_dest = tile;
 
			m_res_dest_td = td;
 
			return false;   // Stop iterating segment
 
		}
 
		return true;
 
	}
 

	
 
	/** Reserve a railway platform. Tile contains the failed tile on abort. */
 
	bool ReserveRailwayStationPlatform(TileIndex &tile, DiagDirection dir)
 
	{
 
		TileIndex     start = tile;
 
		TileIndexDiff diff = TileOffsByDiagDir(dir);
 
@@ -140,25 +140,25 @@ public:
 
	/** Try to reserve the path till the reservation target. */
 
	bool TryReservePath(PBSTileInfo *target)
 
	{
 
		m_res_fail_tile = INVALID_TILE;
 

	
 
		if (target != NULL) {
 
			target->tile = m_res_dest;
 
			target->trackdir = m_res_dest_td;
 
			target->okay = false;
 
		}
 

	
 
		/* Don't bother if the target is reserved. */
 
		if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td)) return false;
 
		if (!IsWaitingPositionFree((Train *)Yapf().GetVehicle(), m_res_dest, m_res_dest_td)) return false;
 

	
 
		for (Node *node = m_res_node; node->m_parent != NULL; node = node->m_parent) {
 
			node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::ReserveSingleTrack);
 
			if (m_res_fail_tile != INVALID_TILE) {
 
				/* Reservation failed, undo. */
 
				Node *fail_node = m_res_node;
 
				TileIndex stop_tile = m_res_fail_tile;
 
				do {
 
					/* If this is the node that failed, stop at the failed tile. */
 
					m_res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE;
 
					fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack<Types>::UnreserveSingleTrack);
 
				} while (fail_node != node && (fail_node = fail_node->m_parent) != NULL);
 
@@ -402,25 +402,25 @@ public:
 
			DumpState(pf1, pf2);
 
		}
 
#endif
 

	
 
		return result1;
 
	}
 

	
 
	FORCEINLINE Trackdir ChooseRailTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found, bool reserve_track, PBSTileInfo *target)
 
	{
 
		if (target != NULL) target->tile = INVALID_TILE;
 

	
 
		/* set origin and destination nodes */
 
		PBSTileInfo origin = FollowTrainReservation(v);
 
		PBSTileInfo origin = FollowTrainReservation((Train *)v);
 
		Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, INVALID_TRACKDIR, 1, true);
 
		Yapf().SetDestination(v);
 

	
 
		/* find the best path */
 
		bool path_found = Yapf().FindPath(v);
 
		if (path_not_found != NULL) {
 
			/* tell controller that the path was only 'guessed'
 
			 * treat the path as found if stopped on the first two way signal(s) */
 
			*path_not_found = !(path_found || Yapf().m_stopped_on_first_two_way_signal);
 
		}
 

	
 
		/* if path not found - return INVALID_TRACKDIR */
 
@@ -525,28 +525,29 @@ Trackdir YapfChooseRailTrack(const Vehic
 
	PfnChooseRailTrack pfnChooseRailTrack = &CYapfRail1::stChooseRailTrack;
 

	
 
	/* check if non-default YAPF type needed */
 
	if (_settings_game.pf.forbid_90_deg) {
 
		pfnChooseRailTrack = &CYapfRail2::stChooseRailTrack; // Trackdir, forbid 90-deg
 
	}
 

	
 
	Trackdir td_ret = pfnChooseRailTrack(v, tile, enterdir, tracks, path_not_found, reserve_track, target);
 

	
 
	return td_ret;
 
}
 

	
 
bool YapfCheckReverseTrain(const Vehicle *v)
 
bool YapfCheckReverseTrain(const Vehicle *vt)
 
{
 
	Train *v = (Train *)vt;
 
	/* last wagon */
 
	const Vehicle *last_veh = GetLastVehicleInChain(v);
 
	const Train *last_veh = (Train *)GetLastVehicleInChain(v);
 

	
 
	/* get trackdirs of both ends */
 
	Trackdir td = v->GetVehicleTrackdir();
 
	Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
 

	
 
	/* tiles where front and back are */
 
	TileIndex tile = v->tile;
 
	TileIndex tile_rev = last_veh->tile;
 

	
 
	int reverse_penalty = 0;
 

	
 
	if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
 
@@ -592,25 +593,25 @@ bool YapfCheckReverseTrain(const Vehicle
 
	bool reverse = pfnCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
 

	
 
	return reverse;
 
}
 

	
 
bool YapfFindNearestRailDepotTwoWay(const Vehicle *v, int max_distance, int reverse_penalty, TileIndex *depot_tile, bool *reversed)
 
{
 
	*depot_tile = INVALID_TILE;
 
	*reversed = false;
 

	
 
	const Vehicle *last_veh = GetLastVehicleInChain(v);
 

	
 
	PBSTileInfo origin = FollowTrainReservation(v);
 
	PBSTileInfo origin = FollowTrainReservation((Train *)v);
 
	TileIndex last_tile = last_veh->tile;
 
	Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir());
 

	
 
	typedef bool (*PfnFindNearestDepotTwoWay)(const Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir, int, int, TileIndex*, bool*);
 
	PfnFindNearestDepotTwoWay pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail1::stFindNearestDepotTwoWay;
 

	
 
	/* check if non-default YAPF type needed */
 
	if (_settings_game.pf.forbid_90_deg) {
 
		pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail2::stFindNearestDepotTwoWay; // Trackdir, forbid 90-deg
 
	}
 

	
 
	bool ret = pfnFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_distance, reverse_penalty, depot_tile, reversed);
0 comments (0 inline, 0 general)