summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/vehicle.cpp142
-rw-r--r--src/vehicle_base.h4
2 files changed, 63 insertions, 83 deletions
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index 95986e061..faa042b33 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -51,6 +51,7 @@
#include "animated_tile_func.h"
#include "effectvehicle_base.h"
#include "core/alloc_func.hpp"
+#include "core/smallmap_type.hpp"
#include "vehiclelist.h"
#include "table/sprites.h"
@@ -715,41 +716,35 @@ void DeleteVehicleChain(Vehicle *v)
} while (v != NULL);
}
-/** head of the linked list to tell what vehicles that visited a depot in a tick */
-static Vehicle* _first_veh_in_depot_list;
+/**
+ * List of vehicles that should check for autoreplace this tick.
+ * Mapping of vehicle -> leave depot immediatelly after autoreplace.
+ */
+typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
+static AutoreplaceMap _vehicles_to_autoreplace;
/** Adds a vehicle to the list of vehicles, that visited a depot this tick
* @param *v vehicle to add
*/
void VehicleEnteredDepotThisTick(Vehicle *v)
{
- /* We need to set v->leave_depot_instantly as we have no control of it's contents at this time.
- * Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */
- if (((v->current_order.GetDepotActionType() & ODATFB_HALT) && v->current_order.IsType(OT_GOTO_DEPOT)) ||
- (v->vehstatus & VS_STOPPED)) {
- /* we keep the vehicle in the depot since the user ordered it to stay */
- v->vehstatus |= VS_STOPPED; // needed for refitting
- v->leave_depot_instantly = false;
- } else {
- /* the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path
- * out of the depot before we might autoreplace it to a different engine. The new engine would not own the reserved path
- * we store that we stopped the vehicle, so autoreplace can start it again */
- v->vehstatus |= VS_STOPPED;
- v->leave_depot_instantly = true;
- }
+ /* Vehicle should stop in the depot if it was in 'stopping' state or
+ * when the vehicle is ordered to halt in the depot. */
+ _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED) &&
+ (!v->current_order.IsType(OT_GOTO_DEPOT) ||
+ !(v->current_order.GetDepotActionType() & ODATFB_HALT));
- if (_first_veh_in_depot_list == NULL) {
- _first_veh_in_depot_list = v;
- } else {
- Vehicle *w = _first_veh_in_depot_list;
- while (w->depot_list != NULL) w = w->depot_list;
- w->depot_list = v;
- }
+ /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
+ * stopping in the depot, so we stop it to ensure that it will not reserve
+ * the path out of the depot before we might autoreplace it to a different
+ * engine. The new engine would not own the reserved path we store that we
+ * stopped the vehicle, so autoreplace can start it again */
+ v->vehstatus |= VS_STOPPED;
}
void CallVehicleTicks()
{
- _first_veh_in_depot_list = NULL; // now we are sure it's initialized at the start of each tick
+ _vehicles_to_autoreplace.Clear();
Station *st;
FOR_ALL_STATIONS(st) LoadUnloadStation(st);
@@ -778,70 +773,57 @@ void CallVehicleTicks()
}
}
- /* now we handle all the vehicles that entered a depot this tick */
- v = _first_veh_in_depot_list;
- if (v != NULL) {
- while (v != NULL) {
- /* Autoreplace needs the current company set as the vehicle owner */
- _current_company = v->owner;
+ for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
+ v = it->first;
+ /* Autoreplace needs the current company set as the vehicle owner */
+ _current_company = v->owner;
- /* Buffer v->depot_list and clear it.
- * Autoreplace might clear this so it has to be buffered. */
- Vehicle *w = v->depot_list;
- v->depot_list = NULL; // it should always be NULL at the end of each tick
-
- /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
- * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
- * they are already leaving the depot again before being replaced. */
- if (v->leave_depot_instantly) {
- v->leave_depot_instantly = false;
- v->vehstatus &= ~VS_STOPPED;
- }
+ /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
+ * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
+ * they are already leaving the depot again before being replaced. */
+ if (it->second) v->vehstatus &= ~VS_STOPPED;
- /* Store the position of the effect as the vehicle pointer will become invalid later */
- int x = v->x_pos;
- int y = v->y_pos;
- int z = v->z_pos;
+ /* Store the position of the effect as the vehicle pointer will become invalid later */
+ int x = v->x_pos;
+ int y = v->y_pos;
+ int z = v->z_pos;
- const Company *c = GetCompany(_current_company);
- SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->engine_renew_money));
- CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
- if (res.Succeeded()) v = NULL; // no longer valid
- SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->engine_renew_money));
+ const Company *c = GetCompany(_current_company);
+ SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->engine_renew_money));
+ CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
+ SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->engine_renew_money));
- if (IsLocalCompany()) {
- if (res.Succeeded()) {
- ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
- } else {
- StringID error_message = res.GetErrorMessage();
+ if (!IsLocalCompany()) continue;
+
+ if (res.Succeeded()) {
+ ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
+ continue;
+ }
- if (error_message != STR_AUTOREPLACE_NOTHING_TO_DO && error_message != INVALID_STRING_ID) {
- if (error_message == STR_0003_NOT_ENOUGH_CASH_REQUIRES) error_message = STR_AUTOREPLACE_MONEY_LIMIT;
+ StringID error_message = res.GetErrorMessage();
+ if (error_message == STR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
- StringID message;
- if (error_message == STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
- message = error_message;
- } else {
- switch (v->type) {
- case VEH_TRAIN: message = STR_TRAIN_AUTORENEW_FAILED; break;
- case VEH_ROAD: message = STR_ROADVEHICLE_AUTORENEW_FAILED; break;
- case VEH_SHIP: message = STR_SHIP_AUTORENEW_FAILED; break;
- case VEH_AIRCRAFT: message = STR_AIRCRAFT_AUTORENEW_FAILED; break;
- default: NOT_REACHED();
- }
- }
+ if (error_message == STR_0003_NOT_ENOUGH_CASH_REQUIRES) error_message = STR_AUTOREPLACE_MONEY_LIMIT;
- SetDParam(0, v->unitnumber);
- SetDParam(1, error_message);
- AddNewsItem(message, NS_ADVICE, v->index, 0);
- }
- }
+ StringID message;
+ if (error_message == STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) {
+ message = error_message;
+ } else {
+ switch (v->type) {
+ case VEH_TRAIN: message = STR_TRAIN_AUTORENEW_FAILED; break;
+ case VEH_ROAD: message = STR_ROADVEHICLE_AUTORENEW_FAILED; break;
+ case VEH_SHIP: message = STR_SHIP_AUTORENEW_FAILED; break;
+ case VEH_AIRCRAFT: message = STR_AIRCRAFT_AUTORENEW_FAILED; break;
+ default: NOT_REACHED();
}
-
- v = w;
}
- _current_company = OWNER_NONE;
+
+ SetDParam(0, v->unitnumber);
+ SetDParam(1, error_message);
+ AddNewsItem(message, NS_ADVICE, v->index, 0);
}
+
+ _current_company = OWNER_NONE;
}
/** Check if a given engine type can be refitted to a given cargo
@@ -1612,7 +1594,7 @@ void VehicleEnterDepot(Vehicle *v)
CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
if (CmdFailed(cost)) {
- v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot
+ _vehicles_to_autoreplace[v] = false;
if (v->owner == _local_company) {
/* Notify the user that we stopped the vehicle */
SetDParam(0, _vehicle_type_names[v->type]);
@@ -2432,6 +2414,8 @@ static void Save_VEHS()
/** Will be called when vehicles need to be loaded. */
void Load_VEHS()
{
+ _vehicles_to_autoreplace.Reset();
+
int index;
Vehicle *v;
diff --git a/src/vehicle_base.h b/src/vehicle_base.h
index 6df247c15..d051f79d9 100644
--- a/src/vehicle_base.h
+++ b/src/vehicle_base.h
@@ -212,8 +212,6 @@ public:
friend void AfterLoadVehicles(bool clear_te_id); ///< So we can set the previous and first pointers while loading
friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading
- Vehicle *depot_list; ///< NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace
-
char *name; ///< Name of vehicle
TileIndex tile; ///< Current tile index
@@ -309,8 +307,6 @@ public:
Order *orders; ///< Pointer to the first order for this vehicle
- bool leave_depot_instantly; ///< NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
-
byte vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
uint16 load_unload_time_rem;