(svn r1681) -Feature: New realistic acceleration.
authorcelestar
Wed, 26 Jan 2005 12:51:04 +0000
changeset 1179 abea5b669f74
parent 1178 ce85710f92ff
child 1180 04f306272df7
(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
train_cmd.c
train_gui.c
vehicle_gui.c
--- a/train_cmd.c	Wed Jan 26 12:42:29 2005 +0000
+++ b/train_cmd.c	Wed Jan 26 12:51:04 2005 +0000
@@ -34,6 +34,200 @@
 	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 @@
 	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 @@
 			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 @@
 						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 @@
 	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 @@
 	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;
 
--- a/train_gui.c	Wed Jan 26 12:42:29 2005 +0000
+++ b/train_gui.c	Wed Jan 26 12:51:04 2005 +0000
@@ -1011,6 +1011,7 @@
 {
 	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 @@
 			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 @@
 	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);
--- a/vehicle_gui.c	Wed Jan 26 12:42:29 2005 +0000
+++ b/vehicle_gui.c	Wed Jan 26 12:51:04 2005 +0000
@@ -299,7 +299,20 @@
 {
 	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);