Changeset - r14276:fe74de3c3311
[Not reviewed]
master
0 4 0
rubidium - 14 years ago 2010-01-16 22:30:04
rubidium@openttd.org
(svn r18838) -Codechange [FS#3524]: reorganisation of the train acceleration code plus some minor optimisations (Terkhen)
4 files changed with 234 insertions and 111 deletions:
0 comments (0 inline, 0 general)
src/settings.cpp
Show inline comments
 
@@ -745,6 +745,21 @@ static bool TrainAccelerationModelChange
 
	return true;
 
}
 

	
 
/**
 
 * This function updates the train acceleration cache after a steepness change.
 
 * @param p1 Callback parameter.
 
 * @return Always true.
 
 */
 
static bool TrainSlopeSteepnessChanged(int32 p1)
 
{
 
	Train *t;
 
	FOR_ALL_TRAINS(t) {
 
		if (t->IsFrontEngine()) t->CargoChanged();
 
	}
 

	
 
	return true;
 
}
 

	
 
static bool DragSignalsDensityChanged(int32)
 
{
 
	InvalidateWindowData(WC_BUILD_SIGNAL, 0);
src/table/settings.h
Show inline comments
 
@@ -22,6 +22,7 @@ static bool DeleteSelectStationWindow(in
 
static bool UpdateConsists(int32 p1);
 
static bool CheckInterval(int32 p1);
 
static bool TrainAccelerationModelChanged(int32 p1);
 
static bool TrainSlopeSteepnessChanged(int32 p1);
 
static bool DragSignalsDensityChanged(int32);
 
static bool TownFoundingChanged(int32 p1);
 
static bool DifficultyReset(int32 level);
 
@@ -372,7 +373,7 @@ const SettingDesc _settings[] = {
 
	 SDT_CONDVAR(GameSettings, economy.found_town,                   SLE_UINT8,128, SL_MAX_VERSION, 0,MS,TF_FORBIDDEN,TF_BEGIN,TF_END - 1, 1, STR_CONFIG_SETTING_TOWN_FOUNDING, TownFoundingChanged),
 

	
 
	     SDT_VAR(GameSettings, vehicle.train_acceleration_model,     SLE_UINT8,                     0,MS,     0,     0,       1, 1, STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL, TrainAccelerationModelChanged),
 
	 SDT_CONDVAR(GameSettings, vehicle.train_slope_steepness,        SLE_UINT8,133, SL_MAX_VERSION, 0, 0,     3,     0,      10, 1, STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS,  NULL),
 
	 SDT_CONDVAR(GameSettings, vehicle.train_slope_steepness,        SLE_UINT8,133, SL_MAX_VERSION, 0, 0,     3,     0,      10, 1, STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS,  TrainSlopeSteepnessChanged),
 
	    SDT_BOOL(GameSettings, pf.forbid_90_deg,                                                    0, 0, false,                    STR_CONFIG_SETTING_FORBID_90_DEG,          NULL),
 
	    SDT_BOOL(GameSettings, vehicle.mammoth_trains,                                              0,NN,  true,                    STR_CONFIG_SETTING_MAMMOTHTRAINS,          NULL),
 
	    SDT_BOOL(GameSettings, order.gotodepot,                                                     0, 0,  true,                    STR_CONFIG_SETTING_GOTODEPOT,              NULL),
src/train.h
Show inline comments
 
@@ -13,6 +13,11 @@
 
#define TRAIN_H
 

	
 
#include "vehicle_base.h"
 
#include "newgrf_engine.h"
 
#include "cargotype.h"
 
#include "rail.h"
 
#include "engine_base.h"
 
#include "rail_map.h"
 

	
 
struct Train;
 

	
 
@@ -59,15 +64,17 @@ struct TrainCache {
 
	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_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
 
	uint32 cached_power;            ///< total power of the consist.
 
	uint16 cached_axle_resistance;  ///< Resistance caused by the axles of the vehicle
 
	uint32 cached_air_drag;         ///< Air drag coefficient of the vehicle
 
	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
 
	uint32 cached_weight;           ///< total weight of the consist.
 
	uint32 cached_slope_resistance; ///< Resistance caused by weight when this vehicle part is at a slope
 
	uint32 cached_max_te;           ///< max tractive effort of consist
 

	
 
	/* cached max. speed / acceleration data */
 
	uint16 cached_max_speed;    ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist)
 
@@ -86,6 +93,12 @@ struct TrainCache {
 
	EngineID first_engine;  ///< cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself.
 
};
 

	
 
/** What type of acceleration should we do? */
 
enum AccelType {
 
	AM_ACCEL, ///< We want to go faster, if possible ofcourse
 
	AM_BRAKE  ///< We want to stop
 
};
 

	
 
/**
 
 * 'Train' is either a loco or a wagon.
 
 */
 
@@ -143,6 +156,9 @@ struct Train : public SpecializedVehicle
 

	
 
	void UpdateAcceleration();
 

	
 
	int GetCurrentMaxSpeed() const;
 
	int GetAcceleration() const;
 

	
 
	/**
 
	 * enum to handle train subtypes
 
	 * Do not access it directly unless you have to. Use the access functions below
 
@@ -360,6 +376,124 @@ struct Train : public SpecializedVehicle
 

	
 
		return v;
 
	}
 

	
 

	
 
protected: /* These functions should not be called outside acceleration code. */
 

	
 
	/**
 
	 * Allows to know the power value that this vehicle will use.
 
	 * @return Power value from the engine in HP, or zero if the vehicle is not powered.
 
	 */
 
	FORCEINLINE uint16 GetPower() const
 
	{
 
		/* Power is not added for articulated parts */
 
		if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
 
			uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
 
			/* Halve power for multiheaded parts */
 
			if (this->IsMultiheaded()) power /= 2;
 
			return power;
 
		}
 

	
 
		return 0;
 
	}
 

	
 
	/**
 
	 * Returns a value if this articulated part is powered.
 
	 * @return Power value from the articulated part in HP, or zero if it is not powered.
 
	 */
 
	FORCEINLINE uint16 GetPoweredPartPower(const Train *head) const
 
	{
 
		if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(head->tile))) {
 
			return RailVehInfo(this->tcache.first_engine)->pow_wag_power;
 
		}
 

	
 
		return 0;
 
	}
 

	
 
	/**
 
	 * Allows to know the weight value that this vehicle will use.
 
	 * @return Weight value from the engine in tonnes.
 
	 */
 
	FORCEINLINE uint16 GetWeight() const
 
	{
 
		uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.Count() * FreightWagonMult(this->cargo_type)) / 16;
 

	
 
		/* Vehicle weight is not added for articulated parts. */
 
		if (!this->IsArticulatedPart()) {
 
			weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight);
 
		}
 

	
 
		/* Powered wagons have extra weight added. */
 
		if (HasBit(this->flags, VRF_POWEREDWAGON)) {
 
			weight += RailVehInfo(this->tcache.first_engine)->pow_wag_weight;
 
		}
 

	
 
		return weight;
 
	}
 

	
 
	/**
 
	 * Allows to know the tractive effort value that this vehicle will use.
 
	 * @return Tractive effort value from the engine.
 
	 */
 
	FORCEINLINE byte GetTractiveEffort() const
 
	{
 
		return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort);
 
	}
 

	
 
	/**
 
	 * Checks the current acceleration status of this vehicle.
 
	 * @return Acceleration status.
 
	 */
 
	FORCEINLINE AccelType GetAccelerationStatus() const
 
	{
 
		return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AM_BRAKE : AM_ACCEL;
 
	}
 

	
 
	/**
 
	 * Calculates the current speed of this vehicle.
 
	 * @return Current speed in mph.
 
	 */
 
	FORCEINLINE uint16 GetCurrentSpeed() const
 
	{
 
		return this->cur_speed * 10 / 16;
 
	}
 

	
 
	/**
 
	 * Returns the rolling friction coefficient of this vehicle.
 
	 * @return Rolling friction coefficient in [1e-3].
 
	 */
 
	FORCEINLINE uint32 GetRollingFriction() const
 
	{
 
		return 35;
 
	}
 

	
 
	/**
 
	 * Calculates the total slope resistance for this vehicle.
 
	 * @return Slope resistance.
 
	 */
 
	FORCEINLINE int32 GetSlopeResistance() const
 
	{
 
		int32 incl = 0;
 

	
 
		for (const Train *u = this; u != NULL; u = u->Next()) {
 
			if (HasBit(u->flags, VRF_GOINGUP)) {
 
				incl += u->tcache.cached_slope_resistance;
 
			} else if (HasBit(u->flags, VRF_GOINGDOWN)) {
 
				incl -= u->tcache.cached_slope_resistance;
 
			}
 
		}
 

	
 
		return incl;
 
	}
 

	
 
	/**
 
	 * Allows to know the acceleration type of a vehicle.
 
	 * @return Acceleration type of the vehicle.
 
	 */
 
	FORCEINLINE int GetAccelerationType() const
 
	{
 
		return GetRailTypeInfo(this->railtype)->acceleration_type;
 
	}
 
};
 

	
 
#define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var)
src/train_cmd.cpp
Show inline comments
 
@@ -98,36 +98,25 @@ void Train::PowerChanged()
 

	
 
	uint32 total_power = 0;
 
	uint32 max_te = 0;
 
	uint32 number_of_parts = 0;
 

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

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

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

	
 
			if (engine_has_power) {
 
				uint16 power = GetVehicleProperty(u, PROP_TRAIN_POWER, rvi_u->power);
 
				if (power != 0) {
 
					/* Halve power for multiheaded parts */
 
					if (u->IsMultiheaded()) power /= 2;
 

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

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

	
 
		/* Only powered parts add tractive effort */
 
		if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort();
 
		total_power += u->GetPoweredPartPower(this);
 
		number_of_parts++;
 
	}
 

	
 
	this->tcache.cached_axle_resistance = 60 * number_of_parts;
 
	this->tcache.cached_air_drag = 20 + 3 * number_of_parts;
 

	
 
	max_te *= 10000; // Tractive effort in (tonnes * 1000 * 10 =) N
 
	max_te /= 256;   // Tractive effort is a [0-255] coefficient
 
	if (this->tcache.cached_power != total_power || this->tcache.cached_max_te != max_te) {
 
		/* If it has no power (no catenary), stop the train */
 
		/* Stop the vehicle if it has no power */
 
		if (total_power == 0) this->vehstatus |= VS_STOPPED;
 

	
 
		this->tcache.cached_power = total_power;
 
@@ -148,24 +137,9 @@ void Train::CargoChanged()
 
	uint32 weight = 0;
 

	
 
	for (Train *u = this; u != NULL; u = u->Next()) {
 
		uint32 vweight = CargoSpec::Get(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16;
 

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

	
 
		/* powered wagons have extra weight added */
 
		if (HasBit(u->flags, VRF_POWEREDWAGON)) {
 
			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->tcache.cached_veh_weight = vweight;
 
		uint32 current_weight = u->GetWeight();
 
		weight += current_weight;
 
		u->tcache.cached_slope_resistance = current_weight * 20 * _settings_game.vehicle.train_slope_steepness; //1% slope * slope steepness
 
	}
 

	
 
	/* store consist weight in cache */
 
@@ -357,11 +331,6 @@ void Train::ConsistChanged(bool same_len
 
	}
 
}
 

	
 
enum AccelType {
 
	AM_ACCEL,
 
	AM_BRAKE
 
};
 

	
 
/**
 
 * Get the stop location of (the center) of the front vehicle of a train at
 
 * a platform of a station.
 
@@ -481,19 +450,21 @@ int Train::GetCurveSpeedLimit() const
 
	return max_speed;
 
}
 

	
 
/** new acceleration*/
 
static int GetTrainAcceleration(Train *v, bool mode)
 
/**
 
 * Calculates the maximum speed of the vehicle under its current conditions.
 
 * @return Maximum speed of the vehicle.
 
 */
 
int Train::GetCurrentMaxSpeed() const
 
{
 
	int max_speed = v->tcache.cached_max_curve_speed;
 
	assert(max_speed == v->GetCurveSpeedLimit());
 
	int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
 

	
 
	if (IsRailStationTile(v->tile) && v->IsFrontEngine()) {
 
		StationID sid = GetStationIndex(v->tile);
 
		if (v->current_order.ShouldStopAtStation(v, sid)) {
 
	int max_speed = this->tcache.cached_max_curve_speed;
 
	assert(max_speed == this->GetCurveSpeedLimit());
 

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

	
 
			/* The distance to go is whatever is still ahead of the train minus the
 
			 * distance from the train's stop location to the end of the platform */
 
@@ -502,9 +473,9 @@ static int GetTrainAcceleration(Train *v
 
			if (distance_to_go > 0) {
 
				int st_max_speed = 120;
 

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

	
 
				st_max_speed = max(st_max_speed, 25 * distance_to_go);
 
@@ -513,45 +484,52 @@ static int GetTrainAcceleration(Train *v
 
		}
 
	}
 

	
 
	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->tcache.cached_veh_weight * 20 * _settings_game.vehicle.train_slope_steepness;
 
		} else if (HasBit(u->flags, VRF_GOINGDOWN)) {
 
			incl -= u->tcache.cached_veh_weight * 20 * _settings_game.vehicle.train_slope_steepness;
 
	for (const Train *u = this; u != NULL; u = u->Next()) {
 
		if (u->track == TRACK_BIT_DEPOT) {
 
			max_speed = min(max_speed, 61);
 
			break;
 
		}
 
	}
 

	
 
	v->max_speed = max_speed;
 

	
 
	bool maglev = GetRailTypeInfo(v->railtype)->acceleration_type == 2;
 
	return min(max_speed, this->tcache.cached_max_speed);
 
}
 

	
 
/**
 
 * Calculates the acceleration of the vehicle under its current conditions.
 
 * @return Current acceleration of the vehicle.
 
 */
 

	
 
int Train::GetAcceleration() const
 
{
 
	int32 speed = this->GetCurrentSpeed();
 

	
 
	/* Weight is stored in tonnes */
 
	int32 mass = this->tcache.cached_weight;
 

	
 
	/* Power is stored in HP, we need it in watts. */
 
	int32 power = this->tcache.cached_power * 746;
 

	
 
	int32 resistance = 0;
 

	
 
	bool maglev = this->GetAccelerationType() == 2;
 

	
 
	const int area = 120;
 
	const int friction = 35; //[1e-3]
 
	int resistance;
 
	if (!maglev) {
 
		resistance = 13 * mass / 10;
 
		resistance += 60 * num;
 
		resistance += friction * mass * speed / 1000;
 
		resistance += (area * drag_coeff * speed * speed) / 10000;
 
		resistance = (13 * mass) / 10;
 
		resistance += this->tcache.cached_axle_resistance;
 
		resistance += (this->GetRollingFriction() * mass * speed) / 1000;
 
		resistance += (area * this->tcache.cached_air_drag * speed * speed) / 10000;
 
	} else {
 
		resistance = (area * (drag_coeff / 2) * speed * speed) / 10000;
 
		resistance += (area * this->tcache.cached_air_drag * speed * speed) / 20000;
 
	}
 
	resistance += incl;
 

	
 
	resistance += this->GetSlopeResistance();
 
	resistance *= 4; //[N]
 

	
 
	const int max_te = v->tcache.cached_max_te; // [N]
 
	/* This value allows to know if the vehicle is accelerating or braking. */
 
	AccelType mode = this->GetAccelerationStatus();
 

	
 
	const int max_te = this->tcache.cached_max_te; // [N]
 
	int force;
 
	if (speed > 0) {
 
		if (!maglev) {
 
@@ -2961,19 +2939,14 @@ int Train::UpdateSpeed()
 
{
 
	uint accel;
 

	
 
	if ((this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK)) {
 
		switch (_settings_game.vehicle.train_acceleration_model) {
 
			default: NOT_REACHED();
 
			case TAM_ORIGINAL:  accel = this->acceleration * -4; break;
 
			case TAM_REALISTIC: accel = GetTrainAcceleration(this, AM_BRAKE); break;
 
		}
 
	} else {
 
		switch (_settings_game.vehicle.train_acceleration_model) {
 
			default: NOT_REACHED();
 
			case TAM_ORIGINAL:  accel = this->acceleration * 2; break;
 
			case TAM_REALISTIC: accel = GetTrainAcceleration(this, AM_ACCEL); break;
 
		}
 
	}
 
	switch (_settings_game.vehicle.train_acceleration_model) {
 
		default: NOT_REACHED();
 
		case TAM_ORIGINAL: accel = this->acceleration * (this->GetAccelerationStatus() == AM_BRAKE) ? -4 : 2; break;
 
		case TAM_REALISTIC:
 
			this->max_speed = this->GetCurrentMaxSpeed();
 
			accel = this->GetAcceleration();
 
			break;
 
 	}
 

	
 
	uint spd = this->subspeed + accel;
 
	this->subspeed = (byte)spd;
0 comments (0 inline, 0 general)