Changeset - r10490:36e425ea6fc5
[Not reviewed]
master
0 2 0
rubidium - 15 years ago 2008-12-26 18:26:11
rubidium@openttd.org
(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).
2 files changed with 71 insertions and 91 deletions:
0 comments (0 inline, 0 general)
src/vehicle.cpp
Show inline comments
 
@@ -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;
 
	}
 

	
 
	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;
 
	}
 
	/* 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;
 
}
 

	
 
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;
 

	
 
			/* 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;
 
	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;
 

	
 
		/* 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;
 

	
 
		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()) continue;
 

	
 
		if (res.Succeeded()) {
 
			ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
 
			continue;
 
		}
 

	
 
		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();
 
			}
 

	
 
			/* 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));
 

	
 
			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;
 
		}
 
		_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;
 

	
src/vehicle_base.h
Show inline comments
 
@@ -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;
 

	
0 comments (0 inline, 0 general)