--- a/src/train_cmd.cpp Sat Jun 02 19:59:29 2007 +0000
+++ b/src/train_cmd.cpp Sat Jul 14 19:42:58 2007 +0000
@@ -15,6 +15,7 @@
#include "tile.h"
#include "tunnel_map.h"
#include "vehicle.h"
+#include "timetable.h"
#include "articulated_vehicles.h"
#include "command.h"
#include "pathfind.h"
@@ -111,7 +112,7 @@
uint32 weight = 0;
for (Vehicle *u = v; u != NULL; u = u->next) {
- uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type) / 16;
+ 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)) {
@@ -230,7 +231,7 @@
/* check the vehicle length (callback) */
uint16 veh_len = CALLBACK_FAILED;
if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
- veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
+ 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 = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code
@@ -447,22 +448,22 @@
v->acceleration = clamp(power / weight * 4, 1, 255);
}
-int GetTrainImage(const Vehicle* v, Direction direction)
+int Train::GetImage(Direction direction) const
{
- int img = v->spritenum;
+ int img = this->spritenum;
int base;
- if (HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
+ if (HASBIT(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction);
if (is_custom_sprite(img)) {
- base = GetCustomVehicleSprite(v, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img)));
+ base = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img)));
if (base != 0) return base;
- img = orig_rail_vehicle_info[v->engine_type].image_index;
+ img = orig_rail_vehicle_info[this->engine_type].image_index;
}
base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]);
- if (v->cargo_count >= v->cargo_cap / 2) base += _wagon_full_adder[img];
+ if (this->cargo.Count() >= this->cargo_cap / 2U) base += _wagon_full_adder[img];
return base;
}
@@ -502,12 +503,12 @@
DrawSprite(image, pal, x, y);
}
-static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
+static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
{
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
const RailVehicleInfo *rvi = RailVehInfo(engine);
- int32 value = (GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8;
+ CommandCost value((GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8);
uint num_vehicles = 1 + CountArticulatedParts(engine);
@@ -565,7 +566,7 @@
v->cargo_type = rvi->cargo_type;
v->cargo_subtype = 0;
v->cargo_cap = rvi->capacity;
- v->value = value;
+ v->value = value.GetCost();
// v->day_counter = 0;
v->u.rail.railtype = rvi->railtype;
@@ -576,7 +577,7 @@
v->group_id = DEFAULT_GROUP;
- AddArticulatedParts(vl);
+ AddArticulatedParts(vl, VEH_TRAIN);
_new_vehicle_id = v->index;
@@ -586,13 +587,13 @@
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
if (IsLocalPlayer()) {
- InvalidateAutoreplaceWindow(VEH_TRAIN); // updates the replace Train window
+ InvalidateAutoreplaceWindow(VEH_TRAIN, v->group_id); // updates the replace Train window
}
GetPlayer(_current_player)->num_engines[engine]++;
}
}
- return value;
+ return CommandCost(value);
}
/** Move all free vehicles in the depot to the train */
@@ -611,9 +612,9 @@
}
}
-static int32 EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi)
+static CommandCost EstimateTrainCost(EngineID engine, const RailVehicleInfo* rvi)
{
- return GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5;
+ return CommandCost(GetEngineProperty(engine, 0x17, rvi->base_cost) * (_price.build_railvehicle >> 3) >> 5);
}
static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building)
@@ -651,7 +652,7 @@
* @param p2 bit 0 when set, the train will get number 0, otherwise it will get a free number
* bit 1 prevents any free cars from being added to the train
*/
-int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
/* Check if the engine-type is valid (for the player) */
if (!IsEngineBuildable(p1, VEH_TRAIN, _current_player)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE);
@@ -673,7 +674,7 @@
if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
- int32 value = EstimateTrainCost(p1, rvi);
+ CommandCost value = EstimateTrainCost(p1, rvi);
uint num_vehicles =
(rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
@@ -712,7 +713,7 @@
v->cargo_subtype = 0;
v->cargo_cap = rvi->capacity;
v->max_speed = rvi->max_speed;
- v->value = value;
+ v->value = value.GetCost();
v->last_station_visited = INVALID_STATION;
v->dest_tile = 0;
@@ -755,7 +756,7 @@
vl[0]->u.rail.other_multiheaded_part = vl[1];
vl[1]->u.rail.other_multiheaded_part = vl[0];
} else {
- AddArticulatedParts(vl);
+ AddArticulatedParts(vl, VEH_TRAIN);
}
TrainConsistChanged(v);
@@ -770,7 +771,7 @@
RebuildVehicleLists();
InvalidateWindow(WC_COMPANY, v->owner);
if (IsLocalPlayer())
- InvalidateAutoreplaceWindow(VEH_TRAIN); // updates the replace Train window
+ InvalidateAutoreplaceWindow(VEH_TRAIN, v->group_id); // updates the replace Train window
GetPlayer(_current_player)->num_engines[p1]++;
}
@@ -909,7 +910,7 @@
* - p1 (bit 16 - 31) what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line
* @param p2 (bit 0) move all vehicles following the source vehicle
*/
-int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
VehicleID s = GB(p1, 0, 16);
VehicleID d = GB(p1, 16, 16);
@@ -937,7 +938,7 @@
}
/* don't move the same vehicle.. */
- if (src == dst) return 0;
+ if (src == dst) return CommandCost();
/* locate the head of the two chains */
Vehicle *src_head = GetFirstVehicleInChain(src);
@@ -954,7 +955,7 @@
if (IsMultiheaded(src) && !IsTrainEngine(src)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
/* when moving all wagons, we can't have the same src_head and dst_head */
- if (HASBIT(p2, 0) && src_head == dst_head) return 0;
+ if (HASBIT(p2, 0) && src_head == dst_head) return CommandCost();
{
int max_len = _patches.mammoth_trains ? 100 : 9;
@@ -1153,7 +1154,7 @@
RebuildVehicleLists();
}
- return 0;
+ return CommandCost();
}
/** Start/Stop a train.
@@ -1162,7 +1163,7 @@
* @param p1 train to start/stop
* @param p2 unused
*/
-int32 CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdStartStopTrain(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1189,7 +1190,7 @@
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
}
- return 0;
+ return CommandCost();
}
/** Sell a (single) train wagon/engine.
@@ -1203,8 +1204,11 @@
* - p2 = 2: when selling attached locos, rearrange all vehicles after it to separate lines;
* all wagons of the same type will go on the same line. Used by the AI currently
*/
-int32 CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
+ /* Check if we deleted a vehicle window */
+ Window *w = NULL;
+
if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR;
Vehicle *v = GetVehicle(p1);
@@ -1225,13 +1229,14 @@
if (flags & DC_EXEC) {
if (v == first && IsFrontEngine(first)) {
- DeleteWindowById(WC_VEHICLE_VIEW, first->index);
+ w = FindWindowById(WC_VEHICLE_VIEW, first->index);
+ if (w != NULL) DeleteWindow(w);
}
InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
RebuildVehicleLists();
}
- int32 cost = 0;
+ CommandCost cost;
switch (p2) {
case 0: case 2: { /* Delete given wagon */
bool switch_engine = false; // update second wagon to engine?
@@ -1243,7 +1248,7 @@
IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
if (rear != NULL) {
- cost -= rear->value;
+ cost.AddCost(-rear->value);
if (flags & DC_EXEC) {
UnlinkWagon(rear, first);
DeleteDepotHighlightOfVehicle(rear);
@@ -1292,12 +1297,13 @@
first->prev_shared = NULL;
first->next_shared = NULL;
- if (IsLocalPlayer()) ShowTrainViewWindow(new_f);
+ /* If we deleted a window then open a new one for the 'new' train */
+ if (IsLocalPlayer() && w != NULL) ShowTrainViewWindow(new_f);
}
}
/* 3. Delete the requested wagon */
- cost -= v->value;
+ cost.AddCost(-v->value);
if (flags & DC_EXEC) {
first = UnlinkWagon(v, first);
DeleteDepotHighlightOfVehicle(v);
@@ -1347,7 +1353,7 @@
Vehicle *rear = v->u.rail.other_multiheaded_part;
if (rear != NULL) {
- cost -= rear->value;
+ cost.AddCost(-rear->value);
/* If this is a multiheaded vehicle with nothing
* between the parts, tmp will be pointing to the
@@ -1369,7 +1375,7 @@
}
}
- cost -= v->value;
+ cost.AddCost(-v->value);
if (flags & DC_EXEC) {
first = UnlinkWagon(v, first);
DeleteDepotHighlightOfVehicle(v);
@@ -1418,7 +1424,7 @@
static void UpdateVarsAfterSwap(Vehicle *v)
{
v->UpdateDeltaXY(v->direction);
- v->cur_image = GetTrainImage(v, v->direction);
+ v->cur_image = v->GetImage(v->direction);
BeginVehicleMove(v);
VehiclePositionChanged(v);
EndVehicleMove(v);
@@ -1611,7 +1617,7 @@
* @param p1 train to reverse
* @param p2 if true, reverse a unit in a train (needs to be in a depot)
*/
-int32 CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdReverseTrainDirection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1651,7 +1657,7 @@
}
}
}
- return 0;
+ return CommandCost();
}
/** Force a train through a red signal
@@ -1660,7 +1666,7 @@
* @param p1 train to ignore the red signal
* @param p2 unused
*/
-int32 CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1670,7 +1676,7 @@
if (flags & DC_EXEC) v->u.rail.force_proceed = 0x50;
- return 0;
+ return CommandCost();
}
/** Refits a train to the specified cargo type.
@@ -1683,7 +1689,7 @@
* - p2 = (bit 16) - refit only this vehicle
* @return cost of refit or error
*/
-int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
CargoID new_cid = GB(p2, 0, 8);
byte new_subtype = GB(p2, 8, 8);
@@ -1701,7 +1707,7 @@
SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
- int32 cost = 0;
+ CommandCost cost;
uint num = 0;
do {
@@ -1750,12 +1756,12 @@
if (amount != 0) {
if (new_cid != v->cargo_type) {
- cost += GetRefitCost(v->engine_type);
+ cost.AddCost(GetRefitCost(v->engine_type));
}
num += amount;
if (flags & DC_EXEC) {
- v->cargo_count = (v->cargo_type == new_cid) ? min(amount, v->cargo_count) : 0;
+ v->cargo.Truncate((v->cargo_type == new_cid) ? amount : 0);
v->cargo_type = new_cid;
v->cargo_cap = amount;
v->cargo_subtype = new_subtype;
@@ -1867,7 +1873,7 @@
* - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
* - p2 bit 8-10 - VLW flag (for mass goto depot)
*/
-int32 CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+CommandCost CmdSendTrainToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
if (p2 & DEPOT_MASS_SEND) {
/* Mass goto depot requested */
@@ -1892,7 +1898,7 @@
TOGGLEBIT(v->current_order.flags, OFB_HALT_IN_DEPOT);
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
}
- return 0;
+ return CommandCost();
}
if (p2 & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders
@@ -1905,7 +1911,7 @@
v->current_order.flags = 0;
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
}
- return 0;
+ return CommandCost();
}
/* check if at a standstill (not stopped only) in a depot
@@ -1929,7 +1935,7 @@
if (tfdd.reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
}
- return 0;
+ return CommandCost();
}
@@ -2075,7 +2081,7 @@
v->cur_speed = 0;
v->UpdateDeltaXY(v->direction);
- v->cur_image = GetTrainImage(v, v->direction);
+ v->cur_image = v->GetImage(v->direction);
VehiclePositionChanged(v);
UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction));
UpdateTrainAcceleration(v);
@@ -2374,6 +2380,7 @@
if (!(v->current_order.flags & OF_PART_OF_ORDERS)) return false;
if ((v->current_order.flags & OF_SERVICE_IF_NEEDED) &&
!VehicleNeedsService(v)) {
+ UpdateVehicleTimetable(v, true);
v->cur_order_index++;
}
break;
@@ -2385,11 +2392,19 @@
default: break;
}
+ /**
+ * Reversing because of order change is allowed only just after leaving a
+ * station (and the difficulty setting to allowed, of course)
+ * this can be detected because only after OT_LEAVESTATION, current_order
+ * will be reset to nothing. (That also happens if no order, but in that case
+ * it won't hit the point in code where may_reverse is checked)
+ */
+ bool may_reverse = v->current_order.type == OT_NOTHING;
+
/* check if we've reached the waypoint? */
- bool at_waypoint = false;
if (v->current_order.type == OT_GOTO_WAYPOINT && v->tile == v->dest_tile) {
+ UpdateVehicleTimetable(v, true);
v->cur_order_index++;
- at_waypoint = true;
}
/* check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */
@@ -2397,6 +2412,7 @@
v->current_order.flags & OF_NON_STOP &&
IsTileType(v->tile, MP_STATION) &&
v->current_order.dest == GetStationIndex(v->tile)) {
+ UpdateVehicleTimetable(v, true);
v->cur_order_index++;
}
@@ -2444,14 +2460,14 @@
return false;
}
- return !at_waypoint && CheckReverseTrain(v);
+ return may_reverse && CheckReverseTrain(v);
}
void Train::MarkDirty()
{
Vehicle *v = this;
do {
- v->cur_image = GetTrainImage(v, v->direction);
+ v->cur_image = v->GetImage(v->direction);
MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
} while ((v = v->next) != NULL);
@@ -2520,22 +2536,28 @@
static byte AfterSetTrainPos(Vehicle *v, bool new_tile)
{
- /* need this hint so it returns the right z coordinate on bridges. */
- byte new_z = GetSlopeZ(v->x_pos, v->y_pos);
-
byte old_z = v->z_pos;
- v->z_pos = new_z;
+ v->z_pos = GetSlopeZ(v->x_pos, v->y_pos);
if (new_tile) {
CLRBIT(v->u.rail.flags, VRF_GOINGUP);
CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
- if (new_z != old_z) {
- TileIndex tile = TileVirtXY(v->x_pos, v->y_pos);
-
- /* XXX workaround, whole UP/DOWN detection needs overhaul */
- if (!IsTunnelTile(tile)) {
- SETBIT(v->u.rail.flags, (new_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
+ if (v->u.rail.track == TRACK_BIT_X || v->u.rail.track == TRACK_BIT_Y) {
+ /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped.
+ * To check whether the current tile is sloped, and in which
+ * direction it is sloped, we get the 'z' at the center of
+ * the tile (middle_z) and the edge of the tile (old_z),
+ * which we then can compare. */
+ static const int HALF_TILE_SIZE = TILE_SIZE / 2;
+ static const int INV_TILE_SIZE_MASK = ~(TILE_SIZE - 1);
+
+ byte middle_z = GetSlopeZ((v->x_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE, (v->y_pos & INV_TILE_SIZE_MASK) | HALF_TILE_SIZE);
+
+ /* For some reason tunnel tiles are always given as sloped :(
+ * But they are not sloped... */
+ if (middle_z != v->z_pos && !IsTunnelTile(TileVirtXY(v->x_pos, v->y_pos))) {
+ SETBIT(v->u.rail.flags, (middle_z > old_z) ? VRF_GOINGUP : VRF_GOINGDOWN);
}
}
}
@@ -2654,28 +2676,6 @@
}
-struct TrainCollideChecker {
- const Vehicle *v;
- const Vehicle *v_skip;
-};
-
-static void *FindTrainCollideEnum(Vehicle *v, void *data)
-{
- const TrainCollideChecker* tcc = (TrainCollideChecker*)data;
-
- if (v != tcc->v &&
- v != tcc->v_skip &&
- v->type == VEH_TRAIN &&
- v->u.rail.track != TRACK_BIT_DEPOT &&
- myabs(v->z_pos - tcc->v->z_pos) < 6 &&
- myabs(v->x_pos - tcc->v->x_pos) < 6 &&
- myabs(v->y_pos - tcc->v->y_pos) < 6) {
- return v;
- } else {
- return NULL;
- }
-}
-
static void SetVehicleCrashed(Vehicle *v)
{
if (v->u.rail.crash_anim_pos != 0) return;
@@ -2694,11 +2694,52 @@
{
uint num = 0;
BEGIN_ENUM_WAGONS(v)
- if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo_count;
+ if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
END_ENUM_WAGONS(v)
return num;
}
+struct TrainCollideChecker {
+ Vehicle *v;
+ const Vehicle *v_skip;
+ uint num;
+};
+
+static void *FindTrainCollideEnum(Vehicle *v, void *data)
+{
+ TrainCollideChecker* tcc = (TrainCollideChecker*)data;
+
+ if (v != tcc->v &&
+ v != tcc->v_skip &&
+ v->type == VEH_TRAIN &&
+ v->u.rail.track != TRACK_BIT_DEPOT &&
+ myabs(v->z_pos - tcc->v->z_pos) < 6 &&
+ myabs(v->x_pos - tcc->v->x_pos) < 6 &&
+ myabs(v->y_pos - tcc->v->y_pos) < 6 ) {
+
+ Vehicle *coll = GetFirstVehicleInChain(v);
+
+ /* it can't collide with its own wagons */
+ if (tcc->v == coll ||
+ (tcc->v->u.rail.track == TRACK_BIT_WORMHOLE && (tcc->v->direction & 2) != (v->direction & 2)))
+ return NULL;
+
+ /* two drivers + passengers killed in train tcc->v (if it was not crashed already) */
+ if (!(tcc->v->vehstatus & VS_CRASHED)) {
+ tcc->num += 2 + CountPassengersInTrain(tcc->v);
+ SetVehicleCrashed(tcc->v);
+ }
+
+ if (!(coll->vehstatus & VS_CRASHED)) {
+ /* two drivers + passengers killed in train coll (if it was not crashed already) */
+ tcc->num += 2 + CountPassengersInTrain(coll);
+ SetVehicleCrashed(coll);
+ }
+ }
+
+ return NULL;
+}
+
/**
* Checks whether the specified train has a collision with another vehicle. If
* so, destroys this vehicle, and the other vehicle if its subtype has TS_Front.
@@ -2715,28 +2756,15 @@
TrainCollideChecker tcc;
tcc.v = v;
tcc.v_skip = v->next;
-
- /* find colliding vehicle */
- Vehicle *realcoll = (Vehicle*)VehicleFromPos(TileVirtXY(v->x_pos, v->y_pos), &tcc, FindTrainCollideEnum);
- if (realcoll == NULL) return;
-
- Vehicle *coll = GetFirstVehicleInChain(realcoll);
-
- /* it can't collide with its own wagons */
- if (v == coll ||
- (v->u.rail.track == TRACK_BIT_WORMHOLE && (v->direction & 2) != (realcoll->direction & 2)))
- return;
-
- /* two drivers + passangers killed in train v */
- uint num = 2 + CountPassengersInTrain(v);
- if (!(coll->vehstatus & VS_CRASHED))
- /* two drivers + passangers killed in train coll (if it was not crashed already) */
- num += 2 + CountPassengersInTrain(coll);
-
- SetVehicleCrashed(v);
- if (IsFrontEngine(coll)) SetVehicleCrashed(coll);
-
- SetDParam(0, num);
+ tcc.num = 0;
+
+ /* find colliding vehicles */
+ VehicleFromPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum);
+
+ /* any dead -> no crash */
+ if (tcc.num == 0) return;
+
+ SetDParam(0, tcc.num);
AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
NEWS_FLAGS(NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, 0),
v->index,
@@ -2770,6 +2798,8 @@
/* For every vehicle after and including the given vehicle */
for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) {
+ DiagDirection enterdir = DIAGDIR_BEGIN;
+ bool update_signals = false;
BeginVehicleMove(v);
GetNewVehiclePosResult gp = GetNewVehiclePos(v);
@@ -2805,7 +2835,7 @@
/* Determine what direction we're entering the new tile from */
Direction dir = GetNewVehicleDirectionByTile(gp.new_tile, gp.old_tile);
- DiagDirection enterdir = DirToDiagDir(dir);
+ enterdir = DirToDiagDir(dir);
assert(IsValidDiagDirection(enterdir));
/* Get the status of the tracks in the new tile and mask
@@ -2912,11 +2942,9 @@
assert(v->u.rail.track);
}
- if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
-
- /* Signals can only change when the first
- * (above) or the last vehicle moves. */
- if (v->next == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
+ /* We need to update signal status, but after the vehicle position hash
+ * has been updated by AfterSetTrainPos() */
+ update_signals = true;
if (prev == NULL) AffectSpeedByDirChange(v, chosen_dir);
@@ -2941,7 +2969,7 @@
/* update image of train, as well as delta XY */
Direction newdir = GetNewVehicleDirection(v, gp.x, gp.y);
v->UpdateDeltaXY(newdir);
- if (update_image) v->cur_image = GetTrainImage(v, newdir);
+ if (update_image) v->cur_image = v->GetImage(newdir);
v->x_pos = gp.x;
v->y_pos = gp.y;
@@ -2953,6 +2981,14 @@
/* This is the first vehicle in the train */
AffectSpeedByZChange(v, old_z);
}
+
+ if (update_signals) {
+ if (IsFrontEngine(v)) TrainMovedChangeSignals(gp.new_tile, enterdir);
+
+ /* Signals can only change when the first
+ * (above) or the last vehicle moves. */
+ if (v->next == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
+ }
}
return;
@@ -2993,8 +3029,6 @@
BeginVehicleMove(v);
EndVehicleMove(v);
- if (IsFrontEngine(v)) RemoveVehicleFromGroup(v);
-
DeleteVehicle(v);
if (v->u.rail.track != TRACK_BIT_DEPOT && v->u.rail.track != TRACK_BIT_WORMHOLE)
@@ -3040,7 +3074,7 @@
v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]);
BeginVehicleMove(v);
v->UpdateDeltaXY(v->direction);
- v->cur_image = GetTrainImage(v, v->direction);
+ v->cur_image = v->GetImage(v->direction);
/* Refrain from updating the z position of the vehicle when on
a bridge, because AfterSetTrainPos will put the vehicle under
the bridge in that case */
@@ -3269,23 +3303,24 @@
}
-void Train_Tick(Vehicle *v)
+void Train::Tick()
{
- if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff)
- v->cargo_days++;
-
- v->tick_counter++;
-
- if (IsFrontEngine(v)) {
- TrainLocoHandler(v, false);
+ if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo();
+
+ this->tick_counter++;
+
+ if (IsFrontEngine(this)) {
+ this->current_order_time++;
+
+ TrainLocoHandler(this, false);
/* make sure vehicle wasn't deleted. */
- if (v->type == VEH_TRAIN && IsFrontEngine(v))
- TrainLocoHandler(v, true);
- } else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) {
+ if (this->type == VEH_TRAIN && IsFrontEngine(this))
+ TrainLocoHandler(this, true);
+ } else if (IsFreeWagon(this) && HASBITS(this->vehstatus, VS_CRASHED)) {
/* Delete flooded standalone wagon */
- if (++v->u.rail.crash_anim_pos >= 4400)
- DeleteVehicle(v);
+ if (++this->u.rail.crash_anim_pos >= 4400)
+ DeleteVehicle(this);
}
}
@@ -3340,9 +3375,9 @@
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
}
-int32 GetTrainRunningCost(const Vehicle *v)
+Money GetTrainRunningCost(const Vehicle *v)
{
- int32 cost = 0;
+ Money cost = 0;
do {
const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
@@ -3376,9 +3411,9 @@
if ((v->vehstatus & VS_STOPPED) == 0) {
/* running costs */
- int32 cost = GetTrainRunningCost(v) / 364;
-
- v->profit_this_year -= cost >> 8;
+ CommandCost cost(GetTrainRunningCost(v) / 364);
+
+ v->profit_this_year -= cost.GetCost() >> 8;
SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
SubtractMoneyFromPlayerFract(v->owner, cost);
@@ -3386,6 +3421,9 @@
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
InvalidateWindowClasses(WC_TRAINS_LIST);
}
+ } else if (IsTrainEngine(v)) {
+ /* Also age engines that aren't front engines */
+ AgeVehicle(v);
}
}