diff -r e442ce398e83 -r d1ac22c62f64 src/train_cmd.cpp --- a/src/train_cmd.cpp Sun Aug 19 14:04:13 2007 +0000 +++ b/src/train_cmd.cpp Sun Sep 02 11:17:33 2007 +0000 @@ -71,7 +71,7 @@ uint32 total_power = 0; uint32 max_te = 0; - for (const Vehicle *u = v; u != NULL; u = u->next) { + for (const Vehicle *u = v; u != NULL; u = u->Next()) { /* Power is not added for articulated parts */ if (IsArticulatedPart(u)) continue; @@ -113,7 +113,7 @@ { uint32 weight = 0; - for (Vehicle *u = v; u != NULL; u = u->next) { + for (Vehicle *u = v; u != NULL; u = u->Next()) { uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16; /* Vehicle weight is not added for articulated parts. */ @@ -159,11 +159,11 @@ v->u.rail.cached_total_length = 0; v->u.rail.compatible_railtypes = 0; - for (Vehicle *u = v; u != NULL; u = u->next) { + for (Vehicle *u = v; u != NULL; u = u->Next()) { const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); - /* Update the v->first cache. This is faster than having to brute force it later. */ - if (u->first == NULL) u->first = v; + /* Check the v->first cache. */ + assert(u->First() == v); /* update the 'first engine' */ u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine; @@ -236,7 +236,7 @@ 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 + 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 u->u.rail.cached_veh_length = 8 - veh_len; v->u.rail.cached_total_length += u->u.rail.cached_veh_length; } @@ -302,7 +302,7 @@ static int GetTrainAcceleration(Vehicle *v, bool mode) { int max_speed = 2000; - int speed = v->cur_speed * 10 / 16; //[mph] + int speed = v->GetDisplaySpeed(); //[mph] int curvecount[2] = {0, 0}; /*first find the curve speed limit */ @@ -310,9 +310,9 @@ int sum = 0; int pos = 0; int lastpos = -1; - for (const Vehicle *u = v; u->next != NULL; u = u->next, pos++) { + for (const Vehicle *u = v; u->Next() != NULL; u = u->Next(), pos++) { Direction dir = u->direction; - Direction ndir = u->next->direction; + Direction ndir = u->Next()->direction; int i; for (i = 0; i < 2; i++) { @@ -372,7 +372,7 @@ 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 Vehicle *u = v; u != NULL; u = u->next) { + for (const Vehicle *u = v; u != NULL; u = u->Next()) { num++; drag_coeff += 3; @@ -559,7 +559,7 @@ SetTrainWagon(v); if (u != NULL) { - u->next = v; + u->SetNext(v); } else { SetFreeWagon(v); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); @@ -584,12 +584,12 @@ _new_vehicle_id = v->index; VehiclePositionChanged(v); - TrainConsistChanged(GetFirstVehicleInChain(v)); - UpdateTrainGroupID(GetFirstVehicleInChain(v)); + TrainConsistChanged(v->First()); + UpdateTrainGroupID(v->First()); InvalidateWindow(WC_VEHICLE_DEPOT, v->tile); if (IsLocalPlayer()) { - InvalidateAutoreplaceWindow(VEH_TRAIN, v->group_id); // updates the replace Train window + InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window } GetPlayer(_current_player)->num_engines[engine]++; } @@ -621,6 +621,7 @@ static void AddRearEngineToMultiheadedTrain(Vehicle* v, Vehicle* u, bool building) { + u = new (u) Train(); u->direction = v->direction; u->owner = v->owner; u->tile = v->tile; @@ -629,7 +630,6 @@ u->z_pos = v->z_pos; u->u.rail.track = TRACK_BIT_DEPOT; u->vehstatus = v->vehstatus & ~VS_STOPPED; - u = new (u) Train(); u->subtype = 0; SetMultiheaded(u); u->spritenum = v->spritenum + 1; @@ -637,7 +637,7 @@ u->cargo_subtype = v->cargo_subtype; u->cargo_cap = v->cargo_cap; u->u.rail.railtype = v->u.rail.railtype; - if (building) v->next = u; + if (building) v->SetNext(u); u->engine_type = v->engine_type; u->build_year = v->build_year; if (building) v->value >>= 1; @@ -773,7 +773,7 @@ RebuildVehicleLists(); InvalidateWindow(WC_COMPANY, v->owner); if (IsLocalPlayer()) - InvalidateAutoreplaceWindow(VEH_TRAIN, v->group_id); // updates the replace Train window + InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window GetPlayer(_current_player)->num_engines[p1]++; } @@ -793,7 +793,7 @@ if (!IsTileDepotType(tile, TRANSPORT_RAIL) || v->cur_speed != 0) return -1; int count = 0; - for (; v != NULL; v = v->next) { + for (; v != NULL; v = v->Next()) { /* This count is used by the depot code to determine the number of engines * in the consist. Exclude articulated parts so that autoreplacing to * engines with more articulated parts than before works correctly. @@ -841,8 +841,7 @@ Vehicle *u; for (u = first; GetNextVehicle(u) != v; u = GetNextVehicle(u)) {} - GetLastEnginePart(u)->next = GetNextVehicle(v); - v->first = NULL; // we shouldn't point to the old first, since the vehicle isn't in that chain anymore + GetLastEnginePart(u)->SetNext(GetNextVehicle(v)); return first; } @@ -858,7 +857,7 @@ Vehicle *v = dst; while (v->engine_type == eng) { - v = v->next; + v = v->Next(); if (v == NULL) return dst; } } @@ -873,11 +872,12 @@ */ static void AddWagonToConsist(Vehicle *v, Vehicle *dest) { - UnlinkWagon(v, GetFirstVehicleInChain(v)); + UnlinkWagon(v, v->First()); if (dest == NULL) return; - v->next = dest->next; - dest->next = v; + Vehicle *next = dest->Next(); + dest->SetNext(v); + v->SetNext(next); ClearFreeWagon(v); ClearFrontEngine(v); } @@ -897,7 +897,7 @@ /* make sure that there are no free cars before next engine */ Vehicle *u; - for (u = v; u->next != NULL && !IsTrainEngine(u->next); u = u->next) {} + for (u = v; u->Next() != NULL && !IsTrainEngine(u->Next()); u = u->Next()) {} if (u == v->u.rail.other_multiheaded_part) continue; AddWagonToConsist(v->u.rail.other_multiheaded_part, u); @@ -934,19 +934,19 @@ } /* if an articulated part is being handled, deal with its parent vehicle */ - while (IsArticulatedPart(src)) src = GetPrevVehicleInChain(src); + while (IsArticulatedPart(src)) src = src->Previous(); if (dst != NULL) { - while (IsArticulatedPart(dst)) dst = GetPrevVehicleInChain(dst); + while (IsArticulatedPart(dst)) dst = dst->Previous(); } /* don't move the same vehicle.. */ if (src == dst) return CommandCost(); /* locate the head of the two chains */ - Vehicle *src_head = GetFirstVehicleInChain(src); + Vehicle *src_head = src->First(); Vehicle *dst_head; if (dst != NULL) { - dst_head = GetFirstVehicleInChain(dst); + dst_head = dst->First(); if (dst_head->tile != src_head->tile) return CMD_ERROR; /* Now deal with articulated part of destination wagon */ dst = GetLastEnginePart(dst); @@ -1023,10 +1023,6 @@ /* do it? */ if (flags & DC_EXEC) { - /* clear the ->first cache */ - for (Vehicle *u = src_head; u != NULL; u = u->next) u->first = NULL; - for (Vehicle *u = dst_head; u != NULL; u = u->next) u->first = NULL; - /* If we move the front Engine and if the second vehicle is not an engine add the whole vehicle to the DEFAULT_GROUP */ if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) { @@ -1042,7 +1038,7 @@ if (src != src_head) { Vehicle *v = src_head; while (GetNextVehicle(v) != src) v = GetNextVehicle(v); - GetLastEnginePart(v)->next = NULL; + GetLastEnginePart(v)->SetNext(NULL); } else { InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line src_head = NULL; @@ -1052,7 +1048,7 @@ if (src_head == dst_head) dst_head = NULL; /* unlink single wagon from linked list */ src_head = UnlinkWagon(src, src_head); - GetLastEnginePart(src)->next = NULL; + GetLastEnginePart(src)->SetNext(NULL); } if (dst == NULL) { @@ -1098,17 +1094,16 @@ Vehicle *v; for (v = src; GetNextVehicle(v) != NULL; v = GetNextVehicle(v)); - GetLastEnginePart(v)->next = dst->next; + GetLastEnginePart(v)->SetNext(dst->Next()); } - dst->next = src; + dst->SetNext(src); } + if (src->u.rail.other_multiheaded_part != NULL) { if (src->u.rail.other_multiheaded_part == src_head) { - src_head = src_head->next; + src_head = src_head->Next(); } AddWagonToConsist(src->u.rail.other_multiheaded_part, src); - /* previous line set the front engine to the old front. We need to clear that */ - src->u.rail.other_multiheaded_part->first = NULL; } /* If there is an engine behind first_engine we moved away, it should become new first_engine @@ -1219,8 +1214,8 @@ SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES); - while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v); - Vehicle *first = GetFirstVehicleInChain(v); + while (IsArticulatedPart(v)) v = v->Previous(); + Vehicle *first = v->First(); /* make sure the vehicle is stopped in the depot */ if (CheckTrainStoppedInDepot(first) < 0) { @@ -1263,9 +1258,6 @@ if ((flags & DC_EXEC) && v == first) { Vehicle *new_f = GetNextVehicle(first); - /* 2.1 If the first wagon is sold, update the first-> pointers to NULL */ - for (Vehicle *tmp = first; tmp != NULL; tmp = tmp->next) tmp->first = NULL; - /* 2.2 If there are wagons present after the deleted front engine, check * if the second wagon (which will be first) is an engine. If it is one, * promote it as a new train, retaining the unitnumber, orders */ @@ -1300,7 +1292,7 @@ first->next_shared = NULL; /* If we deleted a window then open a new one for the 'new' train */ - if (IsLocalPlayer() && w != NULL) ShowTrainViewWindow(new_f); + if (IsLocalPlayer() && w != NULL) ShowVehicleViewWindow(new_f); } } @@ -1471,8 +1463,8 @@ Vehicle *a, *b; /* locate vehicles to swap */ - for (a = v; l != 0; l--) a = a->next; - for (b = v; r != 0; r--) b = b->next; + for (a = v; l != 0; l--) a = a->Next(); + for (b = v; r != 0; r--) b = b->Next(); if (a != b) { /* swap the hidden bits */ @@ -1540,30 +1532,30 @@ static void AdvanceWagons(Vehicle *v, bool before) { Vehicle *base = v; - Vehicle *first = base->next; + Vehicle *first = base->Next(); uint length = CountVehiclesInChain(v); while (length > 2) { /* find pairwise matching wagon * start<>end, start+1<>end-1, ... */ Vehicle *last = first; - for (uint i = length - 3; i > 0; i--) last = last->next; + for (uint i = length - 3; i > 0; i--) last = last->Next(); int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length; if (before) differential *= -1; if (differential > 0) { /* disconnect last car to make sure only this subset moves */ - Vehicle *tempnext = last->next; - last->next = NULL; + Vehicle *tempnext = last->Next(); + last->SetNext(NULL); for (int i = 0; i < differential; i++) TrainController(first, false); - last->next = tempnext; + last->SetNext(tempnext); } base = first; - first = first->next; + first = first->Next(); length -= 2; } } @@ -1594,7 +1586,7 @@ /* count number of vehicles */ int r = -1; const Vehicle *u = v; - do r++; while ( (u = u->next) != NULL ); + do r++; while ((u = u->Next()) != NULL); AdvanceWagons(v, true); @@ -1634,7 +1626,7 @@ return_cmd_error(STR_ONLY_TURN_SINGLE_UNIT); } - Vehicle *front = GetFirstVehicleInChain(v); + Vehicle *front = v->First(); /* make sure the vehicle is stopped in the depot */ if (CheckTrainStoppedInDepot(front) < 0) { return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); @@ -1646,8 +1638,8 @@ InvalidateWindow(WC_VEHICLE_DETAILS, v->index); } } else { - /*turn the whole train around */ - if (v->u.rail.crash_anim_pos != 0 || v->breakdown_ctr != 0) return CMD_ERROR; + /* turn the whole train around */ + if (v->vehstatus & VS_CRASHED || v->breakdown_ctr != 0) return CMD_ERROR; if (flags & DC_EXEC) { if (_patches.realistic_acceleration && v->cur_speed != 0) { @@ -1773,12 +1765,12 @@ } } } - } while ((v = v->next) != NULL && !only_this); + } while ((v = v->Next()) != NULL && !only_this); _returned_refit_capacity = num; /* Update the train's cached variables */ - if (flags & DC_EXEC) TrainConsistChanged(GetFirstVehicleInChain(GetVehicle(p1))); + if (flags & DC_EXEC) TrainConsistChanged(GetVehicle(p1)->First()); return cost; } @@ -2018,7 +2010,7 @@ } break; } - } while ((v = v->next) != NULL); + } while ((v = v->Next()) != NULL); if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT); } @@ -2047,7 +2039,7 @@ static bool CheckTrainStayInDepot(Vehicle *v) { /* bail out if not all wagons are in the same depot or not in a depot at all */ - for (const Vehicle *u = v; u != NULL; u = u->next) { + for (const Vehicle *u = v; u != NULL; u = u->Next()) { if (u->u.rail.track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; } @@ -2471,7 +2463,7 @@ do { 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); + } while ((v = v->Next()) != NULL); /* need to update acceleration and cached values since the goods on the train changed. */ TrainCargoChanged(this); @@ -2719,7 +2711,7 @@ myabs(v->x_pos - tcc->v->x_pos) < 6 && myabs(v->y_pos - tcc->v->y_pos) < 6 ) { - Vehicle *coll = GetFirstVehicleInChain(v); + Vehicle *coll = v->First(); /* it can't collide with its own wagons */ if (tcc->v == coll || @@ -2757,7 +2749,7 @@ TrainCollideChecker tcc; tcc.v = v; - tcc.v_skip = v->next; + tcc.v_skip = v->Next(); tcc.num = 0; /* find colliding vehicles */ @@ -2809,7 +2801,7 @@ Vehicle *prev; /* For every vehicle after and including the given vehicle */ - for (prev = GetPrevVehicleInChain(v); v != NULL; prev = v, v = v->next) { + for (prev = v->Previous(); v != NULL; prev = v, v = v->Next()) { DiagDirection enterdir = DIAGDIR_BEGIN; bool update_signals = false; BeginVehicleMove(v); @@ -2936,7 +2928,7 @@ goto invalid_rail; } - if (IsLevelCrossingTile(v->tile) && v->next == NULL) { + if (IsLevelCrossingTile(v->tile) && v->Next() == NULL) { UnbarCrossing(v->tile); MarkTileDirtyByTile(v->tile); } @@ -2947,7 +2939,7 @@ v->tile = gp.new_tile; if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) { - TrainPowerChanged(GetFirstVehicleInChain(v)); + TrainPowerChanged(v->First()); } v->u.rail.track = chosen_track; @@ -2999,7 +2991,7 @@ /* Signals can only change when the first * (above) or the last vehicle moves. */ - if (v->next == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); + if (v->Next() == NULL) TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); } } return; @@ -3030,8 +3022,8 @@ * *u is then the one-before-last wagon, and *v the last * one which will physicially be removed */ Vehicle *u = v; - for (; v->next != NULL; v = v->next) u = v; - u->next = NULL; + for (; v->Next() != NULL; v = v->Next()) u = v; + u->SetNext(NULL); InvalidateWindow(WC_VEHICLE_DETAILS, v->index); DeleteWindowById(WC_VEHICLE_VIEW, v->index); @@ -3092,7 +3084,7 @@ the bridge in that case */ if (v->u.rail.track != TRACK_BIT_WORMHOLE) AfterSetTrainPos(v, false); } - } while ((v = v->next) != NULL); + } while ((v = v->Next()) != NULL); } static void HandleCrashedTrain(Vehicle *v) @@ -3119,7 +3111,7 @@ EV_EXPLOSION_SMALL); break; } - } while ((u = u->next) != NULL); + } while ((u = u->Next()) != NULL); } if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v); @@ -3257,7 +3249,7 @@ static void TrainLocoHandler(Vehicle *v, bool mode) { /* train has crashed? */ - if (v->u.rail.crash_anim_pos != 0) { + if (v->vehstatus & VS_CRASHED) { if (!mode) HandleCrashedTrain(v); return; } @@ -3315,6 +3307,25 @@ } + +Money Train::GetRunningCost() const +{ + Money cost = 0; + const Vehicle *v = this; + + do { + const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); + + byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost_base); + if (cost_factor == 0) continue; + + cost += cost_factor * _price.running_rail[rvi->running_cost_class]; + } while ((v = GetNextVehicle(v)) != NULL); + + return cost; +} + + void Train::Tick() { if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo(); @@ -3339,18 +3350,8 @@ static void CheckIfTrainNeedsService(Vehicle *v) { - if (_patches.servint_trains == 0) return; - if (!VehicleNeedsService(v)) return; - if (v->vehstatus & VS_STOPPED) return; - if (_patches.gotodepot && VehicleHasDepotOrders(v)) return; - - /* Don't interfere with a depot visit scheduled by the user, or a - * depot visit by the order list. */ - if (v->current_order.type == OT_GOTO_DEPOT && - (v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0) - return; - - if (CheckTrainIsInsideDepot(v)) { + if (_patches.servint_trains == 0 || !VehicleNeedsService(v)) return; + if (v->IsInDepot()) { VehicleServiceInDepot(v); return; } @@ -3377,8 +3378,6 @@ return; } - if (v->current_order.type == OT_LOADING) v->LeaveStation(); - v->current_order.type = OT_GOTO_DEPOT; v->current_order.flags = OF_NON_STOP; v->current_order.dest = depot->index; @@ -3386,22 +3385,6 @@ InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR); } -Money GetTrainRunningCost(const Vehicle *v) -{ - Money cost = 0; - - do { - const RailVehicleInfo *rvi = RailVehInfo(v->engine_type); - - byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost_base); - if (cost_factor == 0) continue; - - cost += cost_factor * _price.running_rail[rvi->running_cost_class]; - } while ((v = GetNextVehicle(v)) != NULL); - - return cost; -} - void OnNewDay_Train(Vehicle *v) { if ((++v->day_counter & 7) == 0) DecreaseVehicleValue(v); @@ -3422,7 +3405,7 @@ if ((v->vehstatus & VS_STOPPED) == 0) { /* running costs */ - CommandCost cost(GetTrainRunningCost(v) / 364); + CommandCost cost(v->GetRunningCost() / 364); v->profit_this_year -= cost.GetCost() >> 8; @@ -3497,7 +3480,7 @@ } Vehicle *w; - for (w = u->next; w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w)); + for (w = u->Next(); w != NULL && (w->engine_type != u->engine_type || w->u.rail.other_multiheaded_part != NULL); w = GetNextVehicle(w)); if (w != NULL) { /* we found a car to partner with this engine. Now we will make sure it face the right way */ if (IsTrainEngine(w)) {