diff --git a/train_cmd.c b/train_cmd.c --- a/train_cmd.c +++ b/train_cmd.c @@ -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; diff --git a/train_gui.c b/train_gui.c --- a/train_gui.c +++ b/train_gui.c @@ -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); diff --git a/vehicle_gui.c b/vehicle_gui.c --- a/vehicle_gui.c +++ b/vehicle_gui.c @@ -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);