1
0
Fork 0

(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).

release/0.7
rubidium 2008-12-26 18:26:11 +00:00
parent a8cb9fa2f5
commit 1721222080
2 changed files with 66 additions and 86 deletions

View File

@ -51,6 +51,7 @@
#include "animated_tile_func.h" #include "animated_tile_func.h"
#include "effectvehicle_base.h" #include "effectvehicle_base.h"
#include "core/alloc_func.hpp" #include "core/alloc_func.hpp"
#include "core/smallmap_type.hpp"
#include "vehiclelist.h" #include "vehiclelist.h"
#include "table/sprites.h" #include "table/sprites.h"
@ -715,41 +716,35 @@ void DeleteVehicleChain(Vehicle *v)
} while (v != NULL); } 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 /** Adds a vehicle to the list of vehicles, that visited a depot this tick
* @param *v vehicle to add * @param *v vehicle to add
*/ */
void VehicleEnteredDepotThisTick(Vehicle *v) 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 or
* Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */ * when the vehicle is ordered to halt in the depot. */
if (((v->current_order.GetDepotActionType() & ODATFB_HALT) && v->current_order.IsType(OT_GOTO_DEPOT)) || _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED) &&
(v->vehstatus & VS_STOPPED)) { (!v->current_order.IsType(OT_GOTO_DEPOT) ||
/* we keep the vehicle in the depot since the user ordered it to stay */ !(v->current_order.GetDepotActionType() & ODATFB_HALT));
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;
}
if (_first_veh_in_depot_list == NULL) { /* We ALWAYS set the stopped state. Even when the vehicle does not plan on
_first_veh_in_depot_list = v; * stopping in the depot, so we stop it to ensure that it will not reserve
} else { * the path out of the depot before we might autoreplace it to a different
Vehicle *w = _first_veh_in_depot_list; * engine. The new engine would not own the reserved path we store that we
while (w->depot_list != NULL) w = w->depot_list; * stopped the vehicle, so autoreplace can start it again */
w->depot_list = v; v->vehstatus |= VS_STOPPED;
}
} }
void CallVehicleTicks() 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; Station *st;
FOR_ALL_STATIONS(st) LoadUnloadStation(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 */ for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) {
v = _first_veh_in_depot_list; v = it->first;
if (v != NULL) { /* Autoreplace needs the current company set as the vehicle owner */
while (v != NULL) { _current_company = v->owner;
/* Autoreplace needs the current company set as the vehicle owner */
_current_company = v->owner;
/* Buffer v->depot_list and clear it. /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick()
* Autoreplace might clear this so it has to be buffered. */ * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that
Vehicle *w = v->depot_list; * they are already leaving the depot again before being replaced. */
v->depot_list = NULL; // it should always be NULL at the end of each tick if (it->second) v->vehstatus &= ~VS_STOPPED;
/* Start vehicle if we stopped them in VehicleEnteredDepotThisTick() /* Store the position of the effect as the vehicle pointer will become invalid later */
* We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that int x = v->x_pos;
* they are already leaving the depot again before being replaced. */ int y = v->y_pos;
if (v->leave_depot_instantly) { int z = v->z_pos;
v->leave_depot_instantly = false;
v->vehstatus &= ~VS_STOPPED;
}
/* Store the position of the effect as the vehicle pointer will become invalid later */ const Company *c = GetCompany(_current_company);
int x = v->x_pos; SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->engine_renew_money));
int y = v->y_pos; CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
int z = v->z_pos; SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->engine_renew_money));
const Company *c = GetCompany(_current_company); if (!IsLocalCompany()) continue;
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 (res.Succeeded()) {
if (res.Succeeded()) { ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
ShowCostOrIncomeAnimation(x, y, z, res.GetCost()); continue;
} 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;
} }
_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 /** 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)); CommandCost cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
if (CmdFailed(cost)) { 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) { if (v->owner == _local_company) {
/* Notify the user that we stopped the vehicle */ /* Notify the user that we stopped the vehicle */
SetDParam(0, _vehicle_type_names[v->type]); SetDParam(0, _vehicle_type_names[v->type]);
@ -2432,6 +2414,8 @@ static void Save_VEHS()
/** Will be called when vehicles need to be loaded. */ /** Will be called when vehicles need to be loaded. */
void Load_VEHS() void Load_VEHS()
{ {
_vehicles_to_autoreplace.Reset();
int index; int index;
Vehicle *v; 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 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 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 char *name; ///< Name of vehicle
TileIndex tile; ///< Current tile index TileIndex tile; ///< Current tile index
@ -309,8 +307,6 @@ public:
Order *orders; ///< Pointer to the first order for this vehicle 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) byte vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
uint16 load_unload_time_rem; uint16 load_unload_time_rem;