Changeset - r1179:50ae3d039937
[Not reviewed]
master
0 3 0
celestar - 19 years ago 2005-01-26 12:51:04
celestar@openttd.org
(svn r1681) -Feature: New realistic acceleration.
This will make things more difficult as narrow curves
and depots impose rather strict speed limits. Feedback welcome
For those who don't like low-speed curves: Switch it off
3 files changed with 231 insertions and 91 deletions:
0 comments (0 inline, 0 general)
train_cmd.c
Show inline comments
 
@@ -34,6 +34,200 @@ static const byte _signal_otherdir[14] =
 
	0x80, 0x80, 0x80, 0x20, 0x40, 0x10
 
};
 

	
 
static const byte _curve_neighbours45[8][2] = {
 
	{7, 1},
 
	{0, 2},
 
	{1, 3},
 
	{2, 4},
 
	{3, 5},
 
	{4, 6},
 
	{5, 7},
 
	{6, 0},
 
};
 

	
 
static const byte _curve_neighbours90[8][2] = {
 
	{6, 2},
 
	{7, 3},
 
	{0, 4},
 
	{1, 5},
 
	{2, 6},
 
	{3, 7},
 
	{4, 0},
 
	{5, 1},
 
};
 

	
 
enum AccelType {
 
	AM_ACCEL,
 
	AM_BRAKE
 
};
 

	
 
//new acceleration
 
static int GetTrainAcceleration(Vehicle *v, bool mode)
 
{
 
	Vehicle *u = v;
 
	int num = 0;	//number of vehicles, change this into the number of axles later
 
	int power = 0;
 
	int mass = 0;
 
	int max_speed = 2000;
 
	int area = 120;
 
	int friction = 35; //[1e-3]
 
	int drag_coeff = 20;	//[1e-4]
 
	int incl = 0;
 
	int resistance;
 
	int speed = v->cur_speed; //[mph]
 
	int force = 0x3FFFFFFF;
 
	int pos = 0;
 
	int lastpos = -1;
 
	int curvecount[2] = {0, 0};
 
	int *dist = NULL;
 
	int sum = 0;
 
	int numcurve = 0;
 
	int i;
 

	
 
	speed *= 10;
 
	speed /= 16;
 

	
 
	//first find the curve speed limit
 
	for (; u->next != NULL; u = u->next, pos++) {
 
		int dir = u->direction;
 
		int ndir = u->next->direction;
 

	
 
		for (i = 0; i < 2; i++) {
 
			if ( _curve_neighbours45[dir][i] == ndir) {
 
				curvecount[i]++;
 
				if (lastpos != -1) {
 
					dist = realloc(dist, sizeof(int) * ++numcurve);
 
					dist[numcurve - 1] = pos - lastpos;
 
					if (pos - lastpos == 1) {
 
						max_speed = 88;
 
					}
 
				}
 
				lastpos = pos;
 
			}
 
		}
 

	
 
		//if we have a 90 degree turn, fix the speed limit to 60
 
		if ( _curve_neighbours90[dir][0] == ndir || _curve_neighbours90[dir][1] == ndir) {
 
			max_speed = 61;
 
		}
 
	}
 

	
 
	for(i = 0; i < numcurve; i++) {
 
		sum += dist[i];
 
	}
 

	
 
	if (numcurve > 0) {
 
		sum /= numcurve;
 
	}
 

	
 
	if ((curvecount[0] != 0 || curvecount[1] != 0) && (max_speed > 88)) {
 
		int total = curvecount[0] + curvecount[1];
 
		if (curvecount[0] == 1 && curvecount[1] == 1) {
 
			max_speed = 0xFFFF;
 
		} else if (total > 1) {
 
			max_speed = 232 - (13 - clamp(sum, 1, 12)) * (13 - clamp(sum, 1, 12));
 
		}
 
	}
 

	
 
	max_speed += (max_speed / 2) * v->u.rail.railtype;
 

	
 
	if (IsTileType(v->tile, MP_STATION) && v->subtype == TS_Front_Engine) {
 
		static const TileIndexDiffC _station_dir_from_vdir[] = {
 
			{0, 0}, {-1, 0}, {0, 0}, {0, 1}, {0, 0}, {1, 0}, {0, 0}, {0, -1}
 
		};
 

	
 
		if (((v->current_order.station == _map2[v->tile]) || !(v->current_order.flags & OF_NON_STOP)) && v->last_station_visited != _map2[v->tile]) {
 
			int station_length = 0;
 
			TileIndex tile = v->tile;
 
			int delta_v;
 

	
 
			max_speed = 120;
 
			do {
 
				station_length++;
 
				tile = TILE_ADD(tile, ToTileIndexDiff(_station_dir_from_vdir[v->direction]));
 
			} while (IsTileType(tile, MP_STATION));
 

	
 
			delta_v = v->cur_speed / (station_length + 1);
 
			if (v->max_speed > (v->cur_speed - delta_v))
 
				max_speed = v->cur_speed - (delta_v / 10);
 

	
 
			max_speed = max(max_speed, 25 * station_length);
 
		}
 
	}
 

	
 
	for (u = v; u != NULL; u = u->next) {
 
		const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
 
		int vmass;
 

	
 
		num++;
 
		power += rvi->power * 746;	//[W]
 
		drag_coeff += 3;
 

	
 
		if (rvi->max_speed != 0)
 
			max_speed = min(rvi->max_speed, max_speed);
 

	
 
		if (u->u.rail.track == 0x80)
 
			max_speed = 61;
 

	
 
		vmass = rvi->weight;  //[t]
 
		vmass += (_cargoc.weights[u->cargo_type] * u->cargo_count) / 16;
 
		mass += vmass; //[t]
 

	
 
		if (!IsTileType(u->tile, MP_TUNNELBRIDGE)) {
 
			if (HASBIT(u->u.rail.flags, VRF_GOINGUP)) {
 
				incl += vmass * 60;		//3% slope, quite a bit actually
 
			} else if (HASBIT(u->u.rail.flags, VRF_GOINGDOWN)) {
 
				incl -= vmass * 60;
 
			}
 
		}
 
	}
 

	
 

	
 
	// these are shown in the UI
 
	v->u.rail.cached_weight = mass;
 
	v->u.rail.cached_power = power / 746;
 
	v->max_speed = max_speed;
 

	
 

	
 
	if (v->u.rail.railtype != 2) {
 
		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]
 

	
 
	if (speed > 0) {
 
		switch (v->u.rail.railtype) {
 
			case 0:
 
			case 1:
 
			{
 
				force = power / speed; //[N]
 
				force *= 22;
 
				force /= 10;
 
			} break;
 
			case 2:
 
				force = power / 25;
 
			break;
 
		}
 
	} else
 
		//"kickoff" acceleration
 
		force = resistance * 10;
 

	
 
	if (force <= 0) force = 10000;
 

	
 
	if (v->u.rail.railtype != 2)
 
		force = min(force, mass * 10 * 200);
 

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

	
 
void UpdateTrainAcceleration(Vehicle *v)
 
{
 
	uint acc, power=0, max_speed=5000, weight=0;
 
@@ -73,84 +267,6 @@ void UpdateTrainAcceleration(Vehicle *v)
 
	v->acceleration = (byte)acc;
 
}
 

	
 
#define F_GRAV 9.82f
 
#define F_THETA 0.05f
 

	
 
#define F_HP_KW 0.74569f
 
#define F_KPH_MS 0.27778f
 
#define F_MU 0.3f
 

	
 
#define F_COEF_FRIC 0.04f
 
#define F_COEF_ROLL 0.18f
 

	
 
#define F_CURVE_FACTOR (1/96.f)
 

	
 
static int GetRealisticAcceleration(Vehicle *v)
 
{
 
	uint emass = 0;
 
	Vehicle *u = v;
 
	float f = 0.0f, spd;
 
	int curves = 0;
 

	
 
	assert(v->subtype == TS_Front_Engine);
 

	
 
	// compute inclination force and number of curves.
 
	do {
 
		const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
 
		uint mass = rvi->weight + ((_cargoc.weights[u->cargo_type] * u->cargo_count) >> 4);
 
		if (rvi->power) emass += mass;
 

	
 
		if (!IsTileType(u->tile, MP_TUNNELBRIDGE)) {
 
			if (HASBIT(u->u.rail.flags, VRF_GOINGUP)) {
 
				f += (float)mass * ( -F_GRAV * F_THETA);
 
			} else if (HASBIT(u->u.rail.flags, VRF_GOINGDOWN)) {
 
				f += (float)mass * ( F_GRAV * F_THETA);
 
			}
 
		}
 

	
 
		// compute curve penalty..
 
		if (u->next != NULL) {
 
			uint diff = (u->direction - u->next->direction) & 7;
 
			if (diff) {
 
				curves += (diff == 1 || diff == 7) ? 1 : 3;
 
			}
 
		}
 
	} while ((u = u->next) != NULL);
 

	
 
	spd = (float)(v->cur_speed ? v->cur_speed : 1);
 

	
 
	// compute tractive effort
 
	{
 
		float te = (float)v->u.rail.cached_power * (F_HP_KW/F_KPH_MS) / spd;
 
		float te2 = (float)emass * (F_MU * F_GRAV);
 
		if (te > te2) te = te2;
 
		f += te;
 
	}
 

	
 
	// add air resistance
 
	{
 
		float cx = 1.0f; // NOT DONE
 

	
 
		// air resistance is doubled in tunnels.
 
		if (v->vehstatus == 0x40) cx *= 2;
 

	
 
		f -= cx * spd * spd * (F_KPH_MS * F_KPH_MS * 0.001f);
 
	}
 

	
 
	// after this f contains the acceleration.
 
	f /= (float)v->u.rail.cached_weight;
 

	
 
	// add friction to sum of forces (avoid mul by weight). (0.001 because we want kN)
 
	f -= (F_COEF_FRIC * F_GRAV * 0.001f + (F_COEF_ROLL * F_KPH_MS * F_GRAV * 0.001f) * spd);
 

	
 
	// penalty for curves?
 
	if (curves)
 
		 f -= (float)min(curves, 8) * F_CURVE_FACTOR;
 

	
 
	return (int)(f  * (1.0/(F_KPH_MS * 0.015f)) + 0.5f);
 
}
 

	
 

	
 
int GetTrainImage(Vehicle *v, byte direction)
 
{
 
	int img = v->spritenum;
 
@@ -1517,9 +1633,9 @@ static byte ChooseTrainTrack(Vehicle *v,
 
			fd.best_track_dist = (uint)-1;
 

	
 
			NewTrainPathfind(tile, _search_directions[i][direction], (TPFEnumProc*)TrainTrackFollower, &fd, NULL);
 
			if (best_track != -1) {
 
				if (best_track_dist == -1) {
 
					if (fd.best_track_dist == -1) {
 
			if (best_track != (uint)-1) {
 
				if (best_track_dist == (uint)-1) {
 
					if (fd.best_track_dist == (uint)-1) {
 
						/* neither reached the destination, pick the one with the smallest bird dist */
 
						if (fd.best_bird_dist > best_bird_dist) goto bad;
 
						if (fd.best_bird_dist < best_bird_dist) goto good;
 
@@ -1528,7 +1644,7 @@ static byte ChooseTrainTrack(Vehicle *v,
 
						goto good;
 
					}
 
				} else {
 
					if (fd.best_track_dist == -1) {
 
					if (fd.best_track_dist == (uint)-1) {
 
						/* didn't find destination, but we've found the destination previously */
 
						goto bad;
 
					} else {
 
@@ -1553,7 +1669,7 @@ static byte ChooseTrainTrack(Vehicle *v,
 
	bad:;
 
		} while (bits != 0);
 
//		printf("Train %d %s\n", v->unitnumber, best_track_dist == -1 ? "NOTFOUND" : "FOUND");
 
		assert(best_track != -1);
 
		assert(best_track != (uint)-1);
 
	}
 

	
 
#if 0
 
@@ -1782,17 +1898,25 @@ static int UpdateTrainSpeed(Vehicle *v)
 
	uint accel;
 

	
 
	if (v->vehstatus & VS_STOPPED || HASBIT(v->u.rail.flags, VRF_REVERSING)) {
 
		accel = -v->acceleration * 2;
 
		if (_patches.realistic_acceleration)
 
			accel = GetTrainAcceleration(v, AM_BRAKE) * 2;
 
		else
 
			accel = v->acceleration * -2;
 
	} else {
 
		accel = v->acceleration;
 
		if (_patches.realistic_acceleration) {
 
			accel = GetRealisticAcceleration(v);
 
		}
 
		if (_patches.realistic_acceleration)
 
			accel = GetTrainAcceleration(v, AM_ACCEL);
 
		else
 
			accel = v->acceleration;
 
	}
 

	
 
	spd = v->subspeed + accel * 2;
 
	v->subspeed = (byte)spd;
 
	v->cur_speed = spd = clamp(v->cur_speed + ((int)spd >> 8), 0, v->max_speed);
 
	{
 
		int tempmax = v->max_speed;
 
		if (v->cur_speed > v->max_speed)
 
			tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
 
		v->cur_speed = spd = clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
 
	}
 

	
 
	if (!(v->direction & 1)) spd = spd * 3 >> 2;
 

	
train_gui.c
Show inline comments
 
@@ -1011,6 +1011,7 @@ static void DrawTrainDetailsWindow(Windo
 
{
 
	Vehicle *v, *u;
 
	uint16 tot_cargo[NUM_CARGO][2];	// count total cargo ([0]-actual cargo, [1]-total cargo)
 
	int max_speed = 0xFFFF;
 
	int i,num,x,y,sel;
 
	StringID str;
 
	byte det_tab = WP(w, traindetails_d).tab;
 
@@ -1030,6 +1031,8 @@ static void DrawTrainDetailsWindow(Windo
 
			tot_cargo[u->cargo_type][0] += u->cargo_count;
 
			tot_cargo[u->cargo_type][1] += u->cargo_cap;
 
		}
 
		if (RailVehInfo(u->engine_type)->max_speed != 0)
 
			max_speed = min(max_speed, RailVehInfo(u->engine_type)->max_speed);
 
	} while ( (u = u->next) != NULL);
 

	
 
	/*	set scroll-amount seperately from counting, as to not
 
@@ -1072,7 +1075,7 @@ static void DrawTrainDetailsWindow(Windo
 
	SetDParam(3, GetTrainRunningCost(v) >> 8);
 
	DrawString(x, 15, STR_885D_AGE_RUNNING_COST_YR, 0);
 

	
 
	SetDParam(2, v->max_speed * 10 >> 4);
 
	SetDParam(2, max_speed * 10 >> 4);
 
	SetDParam(1, v->u.rail.cached_power);
 
	SetDParam(0, v->u.rail.cached_weight);
 
	DrawString(x, 25, STR_885E_WEIGHT_T_POWER_HP_MAX_SPEED, 0);
vehicle_gui.c
Show inline comments
 
@@ -299,7 +299,20 @@ int CDECL VehicleMaxSpeedSorter(const vo
 
{
 
	const Vehicle *va = GetVehicle((*(const SortStruct*)a).index);
 
	const Vehicle *vb = GetVehicle((*(const SortStruct*)b).index);
 
	int r = va->max_speed - vb->max_speed;
 
	int max_speed_a = 0xFFFF, max_speed_b = 0xFFFF;
 
	int r;
 
	const Vehicle *ua = va, *ub = vb;
 
	do {
 
		if (RailVehInfo(ua->engine_type)->max_speed != 0)
 
			max_speed_a = min(max_speed_a, RailVehInfo(ua->engine_type)->max_speed);
 
	} while ((ua = ua->next) != NULL);
 

	
 
	do {
 
		if (RailVehInfo(ub->engine_type)->max_speed != 0)
 
			max_speed_b = min(max_speed_b, RailVehInfo(ub->engine_type)->max_speed);
 
	} while ((ub = ub->next) != NULL);
 

	
 
	r = max_speed_a - max_speed_b;
 

	
 
	VEHICLEUNITNUMBERSORTER(r, va, vb);
 

	
0 comments (0 inline, 0 general)