Changeset - r11982:ff4390b32b95
[Not reviewed]
master
0 18 0
rubidium - 15 years ago 2009-05-22 22:55:41
rubidium@openttd.org
(svn r16393) -Codechange: move VehicleRail to Train.
18 files changed with 138 insertions and 138 deletions:
0 comments (0 inline, 0 general)
src/ai/api/ai_vehicle.cpp
Show inline comments
 
@@ -40,25 +40,25 @@
 
{
 
	if (!IsValidVehicle(vehicle_id)) return -1;
 

	
 
	const Vehicle *v = ::Vehicle::Get(vehicle_id);
 
	switch (v->type) {
 
		case VEH_ROAD: {
 
			uint total_length = 0;
 
			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
 
				total_length += ((RoadVehicle*)u)->cached_veh_length;
 
			}
 
			return total_length;
 
		}
 
		case VEH_TRAIN: return v->u.rail.cached_total_length;
 
		case VEH_TRAIN: return ((Train *)v)->tcache.cached_total_length;
 
		default: return -1;
 
	}
 
}
 

	
 
/* static */ VehicleID AIVehicle::BuildVehicle(TileIndex depot, EngineID engine_id)
 
{
 
	EnforcePrecondition(INVALID_VEHICLE, AIEngine::IsValidEngine(engine_id));
 

	
 
	::VehicleType type = ::Engine::Get(engine_id)->type;
 

	
 
	EnforcePreconditionCustomError(INVALID_VEHICLE, !AIGameSettings::IsDisabledVehicleType((AIVehicle::VehicleType)type), AIVehicle::ERR_VEHICLE_BUILD_DISABLED);
 

	
src/articulated_vehicles.cpp
Show inline comments
 
@@ -305,25 +305,25 @@ void AddArticulatedParts(Vehicle *first,
 
		Vehicle *previous = u;
 
		const Engine *e_artic = Engine::Get(engine_type);
 
		switch (type) {
 
			default: NOT_REACHED();
 

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

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

	
 
				SetArticulatedPart(t);
 
				u = t;
src/autoreplace_cmd.cpp
Show inline comments
 
@@ -394,25 +394,25 @@ static CommandCost ReplaceFreeUnit(Vehic
 
 * @param nothing_to_do is set to 'false' when something was done (only valid when not failed)
 
 * @return cost or error
 
 */
 
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;
 
		uint16 old_total_length = (((Train *)old_head)->tcache.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE;
 

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

	
 
		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;
 
		Train *w;
 
@@ -446,39 +446,39 @@ static CommandCost ReplaceChain(Vehicle 
 
					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);
 
			if (cost.Succeeded() && wagon_removal && new_head->tcache.cached_total_length > old_total_length) cost = CommandCost(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT);
 

	
 
			/* Append/insert wagons into the new vehicle chain
 
			 * We do this from back to front, so we can stop when wagon removal or maximum train length (i.e. from mammoth-train setting) is triggered.
 
			 */
 
			if (cost.Succeeded()) {
 
				for (int i = num_units - 1; i > 0; i--) {
 
					assert(last_engine != NULL);
 
					Vehicle *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]);
 

	
 
					if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) {
 
						/* Insert wagon after 'last_engine' */
 
						CommandCost res = MoveVehicle(append, last_engine, DC_EXEC, false);
 

	
 
						if (res.Succeeded() && wagon_removal && new_head->u.rail.cached_total_length > old_total_length) {
 
						if (res.Succeeded() && wagon_removal && new_head->tcache.cached_total_length > old_total_length) {
 
							MoveVehicle(append, NULL, DC_EXEC | DC_AUTOREPLACE, false);
 
							break;
 
						}
 

	
 
						cost.AddCost(res);
 
						if (cost.Failed()) break;
 
					} else {
 
						/* We have reached 'last_engine', continue with the next engine towards the front */
 
						assert(append == last_engine);
 
						last_engine = GetPrevUnit(last_engine);
 
					}
 
				}
src/depot_gui.cpp
Show inline comments
 
@@ -263,25 +263,25 @@ struct DepotWindow : Window {
 
	 */
 
	void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
 
	{
 
		byte diff_x = 0, diff_y = 0;
 

	
 
		int sprite_y = y + this->resize.step_height - GetVehicleListHeight(v->type);
 

	
 
		switch (v->type) {
 
			case VEH_TRAIN:
 
				DrawTrainImage(v, x + 21, sprite_y, this->sel, this->hscroll.cap + 4, this->hscroll.pos);
 

	
 
				/* Number of wagons relative to a standard length wagon (rounded up) */
 
				SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
 
				SetDParam(0, (((Train *)v)->tcache.cached_total_length + 7) / 8);
 
				DrawString(this->widget[DEPOT_WIDGET_MATRIX].left, this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING, SA_RIGHT); // Draw the counter
 
				break;
 

	
 
			case VEH_ROAD:     DrawRoadVehImage( v, x + 24, sprite_y, this->sel, 1); break;
 
			case VEH_SHIP:     DrawShipImage(    v, x + 19, sprite_y - 1, this->sel); break;
 
			case VEH_AIRCRAFT: {
 
				const Sprite *spr = GetSprite(v->GetImage(DIR_W), ST_NORMAL);
 
				DrawAircraftImage(v, x + 12,
 
									y + max(spr->height + spr->y_offs - 14, 0), // tall sprites needs an y offset
 
									this->sel);
 
			} break;
 
			default: NOT_REACHED();
 
@@ -319,25 +319,25 @@ struct DepotWindow : Window {
 
			DEPOT_WIDGET_SELL_CHAIN,
 
			DEPOT_WIDGET_SELL_ALL,
 
			DEPOT_WIDGET_BUILD,
 
			DEPOT_WIDGET_CLONE,
 
			DEPOT_WIDGET_AUTOREPLACE,
 
			WIDGET_LIST_END);
 

	
 
		/* determine amount of items for scroller */
 
		if (this->type == VEH_TRAIN) {
 
			hnum = 8;
 
			for (uint num = 0; num < this->vehicle_list.Length(); num++) {
 
				const Vehicle *v = this->vehicle_list[num];
 
				hnum = max(hnum, v->u.rail.cached_total_length);
 
				hnum = max(hnum, ((Train *)v)->tcache.cached_total_length);
 
			}
 
			/* Always have 1 empty row, so people can change the setting of the train */
 
			SetVScrollCount(w, this->vehicle_list.Length() + this->wagon_list.Length() + 1);
 
			SetHScrollCount(w, WagonLengthToPixels(hnum));
 
		} else {
 
			SetVScrollCount(w, (this->vehicle_list.Length() + this->hscroll.cap - 1) / this->hscroll.cap);
 
		}
 

	
 
		/* locate the depot struct */
 
		if (this->type == VEH_AIRCRAFT) {
 
			SetDParam(0, GetStationIndex(tile)); // Airport name
 
		} else {
 
@@ -441,25 +441,25 @@ struct DepotWindow : Window {
 
				d->head = d->wagon = v;
 

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

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

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

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

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

	
 
				d->wagon = v;
 

	
 
				return MODE_DRAG_VEHICLE;
 
				}
 
				break;
 

	
 
			case VEH_ROAD:
 
				if (xm >= 24) return MODE_DRAG_VEHICLE;
 
@@ -505,25 +505,25 @@ struct DepotWindow : Window {
 
				if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) {
 
					this->sel = INVALID_VEHICLE;
 
					TrainDepotMoveVehicle(v, sel, gdvp.head);
 
				} else if (v != NULL) {
 
					int image = v->GetImage(DIR_W);
 

	
 
					this->sel = v->index;
 
					this->SetDirty();
 
					SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this);
 

	
 
					switch (v->type) {
 
						case VEH_TRAIN:
 
							_cursor.short_vehicle_offset = 16 - v->u.rail.cached_veh_length * 2;
 
							_cursor.short_vehicle_offset = 16 - ((Train *)v)->tcache.cached_veh_length * 2;
 
							break;
 

	
 
						case VEH_ROAD:
 
							_cursor.short_vehicle_offset = 16 - ((RoadVehicle *)v)->cached_veh_length * 2;
 
							break;
 

	
 
						default:
 
							_cursor.short_vehicle_offset = 0;
 
							break;
 
					}
 
					_cursor.vehchain = _ctrl_pressed;
 
				}
src/economy.cpp
Show inline comments
 
@@ -6,24 +6,25 @@
 
#include "openttd.h"
 
#include "tile_cmd.h"
 
#include "company_func.h"
 
#include "command_func.h"
 
#include "industry_map.h"
 
#include "town.h"
 
#include "news_func.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "vehicle_gui.h"
 
#include "ai/ai.hpp"
 
#include "aircraft.h"
 
#include "train.h"
 
#include "newgrf_engine.h"
 
#include "newgrf_sound.h"
 
#include "newgrf_industries.h"
 
#include "newgrf_industrytiles.h"
 
#include "newgrf_station.h"
 
#include "unmovable.h"
 
#include "group.h"
 
#include "strings_func.h"
 
#include "functions.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
@@ -1641,25 +1642,25 @@ static void LoadUnloadVehicle(Vehicle *v
 
				ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING);
 
			}
 

	
 
			continue;
 
		}
 

	
 
		/* Do not pick up goods when we have no-load set. */
 
		if (u->current_order.GetLoadType() & OLFB_NO_LOAD) continue;
 

	
 
		/* update stats */
 
		int t;
 
		switch (u->type) {
 
			case VEH_TRAIN: t = u->u.rail.cached_max_speed; break;
 
			case VEH_TRAIN: t = ((Train *)u)->tcache.cached_max_speed; break;
 
			case VEH_ROAD:  t = u->max_speed / 2;           break;
 
			default:        t = u->max_speed;               break;
 
		}
 

	
 
		/* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
 
		ge->last_speed = min(t, 255);
 
		ge->last_age = _cur_year - u->build_year;
 
		ge->days_since_pickup = 0;
 

	
 
		/* If there's goods waiting at the station, and the vehicle
 
		 * has capacity for it, load it on the vehicle. */
 
		int cap_left = v->cargo_cap - v->cargo.Count();
 
@@ -1750,25 +1751,25 @@ static void LoadUnloadVehicle(Vehicle *v
 
				}
 
			} else if (cargo_not_full != 0) {
 
				finished_loading = false;
 
			}
 
		}
 
		unloading_time = 20;
 

	
 
		SB(v->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading);
 
	}
 

	
 
	if (v->type == VEH_TRAIN) {
 
		/* Each platform tile is worth 2 rail vehicles. */
 
		int overhang = v->u.rail.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
 
		int overhang = ((Train *)v)->tcache.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
 
		if (overhang > 0) {
 
			unloading_time <<= 1;
 
			unloading_time += (overhang * unloading_time) / 8;
 
		}
 
	}
 

	
 
	/* Calculate the loading indicator fill percent and display
 
	 * In the Game Menu do not display indicators
 
	 * If _settings_client.gui.loading_indicators == 2, show indicators (bool can be promoted to int as 0 or 1 - results in 2 > 0,1 )
 
	 * if _settings_client.gui.loading_indicators == 1, _local_company must be the owner or must be a spectator to show ind., so 1 > 0
 
	 * if _settings_client.gui.loading_indicators == 0, do not display indicators ... 0 is never greater than anything
 
	 */
src/newgrf_engine.cpp
Show inline comments
 
@@ -425,25 +425,25 @@ static void VehicleSetTriggers(const Res
 
	if (v != NULL) v->waiting_triggers = triggers;
 
}
 

	
 

	
 
static uint8 LiveryHelper(EngineID engine, const Vehicle *v)
 
{
 
	const Livery *l;
 

	
 
	if (v == NULL) {
 
		if (!Company::IsValidID(_current_company)) return 0;
 
		l = GetEngineLivery(engine, _current_company, INVALID_ENGINE, NULL);
 
	} else if (v->type == VEH_TRAIN) {
 
		l = GetEngineLivery(v->engine_type, v->owner, v->u.rail.first_engine, v);
 
		l = GetEngineLivery(v->engine_type, v->owner, ((Train *)v)->tcache.first_engine, v);
 
	} else if (v->type == VEH_ROAD) {
 
		l = GetEngineLivery(v->engine_type, v->owner, ((RoadVehicle *)v)->first_engine, v);
 
	} else {
 
		l = GetEngineLivery(v->engine_type, v->owner, INVALID_ENGINE, v);
 
	}
 

	
 
	return l->colour1 + l->colour2 * 16;
 
}
 

	
 
/**
 
 * Helper to get the position of a vehicle within a chain of vehicles.
 
 * @param v the vehicle to get the position of.
 
@@ -527,25 +527,25 @@ static uint32 VehicleGetVariable(const R
 
				uint8 common_cargos[NUM_CARGO];
 
				uint8 common_subtype_best = 0xFF; // Return 0xFF if nothing is carried
 
				uint8 common_subtypes[256];
 
				byte user_def_data = 0;
 
				CargoID common_cargo_type = CT_PASSENGERS;
 
				uint8 common_subtype = 0;
 

	
 
				/* Reset our arrays */
 
				memset(common_cargos, 0, sizeof(common_cargos));
 
				memset(common_subtypes, 0, sizeof(common_subtypes));
 

	
 
				for (u = v; u != NULL; u = u->Next()) {
 
					if (v->type == VEH_TRAIN) user_def_data |= u->u.rail.user_def_data;
 
					if (v->type == VEH_TRAIN) user_def_data |= ((Train *)u)->tcache.user_def_data;
 

	
 
					/* Skip empty engines */
 
					if (u->cargo_cap == 0) continue;
 

	
 
					cargo_classes |= GetCargo(u->cargo_type)->classes;
 
					common_cargos[u->cargo_type]++;
 
				}
 

	
 
				/* Pick the most common cargo type */
 
				for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
 
					if (common_cargos[cargo] > common_cargo_best) {
 
						common_cargo_best = common_cargos[cargo];
 
@@ -763,29 +763,29 @@ static uint32 VehicleGetVariable(const R
 
		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: {
 
			Train *t = (Train *)v;
 
			switch (variable - 0x80) {
 
				case 0x62: return t->track;
 
				case 0x66: return t->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 0x73: return t->tcache.cached_veh_length;
 
				case 0x74: return t->tcache.cached_power;
 
				case 0x75: return GB(t->tcache.cached_power,  8, 24);
 
				case 0x76: return GB(t->tcache.cached_power, 16, 16);
 
				case 0x77: return GB(t->tcache.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;
 

	
 
		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);
 
@@ -877,25 +877,25 @@ static const SpriteGroup *GetVehicleSpri
 
	const SpriteGroup *group;
 
	CargoID cargo;
 

	
 
	if (v == NULL) {
 
		cargo = CT_PURCHASE;
 
	} else {
 
		cargo = v->cargo_type;
 

	
 
		if (v->type == VEH_TRAIN) {
 
			/* We always use cached value, except for callbacks because the override spriteset
 
			 * to use may be different than the one cached. It happens for callback 0x15 (refit engine),
 
			 * as v->cargo_type is temporary changed to the new type */
 
			group = use_cache ? v->u.rail.cached_override : GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->u.rail.first_engine);
 
			group = use_cache ? ((Train *)v)->tcache.cached_override : GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, ((Train *)v)->tcache.first_engine);
 
			if (group != NULL) return group;
 
		} else if (v->type == VEH_ROAD) {
 
			group = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, ((RoadVehicle *)v)->first_engine);
 
			if (group != NULL) return group;
 
		}
 
	}
 

	
 
	const Engine *e = Engine::Get(engine);
 

	
 
	assert(cargo < lengthof(e->group));
 
	group = e->group[cargo];
 
	if (group != NULL) return group;
 
@@ -943,25 +943,25 @@ SpriteID GetRotorOverrideSprite(EngineID
 
	return group->g.result.sprite + (info_view ? 0 : (v->Next()->Next()->state % group->g.result.num_sprites));
 
}
 

	
 

	
 
/**
 
 * Check if a wagon is currently using a wagon override
 
 * @param v The wagon to check
 
 * @return true if it is using an override, false otherwise
 
 */
 
bool UsesWagonOverride(const Vehicle *v)
 
{
 
	assert(v->type == VEH_TRAIN);
 
	return v->u.rail.cached_override != NULL;
 
	return ((Train *)v)->tcache.cached_override != NULL;
 
}
 

	
 
/**
 
 * Evaluate a newgrf callback for vehicles
 
 * @param callback The callback to evalute
 
 * @param param1   First parameter of the callback
 
 * @param param2   Second parameter of the callback
 
 * @param engine   Engine type of the vehicle to evaluate the callback for
 
 * @param v        The vehicle to evaluate the callback for, or NULL if it doesnt exist yet
 
 * @return The value the callback returned, or CALLBACK_FAILED if it failed
 
 */
 
uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v)
src/openttd.cpp
Show inline comments
 
@@ -1118,35 +1118,36 @@ void StateGameLoop()
 
				if (v != v->First()) continue;
 

	
 
				switch (v->type) {
 
					case VEH_ROAD: {
 
						extern byte GetRoadVehLength(const RoadVehicle *v);
 
						if (GetRoadVehLength((RoadVehicle *)v) != ((RoadVehicle *)v)->cached_veh_length) {
 
							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++;
 
						Train *t = (Train *)v;
 
						for (Vehicle *u = t; u != NULL; u = u->Next()) length++;
 

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

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

	
 
						length = 0;
 
						for (Vehicle *u = v; u != NULL; u = u->Next()) {
 
							if (memcmp(&wagons[length], &u->u.rail, sizeof(VehicleRail)) != 0) {
 
						for (Train *u = t; u != NULL; u = u->Next()) {
 
							if (memcmp(&wagons[length], &u->tcache, sizeof(TrainCache)) != 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;
 

	
 
					case VEH_AIRCRAFT: {
 
						Aircraft *a = (Aircraft *)v;
 
						uint speed = a->cached_max_speed;
 
						UpdateAircraftCache(a);
src/rail.h
Show inline comments
 
@@ -214,25 +214,25 @@ static inline Money RailConvertCost(Rail
 
		Money cost = (RailBuildCost(from) - RailBuildCost(to)) >> 2;
 
		if (cost != 0) return cost;
 
	}
 

	
 
	/* make the price the same as remove + build new type */
 
	return RailBuildCost(to) + _price.remove_rail;
 
}
 

	
 
Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data);
 
void DrawTrainDepotSprite(int x, int y, int image, RailType railtype);
 
void DrawDefaultWaypointSprite(int x, int y, RailType railtype);
 
Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data);
 
int TicksToLeaveDepot(const Vehicle *v);
 
int TicksToLeaveDepot(const Train *v);
 

	
 
Foundation GetRailFoundation(Slope tileh, TrackBits bits);
 

	
 

	
 
/**
 
 * Finds out if a company has a certain railtype available
 
 * @param company the company in question
 
 * @param railtype requested RailType
 
 * @return true if company has requested RailType available
 
 */
 
bool HasRailtypeAvail(const CompanyID company, const RailType railtype);
 

	
src/rail_cmd.cpp
Show inline comments
 
@@ -2424,28 +2424,28 @@ static const byte _fractcoords_behind[4]
 
static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
 
static const signed char _deltacoord_leaveoffset[8] = {
 
	-1,  0,  1,  0, /* x */
 
	 0,  1,  0, -1  /* y */
 
};
 

	
 

	
 
/** Compute number of ticks when next wagon will leave a depot.
 
 * Negative means next wagon should have left depot n ticks before.
 
 * @param v vehicle outside (leaving) the depot
 
 * @return number of ticks when the next wagon will leave
 
 */
 
int TicksToLeaveDepot(const Vehicle *v)
 
int TicksToLeaveDepot(const Train *v)
 
{
 
	DiagDirection dir = GetRailDepotDirection(v->tile);
 
	int length = v->u.rail.cached_veh_length;
 
	int length = v->tcache.cached_veh_length;
 

	
 
	switch (dir) {
 
		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
 
}
 

	
 
@@ -2459,25 +2459,25 @@ static VehicleEnterTileStatus VehicleEnt
 
	int length;
 

	
 
	/* this routine applies only to trains in depot tiles */
 
	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;
 
	length = v->tcache.cached_veh_length;
 

	
 
	fract_coord_leave =
 
		((_fractcoords_enter[dir] & 0x0F) + // x
 
			(length + 1) * _deltacoord_leaveoffset[dir]) +
 
		(((_fractcoords_enter[dir] >> 4) +  // y
 
			((length + 1) * _deltacoord_leaveoffset[dir+4])) << 4);
 

	
 
	fract_coord = (x & 0xF) + ((y & 0xF) << 4);
 

	
 
	if (_fractcoords_behind[dir] == fract_coord) {
 
		/* make sure a train is not entering the tile from behind */
 
		return VETSB_CANNOT_ENTER;
src/saveload/vehicle_sl.cpp
Show inline comments
 
@@ -243,25 +243,25 @@ void AfterLoadVehicles(bool part_of_load
 
{
 
	Vehicle *v;
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		/* Reinstate the previous pointer */
 
		if (v->Next() != NULL) v->Next()->previous = v;
 
		if (v->NextShared() != NULL) v->NextShared()->previous_shared = v;
 

	
 
		v->UpdateDeltaXY(v->direction);
 

	
 
		if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
 
		v->first = NULL;
 
		if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
 
		if (v->type == VEH_TRAIN) ((Train *)v)->tcache.first_engine = INVALID_ENGINE;
 
		if (v->type == VEH_ROAD)  ((RoadVehicle *)v)->first_engine = INVALID_ENGINE;
 

	
 
		v->cargo.InvalidateCache();
 
	}
 

	
 
	/* AfterLoadVehicles may also be called in case of NewGRF reload, in this
 
	 * case we may not convert orders again. */
 
	if (part_of_load) {
 
		/* Create shared vehicle chain for very old games (pre 5,2) and create
 
		 * OrderList from shared vehicle chains. For this to work correctly, the
 
		 * following conditions must be fulfilled:
 
		 * a) both next_shared and previous_shared are not set for pre 5,2 games
 
@@ -309,25 +309,25 @@ 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)) ((Train *)v)->u.rail.last_speed = v->cur_speed; // update displayed train speed
 
			if (IsFrontEngine(v)) ((Train *)v)->tcache.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
src/train.h
Show inline comments
 
@@ -250,59 +250,95 @@ int CheckTrainStoppedInDepot(const Train
 
void UpdateTrainAcceleration(Train *v);
 
void CheckTrainsLengths();
 

	
 
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 Train *v, int *station_ahead, int *station_length);
 

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

	
 
/** Variables that are cached to improve performance and such */
 
struct TrainCache {
 
	/* Cached wagon override spritegroup */
 
	const struct SpriteGroup *cached_override;
 

	
 
	uint16 last_speed; // NOSAVE: only used in UI
 

	
 
	/* 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
 
	bool cached_tilt;           ///< train can tilt; feature provides a bonus in curves
 

	
 
	/* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
 
	uint32 cached_weight;     ///< total weight of the consist.
 
	uint32 cached_veh_weight; ///< weight of the vehicle.
 
	uint32 cached_max_te;     ///< max tractive effort of consist
 

	
 
	/**
 
	 * Position/type of visual effect.
 
	 * bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear)
 
	 * bit 4 - 5 = type of effect. (0 = default for engine class, 1 = steam, 2 = diesel, 3 = electric)
 
	 * bit     6 = disable visual effect.
 
	 * bit     7 = disable powered wagons.
 
	 */
 
	byte cached_vis_effect;
 
	byte user_def_data;
 

	
 
	/* NOSAVE: for wagon override - id of the first engine in train
 
	 * 0xffff == not in train */
 
	EngineID first_engine;
 
};
 

	
 
/**
 
 * 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 {
 
	TrainCache tcache;
 

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

	
 
	uint16 crash_anim_pos;
 

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

	
 
	/** Initializes the Vehicle to a train */
 
	Train() { this->type = VEH_TRAIN; }
 

	
 
	/** We want to 'destruct' the right class. */
 
	virtual ~Train() { this->PreDestructor(); }
 

	
 
	const char *GetTypeString() const { return "train"; }
 
	void MarkDirty();
 
	void UpdateDeltaXY(Direction direction);
 
	ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; }
 
	void PlayLeaveStationSound() const;
 
	bool IsPrimaryVehicle() const { return IsFrontEngine(this); }
 
	SpriteID GetImage(Direction direction) const;
 
	int GetDisplaySpeed() const { return this->u.rail.last_speed; }
 
	int GetDisplayMaxSpeed() const { return this->u.rail.cached_max_speed; }
 
	int GetDisplaySpeed() const { return this->tcache.last_speed; }
 
	int GetDisplayMaxSpeed() const { return this->tcache.cached_max_speed; }
 
	Money GetRunningCost() const;
 
	bool IsInDepot() const { return CheckTrainInDepot(this, false) != -1; }
 
	bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
 
	bool Tick();
 
	void OnNewDay();
 
	Trackdir GetVehicleTrackdir() const;
 
	TileIndex GetOrderStationLocation(StationID station);
 
	bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse);
 
	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(); }
src/train_cmd.cpp
Show inline comments
 
@@ -98,40 +98,40 @@ void TrainPowerChanged(Train *v)
 
			bool engine_has_power = HasPowerOnRail(u->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 */
 
					if (IsMultiheaded(u)) power /= 2;
 

	
 
					total_power += power;
 
					/* Tractive effort in (tonnes * 1000 * 10 =) N */
 
					max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
 
					max_te += (u->tcache.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
 
				}
 
			}
 
		}
 

	
 
		if (HasBit(u->flags, VRF_POWEREDWAGON) && HasPowerOnRail(v->railtype, railtype)) {
 
			total_power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
 
			total_power += RailVehInfo(u->tcache.first_engine)->pow_wag_power;
 
		}
 
	}
 

	
 
	if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
 
	if (v->tcache.cached_power != total_power || v->tcache.cached_max_te != max_te) {
 
		/* If it has no power (no catenary), stop the train */
 
		if (total_power == 0) v->vehstatus |= VS_STOPPED;
 

	
 
		v->u.rail.cached_power = total_power;
 
		v->u.rail.cached_max_te = max_te;
 
		v->tcache.cached_power = total_power;
 
		v->tcache.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(Train *v)
 
@@ -140,36 +140,36 @@ static void TrainCargoChanged(Train *v)
 

	
 
	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->flags, VRF_POWEREDWAGON)) {
 
			vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
 
			vweight += RailVehInfo(u->tcache.first_engine)->pow_wag_weight;
 
		}
 

	
 
		/* consist weight is the sum of the weight of all vehicles in the consist */
 
		weight += vweight;
 

	
 
		/* store vehicle weight in cache */
 
		u->u.rail.cached_veh_weight = vweight;
 
		u->tcache.cached_veh_weight = vweight;
 
	}
 

	
 
	/* store consist weight in cache */
 
	v->u.rail.cached_weight = weight;
 
	v->tcache.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 Train *u)
 
{
 
@@ -183,25 +183,25 @@ static void RailVehicleLengthChanged(con
 
}
 

	
 
/** 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 Train *u = (Train *)v, *w = (Train *)v->Next(); w != NULL; u = w, w = w->Next()) {
 
				if (u->track != TRACK_BIT_DEPOT) {
 
					if ((w->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) ||
 
							max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->tcache.cached_veh_length) ||
 
							(w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
 
						SetDParam(0, v->index);
 
						SetDParam(1, v->owner);
 
						ShowErrorMessage(INVALID_STRING_ID, STR_BROKEN_VEHICLE_LENGTH, 0, 0);
 

	
 
						if (!_networking) DoCommandP(0, PM_PAUSED_ERROR, 1, CMD_PAUSE);
 
					}
 
				}
 
			}
 
		}
 
	}
 
}
 
@@ -213,88 +213,88 @@ void CheckTrainsLengths()
 
 * @param v First vehicle of the chain.
 
 * @param same_length should length of vehicles stay the same?
 
 */
 
void TrainConsistChanged(Train *v, bool same_length)
 
{
 
	uint16 max_speed = UINT16_MAX;
 

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

	
 
	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->tcache.cached_total_length = 0;
 
	v->compatible_railtypes = RAILTYPES_NONE;
 

	
 
	bool train_can_tilt = true;
 

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

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

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

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

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

	
 
	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->tcache.user_def_data = GetVehicleProperty(u, 0x25, u->tcache.user_def_data);
 
		u->cache_valid = 0;
 
	}
 

	
 
	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);
 
		u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->tcache.first_engine);
 

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

	
 
		if (rvi_u->visual_effect != 0) {
 
			u->u.rail.cached_vis_effect = rvi_u->visual_effect;
 
			u->tcache.cached_vis_effect = rvi_u->visual_effect;
 
		} else {
 
			if (IsTrainWagon(u) || IsArticulatedPart(u)) {
 
				/* Wagons and articulated parts have no effect by default */
 
				u->u.rail.cached_vis_effect = 0x40;
 
				u->tcache.cached_vis_effect = 0x40;
 
			} else if (rvi_u->engclass == 0) {
 
				/* Steam is offset by -4 units */
 
				u->u.rail.cached_vis_effect = 4;
 
				u->tcache.cached_vis_effect = 4;
 
			} else {
 
				/* Diesel fumes and sparks come from the centre */
 
				u->u.rail.cached_vis_effect = 8;
 
				u->tcache.cached_vis_effect = 8;
 
			}
 
		}
 

	
 
		/* Check powered wagon / visual effect callback */
 
		if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) {
 
			uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
 

	
 
			if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8);
 
			if (callback != CALLBACK_FAILED) u->tcache.cached_vis_effect = GB(callback, 0, 8);
 
		}
 

	
 
		if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
 
			UsesWagonOverride(u) && !HasBit(u->u.rail.cached_vis_effect, 7)) {
 
			UsesWagonOverride(u) && !HasBit(u->tcache.cached_vis_effect, 7)) {
 
			/* wagon is powered */
 
			SetBit(u->flags, VRF_POWEREDWAGON); // cache 'powered' status
 
		} else {
 
			ClrBit(u->flags, VRF_POWEREDWAGON);
 
		}
 

	
 
		if (!IsArticulatedPart(u)) {
 
			/* Do not count powered wagons for the compatible railtypes, as wagons always
 
			   have railtype normal */
 
			if (rvi_u->power > 0) {
 
				v->compatible_railtypes |= GetRailTypeInfo(u->railtype)->powered_railtypes;
 
			}
 
@@ -318,36 +318,36 @@ void TrainConsistChanged(Train *v, bool 
 
			u->cargo_cap = GetVehicleProperty(u, 0x14, rvi_u->capacity);
 
		}
 

	
 
		/* check the vehicle length (callback) */
 
		uint16 veh_len = CALLBACK_FAILED;
 
		if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
 
			veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
 
		}
 
		if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
 
		veh_len = 8 - Clamp(veh_len, 0, 7);
 

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

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

	
 
		v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
 
		if (!same_length) u->tcache.cached_veh_length = veh_len;
 

	
 
		v->tcache.cached_total_length += u->tcache.cached_veh_length;
 
		u->cache_valid = 0;
 
	}
 

	
 
	/* store consist weight/max speed in cache */
 
	v->u.rail.cached_max_speed = max_speed;
 
	v->u.rail.cached_tilt = train_can_tilt;
 
	v->tcache.cached_max_speed = max_speed;
 
	v->tcache.cached_tilt = train_can_tilt;
 

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

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

	
 
enum AccelType {
 
	AM_ACCEL,
 
@@ -364,52 +364,52 @@ enum AccelType {
 
 * @param station_length 'return' the station length in 1/16th tiles
 
 * @return the location, calculated from the begin of the station to stop at.
 
 */
 
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length)
 
{
 
	const Station *st = Station::Get(station_id);
 
	*station_ahead  = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE;
 
	*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) {
 
	if (v->tcache.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) {
 
		osl = v->current_order.GetStopLocation();
 
	}
 

	
 
	/* The stop location of the FRONT! of the train */
 
	int stop;
 
	switch (osl) {
 
		default: NOT_REACHED();
 

	
 
		case OSL_PLATFORM_NEAR_END:
 
			stop = v->u.rail.cached_total_length;
 
			stop = v->tcache.cached_total_length;
 
			break;
 

	
 
		case OSL_PLATFORM_MIDDLE:
 
			stop = *station_length - (*station_length - v->u.rail.cached_total_length) / 2;
 
			stop = *station_length - (*station_length - v->tcache.cached_total_length) / 2;
 
			break;
 

	
 
		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;
 
	return stop - (v->tcache.cached_veh_length + 1) / 2;
 
}
 

	
 
/** new acceleration*/
 
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;
 
@@ -449,25 +449,25 @@ static int GetTrainAcceleration(Train *v
 
			max_speed = absolute_max_speed;
 
		} else if (total > 1) {
 
			if (numcurve > 0) sum /= numcurve;
 
			max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12));
 
		}
 
	}
 

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

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

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

	
 
@@ -480,61 +480,61 @@ static int GetTrainAcceleration(Train *v
 

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

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

	
 
	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 mass = v->tcache.cached_weight;
 
	int power = v->tcache.cached_power * 746;
 
	max_speed = min(max_speed, v->tcache.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 Train *u = v; u != NULL; u = u->Next()) {
 
		num++;
 
		drag_coeff += 3;
 

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

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

	
 
	v->max_speed = max_speed;
 

	
 
	const int area = 120;
 
	const int friction = 35; //[1e-3]
 
	int resistance;
 
	if (v->railtype != RAILTYPE_MAGLEV) {
 
		resistance = 13 * mass / 10;
 
		resistance += 60 * num;
 
		resistance += friction * mass * speed / 1000;
 
		resistance += (area * drag_coeff * speed * speed) / 10000;
 
	} else {
 
		resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
 
	}
 
	resistance += incl;
 
	resistance *= 4; //[N]
 

	
 
	const int max_te = v->u.rail.cached_max_te; // [N]
 
	const int max_te = v->tcache.cached_max_te; // [N]
 
	int force;
 
	if (speed > 0) {
 
		switch (v->railtype) {
 
			case RAILTYPE_RAIL:
 
			case RAILTYPE_ELECTRIC:
 
			case RAILTYPE_MONO:
 
				force = power / speed; //[N]
 
				force *= 22;
 
				force /= 10;
 
				if (mode == AM_ACCEL && force > max_te) force = max_te;
 
				break;
 

	
 
@@ -551,28 +551,28 @@ static int GetTrainAcceleration(Train *v
 

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

	
 
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;
 
	v->max_speed = v->tcache.cached_max_speed;
 

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

	
 
SpriteID Train::GetImage(Direction direction) const
 
{
 
	uint8 spritenum = this->spritenum;
 
	SpriteID sprite;
 

	
 
	if (HasBit(this->flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
 

	
 
	if (is_custom_sprite(spritenum)) {
 
@@ -1176,31 +1176,31 @@ CommandCost CmdMoveRailVehicle(TileIndex
 
		 */
 
		Train *dst_tail = dst_head;
 
		while (dst_tail->Next() != NULL) dst_tail = dst_tail->Next();
 

	
 
		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;
 
				EngineID first_engine = next_to_attach->tcache.first_engine;
 
				next_to_attach->tcache.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;
 
				next_to_attach->tcache.first_engine = first_engine;
 

	
 
				if (callback != CALLBACK_FAILED) {
 
					StringID error = STR_NULL;
 

	
 
					if (callback == 0xFD) error = STR_INCOMPATIBLE_RAIL_TYPES;
 
					if (callback < 0xFD) error = GetGRFStringID(GetEngineGRFID(dst_head->engine_type), 0xD000 + callback);
 

	
 
					if (error != STR_NULL) {
 
						/*
 
						 * The attaching is not allowed. In this case 'next_to_attach'
 
						 * can contain some vehicles of the 'source' and the destination
 
						 * train can have some too. We 'just' add the to-be added wagons
 
@@ -1576,27 +1576,27 @@ void Train::UpdateDeltaXY(Direction dire
 
	this->z_extent      = 6;
 
}
 

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

	
 
static inline void SetLastSpeed(Train *v, int spd)
 
{
 
	int old = v->u.rail.last_speed;
 
	int old = v->tcache.last_speed;
 
	if (spd != old) {
 
		v->u.rail.last_speed = spd;
 
		v->tcache.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(Train *v)
 
{
 
	if (!HasBit(v->flags, VRF_TRAIN_STUCK)) {
 
		/* It is the first time the problem occured, set the "train stuck" flag. */
 
		SetBit(v->flags, VRF_TRAIN_STUCK);
 
@@ -1781,25 +1781,25 @@ static inline void MaybeBarCrossingWithS
 
 */
 
static void AdvanceWagonsBeforeSwap(Train *v)
 
{
 
	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;
 
		int differential = base->tcache.cached_veh_length - last->tcache.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;
 
	}
 
}
 

	
 

	
 
/**
 
@@ -1841,25 +1841,25 @@ static void AdvanceWagonsAfterSwap(Train
 

	
 
	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 */
 
		if (last == dep) nomove = true;
 

	
 
		last = last->Previous();
 
		first = first->Next();
 

	
 
		int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
 
		int differential = last->tcache.cached_veh_length - base->tcache.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(Train *v)
 
{
 
@@ -2258,27 +2258,27 @@ static const int8 _vehicle_smoke_pos[8] 
 
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 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);
 
		int effect_offset = GB(v->tcache.cached_vis_effect, 0, 4) - 8;
 
		byte effect_type = GB(v->tcache.cached_vis_effect, 4, 2);
 
		bool disable_effect = HasBit(v->tcache.cached_vis_effect, 6);
 

	
 
		/* no smoke? */
 
		if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
 
				disable_effect ||
 
				v->vehstatus & VS_HIDDEN) {
 
			continue;
 
		}
 

	
 
		/* No smoke in depots or tunnels */
 
		if (IsRailDepotTile(v->tile) || IsTunnelTile(v->tile)) continue;
 

	
 
		/* No sparks for electric vehicles on nonelectrified tracks */
 
@@ -2385,25 +2385,25 @@ static void CheckNextTrainTile(Train *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 Train *u = v; u != NULL; u = u->Next()) {
 
		if (u->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) {
 
	if (v->tcache.cached_power == 0) {
 
		v->vehstatus |= VS_STOPPED;
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		return true;
 
	}
 

	
 
	SigSegState seg_state;
 

	
 
	if (v->force_proceed == 0) {
 
		/* force proceed was not pressed */
 
		if (++v->load_unload_time_rem < 37) {
 
			InvalidateWindowClasses(WC_TRAINS_LIST);
 
			return true;
 
@@ -4124,25 +4124,25 @@ static bool TrainApproachingLineEnd(Trai
 
	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;
 
		case DIR_SE: x = y;            break;
 
		case DIR_S : x = x + y - 7;    break;
 
		case DIR_W : x = ~y + x + 9;   break;
 
		default: break;
 
	}
 

	
 
	/* do not reverse when approaching red signal */
 
	if (!signal && x + (v->u.rail.cached_veh_length + 1) / 2 >= TILE_SIZE) {
 
	if (!signal && x + (v->tcache.cached_veh_length + 1) / 2 >= TILE_SIZE) {
 
		/* we are too near the tile end, reverse now */
 
		v->cur_speed = 0;
 
		ReverseTrainDirection(v);
 
		return false;
 
	}
 

	
 
	/* slow down */
 
	v->vehstatus |= VS_TRAIN_SLOWING;
 
	uint16 break_speed = _breakdown_speeds[x & 0xF];
 
	if (break_speed < v->cur_speed) v->cur_speed = break_speed;
 

	
 
	return true;
 
@@ -4344,25 +4344,25 @@ static bool TrainLocoHandler(Train *v, b
 
		}
 
	}
 

	
 
	if (v->current_order.IsType(OT_LEAVESTATION)) {
 
		v->current_order.Free();
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		return true;
 
	}
 

	
 
	int j = UpdateTrainSpeed(v);
 

	
 
	/* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
 
	if (v->cur_speed == 0 && v->u.rail.last_speed == 0 && v->vehstatus & VS_STOPPED) {
 
	if (v->cur_speed == 0 && v->tcache.last_speed == 0 && v->vehstatus & VS_STOPPED) {
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
	}
 

	
 
	int adv_spd = (v->direction & 1) ? 192 : 256;
 
	if (j < adv_spd) {
 
		/* if the vehicle has speed 0, update the last_speed field. */
 
		if (v->cur_speed == 0) SetLastSpeed(v, v->cur_speed);
 
	} else {
 
		TrainCheckIfLineEnds(v);
 
		/* Loop until the train has finished moving. */
 
		for (;;) {
 
			j -= adv_spd;
src/train_gui.cpp
Show inline comments
 
@@ -72,25 +72,25 @@ void DrawTrainImage(const Vehicle *v, in
 
	/* Position of highlight box */
 
	int highlight_l = 0;
 
	int highlight_r = 0;
 

	
 
	if (!FillDrawPixelInfo(&tmp_dpi, x - 2, y - 1, count + 1, 14)) return;
 

	
 
	count = (count * 8) / _traininfo_vehicle_width;
 

	
 
	old_dpi = _cur_dpi;
 
	_cur_dpi = &tmp_dpi;
 

	
 
	do {
 
		int width = v->u.rail.cached_veh_length;
 
		int width = ((Train *)v)->tcache.cached_veh_length;
 

	
 
		if (dx + width > 0) {
 
			if (dx <= count) {
 
				SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 
				DrawSprite(v->GetImage(DIR_W), pal, 16 + WagonLengthToPixels(dx), 7 + (is_custom_sprite(RailVehInfo(v->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
 
				if (v->index == selection) {
 
					/* Set the highlight position */
 
					highlight_l = WagonLengthToPixels(dx) + 1;
 
					highlight_r = WagonLengthToPixels(dx + width) + 1;
 
				} else if (_cursor.vehchain && highlight_r != 0) {
 
					highlight_r += WagonLengthToPixels(width);
 
				}
 
@@ -219,25 +219,25 @@ void DrawTrainDetails(const Vehicle *v, 
 
	/* draw the first 3 details tabs */
 
	if (det_tab != 3) {
 
		const Vehicle *u = v;
 
		int x = 1;
 
		for (;;) {
 
			if (--vscroll_pos < 0 && vscroll_pos >= -vscroll_cap) {
 
				int dx = 0;
 

	
 
				u = v;
 
				do {
 
					SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 
					DrawSprite(u->GetImage(DIR_W), pal, x + WagonLengthToPixels(4 + dx), y + 6 + (is_custom_sprite(RailVehInfo(u->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
 
					dx += u->u.rail.cached_veh_length;
 
					dx += ((Train *)u)->tcache.cached_veh_length;
 
					u = u->Next();
 
				} while (u != NULL && IsArticulatedPart(u) && u->cargo_cap == 0);
 

	
 
				int px = x + WagonLengthToPixels(dx) + 2;
 
				int py = y + 2;
 
				switch (det_tab) {
 
					default: NOT_REACHED();
 
					case 0: TrainDetailsCargoTab(   v, px, right, py); break;
 
					case 1:
 
						/* Only show name and value for the 'real' part */
 
						if (!IsArticulatedPart(v)) {
 
							TrainDetailsInfoTab(v, px, right, py);
src/vehicle.cpp
Show inline comments
 
@@ -1415,25 +1415,25 @@ static SpriteID GetEngineColourMap(Engin
 
	if (v != NULL) ((Vehicle*)v)->colourmap = map;
 
	return map;
 
}
 

	
 
SpriteID GetEnginePalette(EngineID engine_type, CompanyID company)
 
{
 
	return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL);
 
}
 

	
 
SpriteID GetVehiclePalette(const Vehicle *v)
 
{
 
	if (v->type == VEH_TRAIN) {
 
		return GetEngineColourMap(v->engine_type, v->owner, v->u.rail.first_engine, v);
 
		return GetEngineColourMap(v->engine_type, v->owner, ((Train *)v)->tcache.first_engine, v);
 
	} else if (v->type == VEH_ROAD) {
 
		return GetEngineColourMap(v->engine_type, v->owner, ((RoadVehicle *)v)->first_engine, v);
 
	}
 

	
 
	return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
 
}
 

	
 

	
 
void Vehicle::BeginLoading()
 
{
 
	assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
 

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

	
 
/** @file  vehicle_base.h Base class for all vehicles. */
 

	
 
#ifndef VEHICLE_BASE_H
 
#define VEHICLE_BASE_H
 

	
 
#include "vehicle_type.h"
 
#include "track_type.h"
 
#include "rail_type.h"
 
#include "cargo_type.h"
 
#include "direction_type.h"
 
#include "gfx_type.h"
 
#include "command_type.h"
 
#include "date_type.h"
 
#include "company_base.h"
 
#include "company_type.h"
 
#include "core/pool_type.hpp"
 
#include "order_base.h"
 
#include "cargopacket.h"
 
#include "texteff.hpp"
 
#include "group_type.h"
 
@@ -35,57 +34,24 @@ enum VehStatus {
 
	VS_CRASHED         = 0x80,
 
};
 

	
 
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 {
 
	/* Cached wagon override spritegroup */
 
	const struct SpriteGroup *cached_override;
 

	
 
	uint16 last_speed; // NOSAVE: only used in UI
 

	
 
	/* 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
 
	bool cached_tilt;           ///< train can tilt; feature provides a bonus in curves
 

	
 
	/* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
 
	uint32 cached_weight;     ///< total weight of the consist.
 
	uint32 cached_veh_weight; ///< weight of the vehicle.
 
	uint32 cached_max_te;     ///< max tractive effort of consist
 

	
 
	/**
 
	 * Position/type of visual effect.
 
	 * bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear)
 
	 * bit 4 - 5 = type of effect. (0 = default for engine class, 1 = steam, 2 = diesel, 3 = electric)
 
	 * bit     6 = disable visual effect.
 
	 * bit     7 = disable powered wagons.
 
	 */
 
	byte cached_vis_effect;
 
	byte user_def_data;
 

	
 
	/* NOSAVE: for wagon override - id of the first engine in train
 
	 * 0xffff == not in train */
 
	EngineID first_engine;
 
};
 

	
 
typedef Pool<Vehicle, VehicleID, 512, 64000> VehiclePool;
 
extern VehiclePool _vehicle_pool;
 

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

	
 
struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle {
 
@@ -195,28 +161,24 @@ public:
 
	union {
 
		OrderList *list;              ///< Pointer to the order list for this vehicle
 
		Order     *old;               ///< Only used during conversion of old save games
 
	} orders;
 

	
 
	byte vehicle_flags;             ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
 
	uint16 load_unload_time_rem;
 

	
 
	GroupID group_id;               ///< Index of group Pool array
 

	
 
	byte subtype;                   ///< subtype (Filled with values from EffectVehicles/TrainSubTypes/AircraftSubTypes)
 

	
 
	union {
 
		VehicleRail rail;
 
	} u;
 

	
 
	/* cached oftenly queried NewGRF values */
 
	uint8 cache_valid;   ///< Whether the caches are valid
 
	uint32 cached_var40; ///< Cache for NewGRF var 40
 
	uint32 cached_var41; ///< Cache for NewGRF var 41
 
	uint32 cached_var42; ///< Cache for NewGRF var 42
 
	uint32 cached_var43; ///< Cache for NewGRF var 43
 

	
 
	/** Create a new vehicle */
 
	Vehicle();
 

	
 
	/** Destroy all stuff that (still) needs the virtual functions to work properly */
 
	void PreDestructor();
src/vehicle_cmd.cpp
Show inline comments
 
@@ -58,25 +58,25 @@ const uint32 _send_to_depot_proc_table[]
 
 * @return result of operation.  Nothing if everything went well
 
 */
 
CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	/* Disable the effect of p2 bit 0, when DC_AUTOREPLACE is not set */
 
	if ((flags & DC_AUTOREPLACE) == 0) SetBit(p2, 0);
 

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

	
 
	switch (v->type) {
 
		case VEH_TRAIN:
 
			if (v->vehstatus & VS_STOPPED && v->u.rail.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
 
			if (v->vehstatus & VS_STOPPED && ((Train *)v)->tcache.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
 
			break;
 

	
 
		case VEH_SHIP:
 
		case VEH_ROAD:
 
			break;
 

	
 
		case VEH_AIRCRAFT: {
 
			Aircraft *a = (Aircraft *)v;
 
			/* cannot stop airplane when in flight, or when taking off / landing */
 
			if (a->state >= STARTTAKEOFF && a->state < TERM7) return_cmd_error(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT);
 
		} break;
 

	
src/vehicle_gui.cpp
Show inline comments
 
@@ -594,25 +594,25 @@ static int CDECL VehicleCargoSorter(cons
 
/** Sort vehicles by their reliability */
 
static int CDECL VehicleReliabilitySorter(const Vehicle * const *a, const Vehicle * const *b)
 
{
 
	int r = (*a)->reliability - (*b)->reliability;
 
	return (r != 0) ? r : VehicleNumberSorter(a, b);
 
}
 

	
 
/** Sort vehicles by their max speed */
 
static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle * const *b)
 
{
 
	int r = 0;
 
	if ((*a)->type == VEH_TRAIN && (*b)->type == VEH_TRAIN) {
 
		r = (*a)->u.rail.cached_max_speed - (*b)->u.rail.cached_max_speed;
 
		r = ((const Train *)(*a))->tcache.cached_max_speed - ((const Train *)(*b))->tcache.cached_max_speed;
 
	} else {
 
		r = (*a)->max_speed - (*b)->max_speed;
 
	}
 
	return (r != 0) ? r : VehicleNumberSorter(a, b);
 
}
 

	
 
/** Sort vehicles by model */
 
static int CDECL VehicleModelSorter(const Vehicle * const *a, const Vehicle * const *b)
 
{
 
	int r = (*a)->engine_type - (*b)->engine_type;
 
	return (r != 0) ? r : VehicleNumberSorter(a, b);
 
}
 
@@ -627,25 +627,25 @@ static int CDECL VehicleValueSorter(cons
 
	for (u = *b; u != NULL; u = u->Next()) diff -= u->value;
 

	
 
	int r = ClampToI32(diff);
 
	return (r != 0) ? r : VehicleNumberSorter(a, b);
 
}
 

	
 
/** Sort vehicles by their length */
 
static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * const *b)
 
{
 
	int r = 0;
 
	switch ((*a)->type) {
 
		case VEH_TRAIN:
 
			r = (*a)->u.rail.cached_total_length - (*b)->u.rail.cached_total_length;
 
			r = ((const Train *)(*a))->tcache.cached_total_length - ((const Train *)(*b))->tcache.cached_total_length;
 
			break;
 

	
 
		case VEH_ROAD: {
 
			const RoadVehicle *u;
 
			for (u = (RoadVehicle *)*a; u != NULL; u = u->Next()) r += u->cached_veh_length;
 
			for (u = (RoadVehicle *)*b; u != NULL; u = u->Next()) r -= u->cached_veh_length;
 
		} break;
 

	
 
		default: NOT_REACHED();
 
	}
 
	return (r != 0) ? r : VehicleNumberSorter(a, b);
 
}
 
@@ -1457,27 +1457,27 @@ struct VehicleDetailsWindow : Window {
 

	
 
		/* Draw running cost */
 
		SetDParam(1, v->age / DAYS_IN_LEAP_YEAR);
 
		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);
 
				SetDParam(1, ((Train *)v)->tcache.cached_power);
 
				SetDParam(0, ((Train *)v)->tcache.cached_weight);
 
				SetDParam(3, ((Train *)v)->tcache.cached_max_te / 1000);
 
				DrawString(2, this->width - 2, 25, (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && ((Train *)v)->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;
 

	
 
@@ -1928,25 +1928,25 @@ struct VehicleViewWindow : Window {
 

	
 
		/* draw widgets & caption */
 
		SetDParam(0, v->index);
 
		this->DrawWidgets();
 

	
 
		if (v->vehstatus & VS_CRASHED) {
 
			str = STR_VEHICLE_STATUS_CRASHED;
 
		} else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
 
			str = STR_VEHICLE_STATUS_BROKEN_DOWN;
 
		} else if (v->vehstatus & VS_STOPPED) {
 
			if (v->type == VEH_TRAIN) {
 
				if (v->cur_speed == 0) {
 
					if (v->u.rail.cached_power == 0) {
 
					if (((Train *)v)->tcache.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(((Train *)v)->flags, VRF_TRAIN_STUCK)) {
src/yapf/yapf_costrail.hpp
Show inline comments
 
@@ -238,26 +238,26 @@ public:
 
				}
 
			}
 
		}
 
		return cost;
 
	}
 

	
 
	FORCEINLINE int PlatformLengthPenalty(int platform_length)
 
	{
 
		int cost = 0;
 
		const Vehicle *v = Yapf().GetVehicle();
 
		assert(v != NULL);
 
		assert(v->type == VEH_TRAIN);
 
		assert(v->u.rail.cached_total_length != 0);
 
		int missing_platform_length = (v->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE - platform_length;
 
		assert(((Train *)v)->tcache.cached_total_length != 0);
 
		int missing_platform_length = (((Train *)v)->tcache.cached_total_length + TILE_SIZE - 1) / TILE_SIZE - platform_length;
 
		if (missing_platform_length < 0) {
 
			/* apply penalty for longer platform than needed */
 
			cost += Yapf().PfGetSettings().rail_longer_platform_penalty + Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
 
		} else if (missing_platform_length > 0) {
 
			/* apply penalty for shorter platform than needed */
 
			cost += Yapf().PfGetSettings().rail_shorter_platform_penalty + Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length;
 
		}
 
		return cost;
 
	}
 

	
 
public:
 
	FORCEINLINE void SetMaxCost(int max_cost)
0 comments (0 inline, 0 general)