--- a/src/vehicle.cpp Mon May 26 20:45:25 2008 +0000
+++ b/src/vehicle.cpp Tue May 27 00:50:55 2008 +0000
@@ -50,6 +50,7 @@
#include "depot_map.h"
#include "animated_tile_func.h"
#include "effectvehicle_base.h"
+#include "core/alloc_func.hpp"
#include "table/sprites.h"
#include "table/strings.h"
@@ -58,7 +59,7 @@
#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
VehicleID _vehicle_id_ctr_day;
-Vehicle *_place_clicked_vehicle;
+const Vehicle *_place_clicked_vehicle;
VehicleID _new_vehicle_id;
uint16 _returned_refit_capacity;
@@ -126,20 +127,20 @@
{
if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
- if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
+ if (_settings.order.no_servicing_if_no_breakdowns && _settings.difficulty.vehicle_breakdowns == 0) {
/* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off.
* Note: If servicing is enabled, we postpone replacement till next service. */
return EngineHasReplacementForPlayer(GetPlayer(this->owner), this->engine_type, this->group_id);
}
- return _patches.servint_ispercent ?
+ return _settings.vehicle.servint_ispercent ?
(this->reliability < GetEngine(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
(this->date_of_last_service + this->service_interval < _date);
}
bool Vehicle::NeedsAutomaticServicing() const
{
- if (_patches.gotodepot && VehicleHasDepotOrders(this)) return false;
+ if (_settings.order.gotodepot && VehicleHasDepotOrders(this)) return false;
if (this->current_order.IsType(OT_LOADING)) return false;
if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false;
return NeedsServicing();
@@ -531,6 +532,12 @@
return v;
}
+const Vehicle *GetLastVehicleInChain(const Vehicle *v)
+{
+ while (v->Next() != NULL) v = v->Next();
+ return v;
+}
+
uint CountVehiclesInChain(const Vehicle* v)
{
uint count = 0;
@@ -906,7 +913,7 @@
if ((rel_old >> 8) != (rel >> 8)) InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
if (v->breakdown_ctr != 0 || v->vehstatus & VS_STOPPED ||
- _opt.diff.vehicle_breakdowns < 1 ||
+ _settings.difficulty.vehicle_breakdowns < 1 ||
v->cur_speed < 5 || _game_mode == GM_MENU) {
return;
}
@@ -923,7 +930,7 @@
if (v->type == VEH_SHIP) rel += 0x6666;
/* reduced breakdowns? */
- if (_opt.diff.vehicle_breakdowns == 1) rel += 0x6666;
+ if (_settings.difficulty.vehicle_breakdowns == 1) rel += 0x6666;
/* check if to break down */
if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) {
@@ -982,9 +989,7 @@
*/
CommandCost CmdMassStartStopVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
- Vehicle **vl = NULL;
- uint16 engine_list_length = 0;
- uint16 engine_count = 0;
+ VehicleList list;
CommandCost return_value = CMD_ERROR;
uint stop_command;
VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5);
@@ -1003,14 +1008,14 @@
uint32 id = p1;
uint16 window_type = p2 & VLW_MASK;
- engine_count = GenerateVehicleSortList((const Vehicle***)&vl, &engine_list_length, vehicle_type, _current_player, id, window_type);
+ GenerateVehicleSortList(&list, vehicle_type, _current_player, id, window_type);
} else {
/* Get the list of vehicles in the depot */
- BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
+ BuildDepotVehicleList(vehicle_type, tile, &list, NULL);
}
- for (uint i = 0; i < engine_count; i++) {
- const Vehicle *v = vl[i];
+ for (uint i = 0; i < list.Length(); i++) {
+ const Vehicle *v = list[i];
if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;
@@ -1032,7 +1037,6 @@
}
}
- free(vl);
return return_value;
}
@@ -1044,15 +1048,10 @@
*/
CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
- Vehicle **engines = NULL;
- Vehicle **wagons = NULL;
- uint16 engine_list_length = 0;
- uint16 engine_count = 0;
- uint16 wagon_list_length = 0;
- uint16 wagon_count = 0;
+ VehicleList list;
CommandCost cost(EXPENSES_NEW_VEHICLES);
- uint sell_command, total_number_vehicles;
+ uint sell_command;
VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
switch (vehicle_type) {
@@ -1064,26 +1063,13 @@
}
/* Get the list of vehicles in the depot */
- BuildDepotVehicleList(vehicle_type, tile, &engines, &engine_list_length, &engine_count,
- &wagons, &wagon_list_length, &wagon_count);
-
- total_number_vehicles = engine_count + wagon_count;
- for (uint i = 0; i < total_number_vehicles; i++) {
- const Vehicle *v;
-
- if (i < engine_count) {
- v = engines[i];
- } else {
- v = wagons[i - engine_count];
- }
-
- CommandCost ret = DoCommand(tile, v->index, 1, flags, sell_command);
-
+ BuildDepotVehicleList(vehicle_type, tile, &list, &list);
+
+ for (uint i = 0; i < list.Length(); i++) {
+ CommandCost ret = DoCommand(tile, list[i]->index, 1, flags, sell_command);
if (CmdSucceeded(ret)) cost.AddCost(ret);
}
- free(engines);
- free(wagons);
if (cost.GetCost() == 0) return CMD_ERROR; // no vehicles to sell
return cost;
}
@@ -1099,9 +1085,7 @@
*/
CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
- Vehicle **vl = NULL;
- uint16 engine_list_length = 0;
- uint16 engine_count = 0;
+ VehicleList list;
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES);
VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
bool all_or_nothing = HasBit(p2, 0);
@@ -1109,10 +1093,10 @@
if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
/* Get the list of vehicles in the depot */
- BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, &vl, &engine_list_length, &engine_count);
-
- for (uint i = 0; i < engine_count; i++) {
- Vehicle *v = vl[i];
+ BuildDepotVehicleList(vehicle_type, tile, &list, &list);
+
+ for (uint i = 0; i < list.Length(); i++) {
+ Vehicle *v = (Vehicle*)list[i];
/* Ensure that the vehicle completely in the depot */
if (!v->IsInDepot()) continue;
@@ -1127,22 +1111,18 @@
* We should never reach this if DC_EXEC is set since then it should
* have failed the estimation guess. */
assert(!(flags & DC_EXEC));
- /* Now we will have to return an error.
- * This goto will leave the loop and it's ok to do so because
- * there is no point in the rest of the loop. */
- goto error;
+ /* Now we will have to return an error. */
+ return CMD_ERROR;
}
}
}
if (cost.GetCost() == 0) {
-error:
/* Either we didn't replace anything or something went wrong.
* Either way we want to return an error and not execute this command. */
cost = CMD_ERROR;
}
- free(vl);
return cost;
}
@@ -1311,100 +1291,55 @@
return total_cost;
}
-
-/* Extend the list size for BuildDepotVehicleList() */
-static inline void ExtendVehicleListSize(const Vehicle ***engine_list, uint16 *engine_list_length, uint16 step_size)
-{
- *engine_list_length = min(*engine_list_length + step_size, GetMaxVehicleIndex() + 1);
- *engine_list = ReallocT(*engine_list, *engine_list_length);
-}
-
-/** Generates a list of vehicles inside a depot
- * Will enlarge allocated space for the list if they are too small, so it's ok to call with (pointer to NULL array, pointer to uninitised uint16, pointer to 0)
- * If one of the lists is not needed (say wagons when finding ships), all the pointers regarding that list should be set to NULL
- * @param type Type of vehicle
- * @param tile The tile the depot is located in
- * @param ***engine_list Pointer to a pointer to an array of vehicles in the depot (old list is freed and a new one is malloced)
- * @param *engine_list_length Allocated size of engine_list. Needs to be set to 0 when engine_list points to a NULL array
- * @param *engine_count The number of engines stored in the list
- * @param ***wagon_list Pointer to a pointer to an array of free wagons in the depot (old list is freed and a new one is malloced)
- * @param *wagon_list_length Allocated size of wagon_list. Needs to be set to 0 when wagon_list points to a NULL array
- * @param *wagon_count The number of engines stored in the list
+/**
+ * Generate a list of vehicles inside a depot.
+ * @param type Type of vehicle
+ * @param tile The tile the depot is located on
+ * @param engines Pointer to list to add vehicles to
+ * @param wagons Pointer to list to add wagons to (can be NULL)
*/
-void BuildDepotVehicleList(VehicleType type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count)
+void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engines, VehicleList *wagons)
{
- Vehicle *v;
-
- /* This function should never be called without an array to store results */
- assert(!(engine_list == NULL && type != VEH_TRAIN));
- assert(!(type == VEH_TRAIN && engine_list == NULL && wagon_list == NULL));
-
- /* Both array and the length should either be NULL to disable the list or both should not be NULL */
- assert((engine_list == NULL && engine_list_length == NULL) || (engine_list != NULL && engine_list_length != NULL));
- assert((wagon_list == NULL && wagon_list_length == NULL) || (wagon_list != NULL && wagon_list_length != NULL));
-
- assert(!(engine_list != NULL && engine_count == NULL));
- assert(!(wagon_list != NULL && wagon_count == NULL));
-
- if (engine_count != NULL) *engine_count = 0;
- if (wagon_count != NULL) *wagon_count = 0;
-
- switch (type) {
- case VEH_TRAIN:
- FOR_ALL_VEHICLES(v) {
- if (v->tile == tile && v->type == VEH_TRAIN && v->u.rail.track == TRACK_BIT_DEPOT) {
- if (IsFrontEngine(v)) {
- if (engine_list == NULL) continue;
- if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
- (*engine_list)[(*engine_count)++] = v;
- } else if (IsFreeWagon(v)) {
- if (wagon_list == NULL) continue;
- if (*wagon_count == *wagon_list_length) ExtendVehicleListSize((const Vehicle***)wagon_list, wagon_list_length, 25);
- (*wagon_list)[(*wagon_count)++] = v;
- }
+ engines->Clear();
+ if (wagons != NULL && wagons != engines) wagons->Clear();
+
+ const Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ /* General tests for all vehicle types */
+ if (v->type != type) continue;
+ if (v->tile != tile) continue;
+
+ switch (type) {
+ case VEH_TRAIN:
+ if (v->u.rail.track != TRACK_BIT_DEPOT) continue;
+ if (wagons != NULL && IsFreeWagon(v)) {
+ *wagons->Append() = v;
+ continue;
}
- }
- break;
-
- case VEH_ROAD:
- FOR_ALL_VEHICLES(v) {
- if (v->tile == tile && v->type == VEH_ROAD && v->IsInDepot() && IsRoadVehFront(v)) {
- if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
- (*engine_list)[(*engine_count)++] = v;
- }
- }
- break;
-
- case VEH_SHIP:
- FOR_ALL_VEHICLES(v) {
- if (v->tile == tile && v->type == VEH_SHIP && v->IsInDepot()) {
- if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
- (*engine_list)[(*engine_count)++] = v;
- }
- }
- break;
-
- case VEH_AIRCRAFT:
- FOR_ALL_VEHICLES(v) {
- if (v->tile == tile &&
- v->type == VEH_AIRCRAFT && IsNormalAircraft(v) &&
- v->IsInDepot()) {
- if (*engine_count == *engine_list_length) ExtendVehicleListSize((const Vehicle***)engine_list, engine_list_length, 25);
- (*engine_list)[(*engine_count)++] = v;
- }
- }
- break;
-
- default: NOT_REACHED();
+ break;
+
+ default:
+ if (!v->IsInDepot()) continue;
+ break;
+ }
+
+ if (!v->IsPrimaryVehicle()) continue;
+
+ *engines->Append() = v;
}
+
+ /* Ensure the lists are not wasting too much space. If the lists are fresh
+ * (i.e. built within a command) then this will actually do nothing. */
+ engines->Compact();
+ if (wagons != NULL && wagons != engines) wagons->Compact();
}
/**
- * @param sort_list list to store the list in. Either NULL or the length length_of_array tells
- * @param length_of_array informs the length allocated for sort_list. This is not the same as the number of vehicles in the list. Needs to be 0 when sort_list is NULL
- * @param type type of vehicle
- * @param owner PlayerID of owner to generate a list for
- * @param index This parameter has different meanings depending on window_type
+ * Generate a list of vehicles based on window type.
+ * @param list Pointer to list to add vehicles to
+ * @param type Type of vehicle
+ * @param owner Player to generate list for
+ * @param index This parameter has different meanings depending on window_type
* <ul>
* <li>VLW_STATION_LIST: index of station to generate a list for</li>
* <li>VLW_SHARED_ORDERS: index of order to generate a list for<li>
@@ -1412,83 +1347,71 @@
* <li>VLW_DEPOT_LIST: TileIndex of the depot/hangar to make the list for</li>
* <li>VLW_GROUP_LIST: index of group to generate a list for</li>
* </ul>
- * @param window_type tells what kind of window the list is for. Use the VLW flags in vehicle_gui.h
- * @return the number of vehicles added to the list
+ * @param window_type The type of window the list is for, using the VLW_ flags in vehicle_gui.h
*/
-uint GenerateVehicleSortList(const Vehicle ***sort_list, uint16 *length_of_array, VehicleType type, PlayerID owner, uint32 index, uint16 window_type)
+void GenerateVehicleSortList(VehicleList *list, VehicleType type, PlayerID owner, uint32 index, uint16 window_type)
{
- uint n = 0;
+ list->Clear();
+
const Vehicle *v;
switch (window_type) {
- case VLW_STATION_LIST: {
+ case VLW_STATION_LIST:
FOR_ALL_VEHICLES(v) {
if (v->type == type && v->IsPrimaryVehicle()) {
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
if (order->IsType(OT_GOTO_STATION) && order->GetDestination() == index) {
- if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
- (*sort_list)[n++] = v;
+ *list->Append() = v;
break;
}
}
}
}
break;
- }
-
- case VLW_SHARED_ORDERS: {
+
+ case VLW_SHARED_ORDERS:
FOR_ALL_VEHICLES(v) {
/* Find a vehicle with the order in question */
- if (v->orders != NULL && v->orders->index == index) break;
- }
-
- if (v != NULL && v->orders != NULL && v->orders->index == index) {
- /* Only try to make the list if we found a vehicle using the order in question */
- for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
- if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
- (*sort_list)[n++] = v;
+ if (v->orders != NULL && v->orders->index == index) {
+ /* Add all vehicles from this vehicle's shared order list */
+ for (v = GetFirstVehicleFromSharedList(v); v != NULL; v = v->next_shared) {
+ *list->Append() = v;
+ }
+ break;
}
}
break;
- }
-
- case VLW_STANDARD: {
+
+ case VLW_STANDARD:
FOR_ALL_VEHICLES(v) {
if (v->type == type && v->owner == owner && v->IsPrimaryVehicle()) {
- /* TODO find a better estimate on the total number of vehicles for current player */
- if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles() / 4);
- (*sort_list)[n++] = v;
+ *list->Append() = v;
}
}
break;
- }
-
- case VLW_DEPOT_LIST: {
+
+ case VLW_DEPOT_LIST:
FOR_ALL_VEHICLES(v) {
if (v->type == type && v->IsPrimaryVehicle()) {
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == index) {
- if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
- (*sort_list)[n++] = v;
+ *list->Append() = v;
break;
}
}
}
}
break;
- }
case VLW_GROUP_LIST:
FOR_ALL_VEHICLES(v) {
if (v->type == type && v->IsPrimaryVehicle() &&
v->owner == owner && v->group_id == index) {
- if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, GetNumVehicles() / 4);
-
- (*sort_list)[n++] = v;
+ *list->Append() = v;
}
}
break;
@@ -1496,16 +1419,7 @@
default: NOT_REACHED(); break;
}
- if ((n + 100) < *length_of_array) {
- /* We allocated way too much for sort_list.
- * Now we will reduce how much we allocated.
- * We will still make it have room for 50 extra vehicles to prevent having
- * to move the whole array if just one vehicle is added later */
- *length_of_array = n + 50;
- *sort_list = ReallocT(*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
- }
-
- return n;
+ list->Compact();
}
/**
@@ -1519,14 +1433,13 @@
*/
CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id)
{
- const Vehicle **sort_list = NULL;
- uint16 array_length = 0;
-
- uint n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, vlw_flag);
+ VehicleList list;
+
+ GenerateVehicleSortList(&list, type, owner, id, vlw_flag);
/* Send all the vehicles to a depot */
- for (uint i = 0; i < n; i++) {
- const Vehicle *v = sort_list[i];
+ for (uint i = 0; i < list.Length(); i++) {
+ const Vehicle *v = list[i];
CommandCost ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type));
/* Return 0 if DC_EXEC is not set this is a valid goto depot command)
@@ -1534,12 +1447,10 @@
* and we will issue the command. We can now safely quit the loop, knowing
* it will succeed at least once. With DC_EXEC we really need to send them to the depot */
if (CmdSucceeded(ret) && !(flags & DC_EXEC)) {
- free((void*)sort_list);
return CommandCost();
}
}
- free((void*)sort_list);
return (flags & DC_EXEC) ? CommandCost() : CMD_ERROR;
}
@@ -1733,7 +1644,7 @@
if (flags & DC_EXEC) {
free(v->name);
v->name = strdup(_cmd_text);
- ResortVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 1);
MarkWholeScreenDirty();
}
@@ -1915,10 +1826,10 @@
static UnitID gmax = 0;
switch (type) {
- case VEH_TRAIN: max = _patches.max_trains; break;
- case VEH_ROAD: max = _patches.max_roadveh; break;
- case VEH_SHIP: max = _patches.max_ships; break;
- case VEH_AIRCRAFT: max = _patches.max_aircraft; break;
+ case VEH_TRAIN: max = _settings.vehicle.max_trains; break;
+ case VEH_ROAD: max = _settings.vehicle.max_roadveh; break;
+ case VEH_SHIP: max = _settings.vehicle.max_ships; break;
+ case VEH_AIRCRAFT: max = _settings.vehicle.max_aircraft; break;
default: NOT_REACHED();
}
@@ -1968,14 +1879,14 @@
assert(IsPlayerBuildableVehicleType(type));
if (!IsValidPlayer(_current_player)) return false;
- if (_patches.always_build_infrastructure) return true;
+ if (_settings.gui.always_build_infrastructure) return true;
UnitID max;
switch (type) {
- case VEH_TRAIN: max = _patches.max_trains; break;
- case VEH_ROAD: max = _patches.max_roadveh; break;
- case VEH_SHIP: max = _patches.max_ships; break;
- case VEH_AIRCRAFT: max = _patches.max_aircraft; break;
+ case VEH_TRAIN: max = _settings.vehicle.max_trains; break;
+ case VEH_ROAD: max = _settings.vehicle.max_roadveh; break;
+ case VEH_SHIP: max = _settings.vehicle.max_ships; break;
+ case VEH_AIRCRAFT: max = _settings.vehicle.max_aircraft; break;
default: NOT_REACHED();
}
@@ -2007,7 +1918,7 @@
/* The default livery is always available for use, but its in_use flag determines
* whether any _other_ liveries are in use. */
- if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) {
+ if (p->livery[LS_DEFAULT].in_use && (_settings.gui.liveries == 2 || (_settings.gui.liveries == 1 && player == _local_player))) {
/* Determine the livery scheme to use */
switch (GetEngine(engine_type)->type) {
default: NOT_REACHED();
@@ -2576,7 +2487,7 @@
/* Not the first call for this tick, or still loading */
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
- (_patches.timetabling && this->current_order_time < wait_time)) return;
+ (_settings.order.timetabling && this->current_order_time < wait_time)) return;
this->PlayLeaveStationSound();
@@ -2807,11 +2718,11 @@
{
if (!ContainsBackup()) return v;
if (v != NULL) {
- ChangeVehicleViewWindow(v, INVALID_VEHICLE);
+ ChangeVehicleViewWindow(v->index, INVALID_VEHICLE);
DoCommand(0, v->index, 1, DC_EXEC, GetCmdSellVeh(v));
}
v = RestoreBackupVehicle(this->vehicles, p);
- ChangeVehicleViewWindow(INVALID_VEHICLE, v);
+ ChangeVehicleViewWindow(INVALID_VEHICLE, v->index);
if (orders != NULL) RestoreVehicleOrdersBruteForce(v, orders);
if (economy != NULL) economy->Restore();
/* If we stored cargo as well then we should restore it. */