|
@@ -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 */
|
|
|
/* 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));
|
|
|
|
|
|
/* 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;
|
|
|
v->leave_depot_instantly = true;
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
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,25 +773,15 @@ 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) {
|
|
|
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;
|
|
|
}
|
|
|
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;
|
|
@@ -806,16 +791,18 @@ void CallVehicleTicks()
|
|
|
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));
|
|
|
|
|
|
if (IsLocalCompany()) {
|
|
|
if (!IsLocalCompany()) continue;
|
|
|
|
|
|
if (res.Succeeded()) {
|
|
|
ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
|
|
|
} else {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
StringID error_message = res.GetErrorMessage();
|
|
|
|
|
|
if (error_message != STR_AUTOREPLACE_NOTHING_TO_DO && error_message != INVALID_STRING_ID) {
|
|
|
if (error_message == STR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue;
|
|
|
|
|
|
if (error_message == STR_0003_NOT_ENOUGH_CASH_REQUIRES) error_message = STR_AUTOREPLACE_MONEY_LIMIT;
|
|
|
|
|
|
StringID message;
|
|
@@ -835,14 +822,9 @@ void CallVehicleTicks()
|
|
|
SetDParam(1, error_message);
|
|
|
AddNewsItem(message, NS_ADVICE, v->index, 0);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
v = w;
|
|
|
}
|
|
|
|
|
|
_current_company = OWNER_NONE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** Check if a given engine type can be refitted to a given cargo
|
|
|
* @param engine_type Engine type to check
|
|
@@ -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;
|
|
|
|