(svn r14745) -Codechange: move "depot_list" and "leave_depot_immediately" out of the vehicle struct (saving up to 16 bytes per vehicle) as it is only used to tell a calling function entered a depot (for autoreplace).

This commit is contained in:
rubidium 2008-12-26 18:26:11 +00:00
parent 634842525b
commit 047e40d33f
2 changed files with 66 additions and 86 deletions

View File

@ -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 (it->second) 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 (v->leave_depot_instantly) {
v->leave_depot_instantly = false;
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);
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);
if (res.Succeeded()) v = NULL; // no longer valid
SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->engine_renew_money));
if (!IsLocalCompany()) continue;
if (IsLocalCompany()) {
if (res.Succeeded()) {
ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
} else {
StringID error_message = res.GetErrorMessage();
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 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();
}
}
SetDParam(0, v->unitnumber);
SetDParam(1, error_message);
AddNewsItem(message, NS_ADVICE, v->index, 0);
}
}
}
v = w;
if (res.Succeeded()) {
ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
continue;
}
_current_company = OWNER_NONE;
StringID error_message = res.GetErrorMessage();
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;
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();
}
}
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;

View File

@ -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;