summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ai.c2
-rw-r--r--ai_new.c14
-rw-r--r--aircraft_cmd.c53
-rw-r--r--aircraft_gui.c17
-rw-r--r--misc.c4
-rw-r--r--oldloader.c51
-rw-r--r--order.h124
-rw-r--r--order_cmd.c1007
-rw-r--r--order_gui.c204
-rw-r--r--rail_cmd.c5
-rw-r--r--roadveh_cmd.c44
-rw-r--r--saveload.c12
-rw-r--r--saveload.h10
-rw-r--r--ship_cmd.c53
-rw-r--r--ship_gui.c23
-rw-r--r--station.h2
-rw-r--r--station_cmd.c7
-rw-r--r--train_cmd.c98
-rw-r--r--ttd.c1
-rw-r--r--vehicle.c203
-rw-r--r--vehicle.h132
-rw-r--r--vehicle_gui.c8
22 files changed, 1249 insertions, 825 deletions
diff --git a/ai.c b/ai.c
index 0bd26e46f..3560ad639 100644
--- a/ai.c
+++ b/ai.c
@@ -3618,7 +3618,7 @@ static void AiStateRemoveStation(Player *p)
// Get a list of all stations that are in use by a vehicle
memset(in_use, 0, sizeof(in_use));
- for (ord = _order_array; ord != _ptr_to_next_order; ++ord) {
+ FOR_ALL_ORDERS(ord) {
if (ord->type == OT_GOTO_STATION)
in_use[ord->station] = 1;
}
diff --git a/ai_new.c b/ai_new.c
index 91219642e..c209ab1ba 100644
--- a/ai_new.c
+++ b/ai_new.c
@@ -502,14 +502,12 @@ static bool AiNew_CheckVehicleStation(Player *p, Station *st) {
// Also check if we don't have already a lot of busses to this city...
FOR_ALL_VEHICLES(v) {
if (v->owner == _current_player) {
- const Order *sched = v->schedule_ptr;
- if (sched != NULL) {
- for (; sched->type != OT_NOTHING; ++sched) {
- if (sched->type == OT_GOTO_STATION &&
- GetStation(sched->station) == st) {
- // This vehicle has this city in his list
- count++;
- }
+ const Order *order;
+
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->type == OT_GOTO_STATION && GetStation(order->station) == st) {
+ // This vehicle has this city in its list
+ count++;
}
}
}
diff --git a/aircraft_cmd.c b/aircraft_cmd.c
index 4fa94a345..c241155ac 100644
--- a/aircraft_cmd.c
+++ b/aircraft_cmd.c
@@ -126,7 +126,7 @@ int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
// allocate 2 or 3 vehicle structs, depending on type
if (!AllocateVehicles(vl, (avi->subtype & 1) == 0 ? 3 : 2) ||
- _ptr_to_next_order >= endof(_order_array))
+ IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
unit_num = GetFreeUnitNumber(VEH_Aircraft);
@@ -200,9 +200,6 @@ int32 CmdBuildAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_new_aircraft_id = v->index;
- _ptr_to_next_order->type = OT_NOTHING;
- _ptr_to_next_order->flags = 0;
- v->schedule_ptr = _ptr_to_next_order++;
// the AI doesn't click on a tile to build airplanes, so the below code will
// never work. Therefore just assume the AI's planes always come from Hangar0
// On hold for NewAI
@@ -490,7 +487,7 @@ static void CheckIfAircraftNeedsService(Vehicle *v)
v->current_order.flags & OF_FULL_LOAD)
return;
- if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
+ if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
st = GetStation(v->current_order.station);
@@ -510,13 +507,13 @@ static void CheckIfAircraftNeedsService(Vehicle *v)
void InvalidateAircraftWindows(const Vehicle *v)
{
- const Order *o;
+ const Order *order;
InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
- for ( o = v->schedule_ptr; o->type != OT_NOTHING; o++) {
- if (o->type == OT_GOTO_STATION ) {
- InvalidateWindow(WC_AIRCRAFT_LIST, o->station << 16 | v->owner);
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->type == OT_GOTO_STATION ) {
+ InvalidateWindow(WC_AIRCRAFT_LIST, (order->station << 16) | v->owner);
}
}
}
@@ -1024,21 +1021,9 @@ static void HandleAircraftSmoke(Vehicle *v)
}
}
-// returns true if the vehicle does have valid orders
-// false if none are valid
-static bool CheckForValidOrders(Vehicle *v)
-{
- int i;
- for (i = 0; i < v->num_orders; i++) {
- if( v->schedule_ptr[i].type != OT_DUMMY )
- return true;
- }
- return false;
-}
-
static void ProcessAircraftOrder(Vehicle *v)
{
- Order order;
+ Order *order;
// OT_GOTO_DEPOT, OT_LOADING
if (v->current_order.type == OT_GOTO_DEPOT ||
@@ -1057,32 +1042,32 @@ static void ProcessAircraftOrder(Vehicle *v)
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
- order = v->schedule_ptr[v->cur_order_index];
+ order = GetVehicleOrder(v, v->cur_order_index);
- if (order.type == OT_NOTHING) {
+ if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
return;
}
- if ( order.type == OT_DUMMY && !CheckForValidOrders(v))
+ if (order->type == OT_DUMMY && !CheckForValidOrders(v))
CrashAirplane(v);
- if (order.type == v->current_order.type &&
- order.flags == v->current_order.flags &&
- order.station == v->current_order.station)
+ if (order->type == v->current_order.type &&
+ order->flags == v->current_order.flags &&
+ order->station == v->current_order.station)
return;
- v->current_order = order;
+ v->current_order = *order;
// orders are changed in flight, ensure going to the right station
- if (order.type == OT_GOTO_STATION && v->u.air.state == FLYING) {
+ if (order->type == OT_GOTO_STATION && v->u.air.state == FLYING) {
AircraftNextAirportPos_and_Order(v);
- v->u.air.targetairport = order.station;
+ v->u.air.targetairport = order->station;
}
- InvalidateVehicleOrderWidget(v);
-
+ InvalidateVehicleOrder(v);
+
InvalidateAircraftWindows(v);
}
@@ -1116,7 +1101,7 @@ static void HandleAircraftLoading(Vehicle *v, int mode)
}
}
v->cur_order_index++;
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
}
static void CrashAirplane(Vehicle *v)
diff --git a/aircraft_gui.c b/aircraft_gui.c
index a2f6fd79c..31a081f27 100644
--- a/aircraft_gui.c
+++ b/aircraft_gui.c
@@ -920,16 +920,13 @@ void ShowAircraftDepotWindow(uint tile)
}
}
-static void DrawSmallSchedule(Vehicle *v, int x, int y) {
- const Order *sched;
- int sel;
- Order ord;
- int i = 0;
+static void DrawSmallOrderList(Vehicle *v, int x, int y) {
+ const Order *order;
+ int sel, i = 0;
- sched = v->schedule_ptr;
sel = v->cur_order_index;
- while ((ord = *sched++).type != OT_NOTHING) {
+ FOR_VEHICLE_ORDERS(v, order) {
if (sel == 0) {
_stringwidth_base = 0xE0;
DoDrawString( "\xAF", x-6, y, 16);
@@ -937,8 +934,8 @@ static void DrawSmallSchedule(Vehicle *v, int x, int y) {
}
sel--;
- if (ord.type == OT_GOTO_STATION) {
- SetDParam(0, ord.station);
+ if (order->type == OT_GOTO_STATION) {
+ SetDParam(0, order->station);
DrawString(x, y, STR_A036, 0);
y += 6;
@@ -1052,7 +1049,7 @@ static void PlayerAircraftWndProc(Window *w, WindowEvent *e)
DrawString(x + 19, y, STR_01AB, 0);
}
- DrawSmallSchedule(v, x + 136, y);
+ DrawSmallOrderList(v, x + 136, y);
y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
}
diff --git a/misc.c b/misc.c
index da2ad80ee..1e2a0024a 100644
--- a/misc.c
+++ b/misc.c
@@ -150,6 +150,8 @@ void CSleep(int milliseconds)
#endif
}
+void InitializeVehicles();
+void InitializeOrders();
void InitializeClearLand();
void InitializeRail();
void InitializeRailGui();
@@ -206,7 +208,7 @@ void InitializeGame()
}
InitializeVehicles();
- _backup_orders_tile = 0;
+ InitializeOrders();
InitNewsItemStructs();
InitializeLandscape();
diff --git a/oldloader.c b/oldloader.c
index cdeafa622..16c08d744 100644
--- a/oldloader.c
+++ b/oldloader.c
@@ -752,6 +752,22 @@ static void FixDepot(Depot *n, OldDepot *o, int num)
} while (n++,o++,--num);
}
+static void FixOrder(uint16 *o, int num)
+{
+ Order *order;
+ int i;
+
+ for (i = 0; i < num; ++i) {
+ order = GetOrder(i);
+ AssignOrder(order, UnpackOldOrder(*o));
+ /* Recover the next list */
+ if (i > 0 && order->type != OT_NOTHING)
+ GetOrder(i - 1)->next = order;
+
+ o++;
+ }
+}
+
static void FixVehicle(OldVehicle *o, int num)
{
Vehicle *n;
@@ -767,10 +783,9 @@ static void FixVehicle(OldVehicle *o, int num)
n->subtype = o->subtype;
if (o->schedule_ptr == 0xFFFFFFFF || o->schedule_ptr == 0) {
- n->schedule_ptr = NULL;
+ n->orders = NULL;
} else {
- n->schedule_ptr = _order_array + REMAP_ORDER_IDX(o->schedule_ptr);
- assert(n->schedule_ptr >= _order_array && n->schedule_ptr < _ptr_to_next_order);
+ n->orders = GetOrder(REMAP_ORDER_IDX(o->schedule_ptr));
}
n->current_order.type = o->next_order & 0x0f;
@@ -870,6 +885,31 @@ static void FixVehicle(OldVehicle *o, int num)
break;
}
} while (i++,o++,--num);
+
+ /* Check for shared orders, and link them correctly */
+ {
+ Vehicle *v;
+
+ FOR_ALL_VEHICLES(v) {
+ Vehicle *u;
+
+ if (v->type == 0)
+ continue;
+
+ FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
+ if (u->type == 0)
+ continue;
+
+ /* If a vehicle has the same orders, add the link to eachother
+ in both vehicles */
+ if (v->orders == u->orders) {
+ v->next_shared = u;
+ u->prev_shared = v;
+ break;
+ }
+ }
+ }
+ }
}
static void FixSubsidy(Subsidy *n, OldSubsidy *o, int num)
@@ -1447,15 +1487,12 @@ bool LoadOldSaveGame(const char *file)
}
}
- for (i = 0; i < lengthof(m->order_list); ++i)
- _order_array[i] = UnpackOldOrder(m->order_list[i]);
- _ptr_to_next_order = _order_array + REMAP_ORDER_IDX(m->ptr_to_next_order);
-
FixTown(m->town_list, lengthof(m->town_list), m->town_name_type);
FixIndustry(m->industries, lengthof(m->industries));
FixStation(m->stations, lengthof(m->stations));
FixDepot(_depots, m->depots, lengthof(m->depots));
+ FixOrder(m->order_list, lengthof(m->order_list));
FixVehicle(m->vehicles, lengthof(m->vehicles));
FixSubsidy(_subsidies, m->subsidies, lengthof(m->subsidies));
diff --git a/order.h b/order.h
new file mode 100644
index 000000000..dc7da1fa7
--- /dev/null
+++ b/order.h
@@ -0,0 +1,124 @@
+#ifndef ORDER_H
+#define ORDER_H
+
+/* Order types */
+enum {
+ OT_NOTHING = 0,
+ OT_GOTO_STATION = 1,
+ OT_GOTO_DEPOT = 2,
+ OT_LOADING = 3,
+ OT_LEAVESTATION = 4,
+ OT_DUMMY = 5,
+ OT_GOTO_WAYPOINT = 6
+};
+
+/* Order flags -- please use OFB instead OF and use HASBIT/SETBIT/CLEARBIT */
+enum {
+ OF_UNLOAD = 0x2,
+ OF_FULL_LOAD = 0x4, // Also used when to force an aircraft into a depot
+ OF_NON_STOP = 0x8
+};
+
+/* Order flags bits */
+enum {
+ OFB_UNLOAD = 1,
+ OFB_FULL_LOAD = 2,
+ OFB_NON_STOP = 3
+};
+
+/* Possible clone options */
+enum {
+ CO_SHARE = 0,
+ CO_COPY = 1,
+ CO_UNSHARE = 2
+};
+
+/* If you change this, keep in mind that it is saved on 3 places:
+ - Load_ORDR, all the global orders
+ - Vehicle -> current_order
+ - REF_SHEDULE (all REFs are currently limited to 16 bits!!) */
+typedef struct Order {
+ uint8 type;
+ uint8 flags;
+ uint16 station;
+
+ struct Order *next; //! Pointer to next order. If NULL, end of list
+
+ uint16 index; //! Index of the order, is not saved or anything, just for reference
+} Order;
+
+typedef struct {
+ VehicleID clone;
+ byte orderindex;
+ Order order[41];
+ uint16 service_interval;
+ char name[32];
+} BackuppedOrders;
+
+VARDEF TileIndex _backup_orders_tile;
+VARDEF BackuppedOrders _backup_orders_data[1];
+
+VARDEF Order _orders[5000];
+VARDEF uint32 _orders_size;
+
+static inline Order *GetOrder(uint index)
+{
+ assert(index < _orders_size);
+ return &_orders[index];
+}
+
+#define FOR_ALL_ORDERS_FROM(o, from) for(o = GetOrder(from); o != &_orders[_orders_size]; o++)
+#define FOR_ALL_ORDERS(o) FOR_ALL_ORDERS_FROM(o, 0)
+
+#define FOR_VEHICLE_ORDERS(v, order) for (order = v->orders; order != NULL; order = order->next)
+
+static inline bool HasOrderPoolFree(uint amount)
+{
+ Order *order;
+
+ FOR_ALL_ORDERS(order)
+ if (order->type == OT_NOTHING)
+ if (--amount == 0)
+ return true;
+
+ return false;
+}
+
+static inline bool IsOrderPoolFull()
+{
+ return !HasOrderPoolFree(1);
+}
+
+/* Pack and unpack routines */
+
+static inline uint32 PackOrder(const Order *order)
+{
+ return order->station << 16 | order->flags << 8 | order->type;
+}
+
+static inline Order UnpackOrder(uint32 packed)
+{
+ Order order;
+ order.type = (packed & 0x000000FF);
+ order.flags = (packed & 0x0000FF00) >> 8;
+ order.station = (packed & 0xFFFF0000) >> 16;
+ order.next = NULL;
+ return order;
+}
+
+/* Functions */
+void BackupVehicleOrders(Vehicle *v, BackuppedOrders *order);
+void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *order);
+void DeleteDestinationFromVehicleOrder(Order dest);
+void InvalidateVehicleOrder(const Vehicle *v);
+bool VehicleHasDepotOrders(const Vehicle *v);
+bool CheckOrders(const Vehicle *v);
+void DeleteVehicleOrders(Vehicle *v);
+bool IsOrderListShared(const Vehicle *v);
+void AssignOrder(Order *order, Order data);
+bool CheckForValidOrders(Vehicle *v);
+
+Order UnpackVersion4Order(uint16 packed);
+Order UnpackOldOrder(uint16 packed);
+
+#endif /* ORDER_H */
diff --git a/order_cmd.c b/order_cmd.c
index 7332b0513..1e074bcd4 100644
--- a/order_cmd.c
+++ b/order_cmd.c
@@ -6,27 +6,139 @@
#include "station.h"
#include "player.h"
#include "news.h"
+#include "saveload.h"
-/* p1 & 0xFFFF = vehicle
- * p1 >> 16 = index in order list
- * p2 = order command to insert
+/**
+ *
+ * Unpacks a order from savegames made with TTD(Patch)
+ *
*/
-int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+Order UnpackOldOrder(uint16 packed)
{
- Vehicle *v = GetVehicle(p1 & 0xFFFF);
- int sel = p1 >> 16;
- Order new_order = UnpackOrder(p2);
+ Order order;
+ order.type = (packed & 0x000F);
+ order.flags = (packed & 0x00F0) >> 4;
+ order.station = (packed & 0xFF00) >> 8;
+ order.next = NULL;
+
+ // Sanity check
+ // TTD stores invalid orders as OT_NOTHING with non-zero flags/station
+ if (order.type == OT_NOTHING && (order.flags != 0 || order.station != 0)) {
+ order.type = OT_DUMMY;
+ order.flags = 0;
+ }
+
+ return order;
+}
+
+/**
+ *
+ * Unpacks a order from savegames with version 4 and lower
+ *
+ */
+Order UnpackVersion4Order(uint16 packed)
+{
+ Order order;
+ order.type = (packed & 0x000F);
+ order.flags = (packed & 0x00F0) >> 4;
+ order.station = (packed & 0xFF00) >> 8;
+ order.next = NULL;
+ return order;
+}
+
+/**
+ *
+ * Updates the widgets of a vehicle which contains the order-data
+ *
+ */
+void InvalidateVehicleOrder(const Vehicle *v)
+{
+ InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+ InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
+}
+
+/**
+ *
+ * Swap two orders
+ *
+ */
+static void SwapOrders(Order *order1, Order *order2)
+{
+ Order temp_order;
+
+ temp_order = *order1;
+ *order1 = *order2;
+ *order2 = temp_order;
+}
+
+/**
+ *
+ * Allocate a new order
+ *
+ * @return Order* if a free space is found, else NULL.
+ *
+ */
+static Order *AllocateOrder()
+{
+ Order *order;
+
+ FOR_ALL_ORDERS(order) {
+ if (order->type == OT_NOTHING) {
+ uint index = order->index;
+ memset(order, 0, sizeof(Order));
+ order->index = index;
+ return order;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ *
+ * Assign data to an order (from an other order)
+ * This function makes sure that the index is maintained correctly
+ *
+ */
+void AssignOrder(Order *order, Order data)
+{
+ order->type = data.type;
+ order->flags = data.flags;
+ order->station = data.station;
+}
+
+/**
+ *
+ * Add an order to the orderlist of a vehicle
+ *
+ * @param veh_sel First 16 bits are the ID of the vehicle. The next 16 are the selected order (if any)
+ * If the lastone is given, order will be inserted above thatone
+ * @param packed_order Packed order to insert
+ *
+ */
+int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 veh_sel, uint32 packed_order)
+{
+ Vehicle *v = GetVehicle(veh_sel & 0xFFFF);
+ int sel = veh_sel >> 16;
+ Order new_order = UnpackOrder(packed_order);
- if (sel > v->num_orders) return_cmd_error(STR_EMPTY);
- if (_ptr_to_next_order == endof(_order_array)) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
- if (v->num_orders >= 40) return_cmd_error(STR_8832_TOO_MANY_ORDERS);
+ if (sel > v->num_orders)
+ return_cmd_error(STR_EMPTY);
- // for ships, make sure that the station is not too far away from the previous destination.
+ if (IsOrderPoolFull())
+ return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
+
+ /* XXX - This limit is only here because the backuppedorders can't
+ handle any more then this.. */
+ if (v->num_orders >= 40)
+ return_cmd_error(STR_8832_TOO_MANY_ORDERS);
+
+ /* For ships, make sure that the station is not too far away from the previous destination. */
if (v->type == VEH_Ship && IS_HUMAN_PLAYER(v->owner) &&
- sel != 0 && v->schedule_ptr[sel - 1].type == OT_GOTO_STATION) {
+ sel != 0 && GetVehicleOrder(v, sel - 1)->type == OT_GOTO_STATION) {
int dist = GetTileDist(
- GetStation(v->schedule_ptr[sel - 1].station)->xy,
+ GetStation(GetVehicleOrder(v, sel - 1)->station)->xy,
GetStation(new_order.station)->xy
);
if (dist >= 130)
@@ -34,101 +146,158 @@ int32 CmdInsertOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
}
if (flags & DC_EXEC) {
- Order *s1;
- Order *s2;
+ Order *new;
Vehicle *u;
- s1 = &v->schedule_ptr[sel];
- s2 = _ptr_to_next_order++;
- do s2[1] = s2[0]; while (--s2 >= s1);
- *s1 = new_order;
+ new = AllocateOrder();
+ AssignOrder(new, new_order);
+
+ /* Create new order and link in list */
+ if (v->orders == NULL) {
+ v->orders = new;
+ } else {
+ /* Try to get the previous item (we are inserting above the
+ selected) */
+ Order *order = GetVehicleOrder(v, sel - 1);
+
+ if (order == NULL && GetVehicleOrder(v, sel) != NULL) {
+ /* There is no previous item, so we are altering v->orders itself
+ But because the orders can be shared, we copy the info over
+ the v->orders, so we don't have to change the pointers of
+ all vehicles */
+ SwapOrders(v->orders, new);
+ /* Now update the next pointers */
+ v->orders->next = new;
+ } else if (order == NULL) {
+ /* 'sel' is a non-existing order, add him to the end */
+ order = GetLastVehicleOrder(v);
+ order->next = new;
+ } else {
+ /* Put the new order in between */
+ new->next = order->next;
+ order->next = new;
+ }
+ }
- s1 = v->schedule_ptr;
+ u = GetFirstVehicleFromSharedList(v);
+ while (u != NULL) {
+ /* Increase amount of orders */
+ u->num_orders++;
- FOR_ALL_VEHICLES(u) {
- if (u->type != 0 && u->schedule_ptr != NULL) {
- if (s1 < u->schedule_ptr) {
- u->schedule_ptr++;
- } else if (s1 == u->schedule_ptr) { // handle shared orders
- u->num_orders++;
+ /* If the orderlist was empty, assign it */
+ if (u->orders == NULL)
+ u->orders = v->orders;
- if ((byte)sel <= u->cur_order_index) {
- sel++;
- if ((byte)sel < u->num_orders)
- u->cur_order_index = sel;
- }
- InvalidateWindow(WC_VEHICLE_VIEW, u->index);
- InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
- }
+ assert(v->orders == u->orders);
+
+ /* If there is added an order before the current one, we need
+ to update the selected order */
+ if (sel <= u->cur_order_index) {
+ uint cur = u->cur_order_index + 1;
+ /* Check if we don't go out of bound */
+ if (cur < u->num_orders)
+ u->cur_order_index = cur;
}
+ /* Update any possible open window of the vehicle */
+ InvalidateVehicleOrder(u);
+
+ u = u->next_shared;
}
+ /* Make sure to rebuild the whole list */
RebuildVehicleLists();
}
return 0;
}
+/**
+ *
+ * Declone an order-list
+ *
+ */
static int32 DecloneOrder(Vehicle *dst, uint32 flags)
{
- if (_ptr_to_next_order == endof(_order_array))
- return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
-
if (flags & DC_EXEC) {
- DeleteVehicleSchedule(dst);
-
- dst->num_orders = 0;
- _ptr_to_next_order->type = OT_NOTHING;
- _ptr_to_next_order->flags = 0;
- dst->schedule_ptr = _ptr_to_next_order++;
-
- InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
+ /* Delete orders from vehicle */
+ DeleteVehicleOrders(dst);
+ InvalidateVehicleOrder(dst);
RebuildVehicleLists();
}
return 0;
}
-/* p1 = vehicle
- * p2 = sel
+/**
+ *
+ * Delete an order from the orderlist of a vehicle
+ *
+ * @param vehicle_id The ID of the vehicle
+ * @param selected The order to delete
+ *
*/
-int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 selected)
{
- Vehicle *v = GetVehicle(p1), *u;
- uint sel = (uint)p2;
+ Vehicle *v = GetVehicle(vehicle_id), *u;
+ uint sel = selected;
+ Order *order;
+ /* XXX -- Why is this here? :s */
_error_message = STR_EMPTY;
+
+ /* If we did not select an order, we maybe want to de-clone the orders */
if (sel >= v->num_orders)
return DecloneOrder(v, flags);
+ order = GetVehicleOrder(v, sel);
+ if (order == NULL)
+ return CMD_ERROR;
+
if (flags & DC_EXEC) {
- Order *s1 = &v->schedule_ptr[sel];
-
- // copy all orders to get rid of the hole
- do s1[0] = s1[1]; while (++s1 != _ptr_to_next_order);
- _ptr_to_next_order--;
-
- s1 = v->schedule_ptr;
-
- FOR_ALL_VEHICLES(u) {
- if (u->type != 0 && u->schedule_ptr != NULL) {
- if (s1 < u->schedule_ptr) {
- u->schedule_ptr--;
- } else if (s1 == u->schedule_ptr) {// handle shared orders
- u->num_orders--;
- if ((byte)sel < u->cur_order_index)
- u->cur_order_index--;
-
- if ((byte)sel == u->cur_order_index &&
- u->current_order.type == OT_LOADING &&
- u->current_order.flags & OF_NON_STOP) {
- u->current_order.flags = 0;
- }
+ if (GetVehicleOrder(v, sel - 1) == NULL) {
+ if (GetVehicleOrder(v, sel + 1) != NULL) {
+ /* First item, but not the last, so we need to alter v->orders
+ Because we can have shared order, we copy the data
+ from the next item over the deleted */
+ order = GetVehicleOrder(v, sel + 1);
+ SwapOrders(v->orders, order);
+ } else {
+ /* Last item, so clean the list */
+ v->orders = NULL;
+ }
+ } else {
+ GetVehicleOrder(v, sel - 1)->next = order->next;
+ }
- InvalidateWindow(WC_VEHICLE_VIEW, u->index);
- InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
- }
+ /* Give the item free */
+ order->type = OT_NOTHING;
+
+ u = GetFirstVehicleFromSharedList(v);
+ while (u != NULL) {
+ u->num_orders--;
+
+ if (sel < u->cur_order_index)
+ u->cur_order_index--;
+
+ /* If we removed the last order, make sure the shared vehicles
+ also set their orders to NULL */
+ if (v->orders == NULL)
+ u->orders = NULL;
+
+ assert(v->orders == u->orders);
+
+ /* NON-stop flag is misused to see if a train is in a station that is
+ on his order list or not */
+ if (sel == u->cur_order_index &&
+ u->current_order.type == OT_LOADING &&
+ HASBIT(u->current_order.flags, OFB_NON_STOP)) {
+ u->current_order.flags = 0;
}
+
+ /* Update any possible open window of the vehicle */
+ InvalidateVehicleOrder(u);
+
+ u = u->next_shared;
}
RebuildVehicleLists();
@@ -137,321 +306,651 @@ int32 CmdDeleteOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return 0;
}
-/* p1 = vehicle */
-int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+/**
+ *
+ * Goto next order of order-list
+ *
+ * @param vehicle_id The ID of the vehicle
+ *
+ */
+int32 CmdSkipOrder(int x, int y, uint32 flags, uint32 vehicle_id, uint32 not_used)
{
- Vehicle *v = GetVehicle(p1);
+ Vehicle *v = GetVehicle(vehicle_id);
if (flags & DC_EXEC) {
+ /* Goto next order */
{
byte b = v->cur_order_index + 1;
- if (b >= v->num_orders) b = 0;
+ if (b >= v->num_orders)
+ b = 0;
+
v->cur_order_index = b;
if (v->type == VEH_Train)
v->u.rail.days_since_order_progr = 0;
}
+ /* NON-stop flag is misused to see if a train is in a station that is
+ on his order list or not */
if (v->current_order.type == OT_LOADING &&
- v->current_order.flags & OF_NON_STOP) {
+ HASBIT(v->current_order.flags, OFB_NON_STOP)) {
v->current_order.flags = 0;
}
- InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
+ InvalidateVehicleOrder(v);
}
- //we have an aircraft, they have a mini-schedule, so update them all
+ /* We have an aircraft/ship, they have a mini-schedule, so update them all */
if (v->type == VEH_Aircraft) InvalidateAircraftWindows(v);
-
- //same goes for ships
if (v->type == VEH_Ship) InvalidateShipWindows(v);
return 0;
}
-/* p1 = vehicle
- * p2&0xFF = sel
- * p2>>8 = mode
+
+/**
+ *
+ * Add an order to the orderlist of a vehicle
+ *
+ * @param veh_sel First 16 bits are the ID of the vehicle. The next 16 are the selected order (if any)
+ * If the lastone is given, order will be inserted above thatone
+ * @param mode Mode to change the order to
+ *
*/
-int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+int32 CmdModifyOrder(int x, int y, uint32 flags, uint32 veh_sel, uint32 mode)
{
- Vehicle *v = GetVehicle(p1);
- byte sel = (byte)p2;
- Order *sched;
+ Vehicle *v = GetVehicle(veh_sel & 0xFFFF);
+ byte sel = veh_sel >> 16;
+ Order *order;
+ /* Is it a valid order? */
if (sel >= v->num_orders)
return CMD_ERROR;
- sched = &v->schedule_ptr[sel];
- if (sched->type != OT_GOTO_STATION &&
- (sched->type != OT_GOTO_DEPOT || (p2 >> 8) == 1) &&
- (sched->type != OT_GOTO_WAYPOINT || (p2 >> 8) != 2))
+ order = GetVehicleOrder(v, sel);
+ if (order->type != OT_GOTO_STATION &&
+ (order->type != OT_GOTO_DEPOT || mode == OFB_UNLOAD) &&
+ (order->type != OT_GOTO_WAYPOINT || mode != OFB_NON_STOP))
return CMD_ERROR;
if (flags & DC_EXEC) {
- switch (p2 >> 8) {
- case 0: // full load
- sched->flags ^= OF_FULL_LOAD;
- if (sched->type != OT_GOTO_DEPOT) sched->flags &= ~OF_UNLOAD;
+ switch (mode) {
+ case OFB_FULL_LOAD:
+ TOGGLEBIT(order->flags, OFB_FULL_LOAD);
+ if (order->type != OT_GOTO_DEPOT)
+ CLRBIT(order->flags, OFB_UNLOAD);
break;
- case 1: // unload
- sched->flags ^= OF_UNLOAD;
- sched->flags &= ~OF_FULL_LOAD;
+ case OFB_UNLOAD:
+ TOGGLEBIT(order->flags, OFB_UNLOAD);
+ CLRBIT(order->flags, OFB_FULL_LOAD);
break;
- case 2: // non stop
- sched->flags ^= OF_NON_STOP;
+ case OFB_NON_STOP:
+ TOGGLEBIT(order->flags, OFB_NON_STOP);
break;
}
- sched = v->schedule_ptr;
- FOR_ALL_VEHICLES(v) {
- if (v->schedule_ptr == sched)
- InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
+ /* Update the windows, also for vehicles that share the same order list */
+ {
+ Vehicle *u = GetFirstVehicleFromSharedList(v);
+ while (u != NULL) {
+ InvalidateVehicleOrder(u);
+ u = u->next_shared;
+ }
}
-
}
return 0;
}
-// Clone an order
-// p1 & 0xFFFF is destination vehicle
-// p1 >> 16 is source vehicle
+/**
+ *
+ * Clone/share/copy an order-list of an other vehicle
+ *
+ * @param veh1_veh2 First 16 bits are of destination vehicle, last 16 of source vehicle
+ * @param mode Mode of cloning (CO_SHARE, CO_COPY, CO_UNSHARE)
+ *
+ */
+int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 veh1_veh2, uint32 mode)
+{
+ Vehicle *dst = GetVehicle(veh1_veh2 & 0xFFFF);
-// p2 is
-// 0 - clone
-// 1 - copy
-// 2 - unclone
+ if (dst->type == 0 || dst->owner != _current_player)
+ return CMD_ERROR;
+ switch(mode) {
+ case CO_SHARE: {
+ Vehicle *src = GetVehicle(veh1_veh2 >> 16);
-int32 CmdCloneOrder(int x, int y, uint32 flags, uint32 p1, uint32 p2)
-{
- Vehicle *dst = GetVehicle(p1 & 0xFFFF);
+ /* Sanity checks */
+ if (src->type == 0 || src->owner != _current_player || dst->type != src->type || dst == src)
+ return CMD_ERROR;
- if (!(dst->type && dst->owner == _current_player))
- return CMD_ERROR;
+ /* Trucks can't share orders with busses (and visa versa) */
+ if (src->type == VEH_Road) {
+ if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
+ return CMD_ERROR;
+ }
- switch(p2) {
+ /* Is the vehicle already in the shared list? */
+ {
+ Vehicle *u = GetFirstVehicleFromSharedList(src);
+ while (u != NULL) {
+ if (u == dst)
+ return CMD_ERROR;
+ u = u->next_shared;
+ }
+ }
- // share vehicle orders?
- case 0: {
- Vehicle *src = GetVehicle(p1 >> 16);
+ if (flags & DC_EXEC) {
+ /* If the destination vehicle had a OrderList, destroy it */
+ DeleteVehicleOrders(dst);
- // sanity checks
- if (!(src->owner == _current_player && dst->type == src->type && dst != src))
- return CMD_ERROR;
+ dst->orders = src->orders;
+ dst->num_orders = src->num_orders;
- // let's see what happens with road vehicles
- if (src->type == VEH_Road) {
- if (src->cargo_type != dst->cargo_type && (src->cargo_type == CT_PASSENGERS || dst->cargo_type == CT_PASSENGERS))
- return CMD_ERROR;
- }
+ /* Link this vehicle in the shared-list */
+ dst->next_shared = src->next_shared;
+ dst->prev_shared = src;
+ if (src->next_shared != NULL)
+ src->next_shared->prev_shared = dst;
+ src->next_shared = dst;
+
+ InvalidateVehicleOrder(dst);
+ InvalidateVehicleOrder(src);
- if (flags & DC_EXEC) {
- DeleteVehicleSchedule(dst);
- dst->schedule_ptr = src->schedule_ptr;
- dst->num_orders = src->num_orders;
+ RebuildVehicleLists();
+ }
+ } break;
- InvalidateWindow(WC_VEHICLE_ORDERS, src->index);
- InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
+ case CO_COPY: {
+ Vehicle *src = GetVehicle(veh1_veh2 >> 16);
+ int delta;
- RebuildVehicleLists();
- }
- break;
- }
+ /* Sanity checks */
+ if (src->type == 0 || src->owner != _current_player || dst->type != src->type || dst == src)
+ return CMD_ERROR;
- // copy vehicle orders?
- case 1: {
- Vehicle *src = GetVehicle(p1 >> 16);
- int delta;
-
- // sanity checks
- if (!(src->owner == _current_player && dst->type == src->type && dst != src))
- return CMD_ERROR;
-
- // let's see what happens with road vehicles
- if (src->type == VEH_Road) {
- const Order *i;
- TileIndex required_dst;
-
- for (i = src->schedule_ptr; i->type != OT_NOTHING; ++i) {
- if (i->type == OT_GOTO_STATION) {
- const Station *st = GetStation(i->station);
- required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
- if ( !required_dst )
- return CMD_ERROR;
+ /* Trucks can't copy all the orders from busses (and visa versa) */
+ if (src->type == VEH_Road) {
+ const Order *order;
+ TileIndex required_dst;
+
+ FOR_VEHICLE_ORDERS(src, order) {
+ if (order->type == OT_GOTO_STATION) {
+ const Station *st = GetStation(order->station);
+ required_dst = (dst->cargo_type == CT_PASSENGERS) ? st->bus_tile : st->lorry_tile;
+ /* This station has not the correct road-bay, so we can't copy! */
+ if (!required_dst)
+ return CMD_ERROR;
+ }
}
}
- }
- // make sure there's orders available
- delta = IsScheduleShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
- if (delta > endof(_order_array) - _ptr_to_next_order)
- return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
+ /* make sure there are orders available */
+ delta = IsOrderListShared(dst) ? src->num_orders + 1 : src->num_orders - dst->num_orders;
+ if (!HasOrderPoolFree(delta))
+ return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
- if (flags & DC_EXEC) {
- DeleteVehicleSchedule(dst);
- dst->schedule_ptr = _ptr_to_next_order;
- dst->num_orders = src->num_orders;
- _ptr_to_next_order += src->num_orders + 1;
- memcpy(dst->schedule_ptr, src->schedule_ptr, (src->num_orders + 1) * sizeof(Order));
+ if (flags & DC_EXEC) {
+ const Order *order;
+ Order **order_dst;
- InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
+ /* If the destination vehicle had a OrderList, destroy it */
+ DeleteVehicleOrders(dst);
- RebuildVehicleLists();
- }
- break;
- }
+ order_dst = &dst->orders;
+ FOR_VEHICLE_ORDERS(src, order) {
+ *order_dst = AllocateOrder();
+ AssignOrder(*order_dst, *order);
+ order_dst = &(*order_dst)->next;
+ }
+
+ dst->num_orders = src->num_orders;
+
+ InvalidateVehicleOrder(dst);
- // declone vehicle orders?
- case 2: return DecloneOrder(dst, flags);
+ RebuildVehicleLists();
+ }
+ } break;
+
+ case CO_UNSHARE:
+ return DecloneOrder(dst, flags);
}
return 0;
}
+/**
+ *
+ * Backup a vehicle order-list, so you can replace a vehicle
+ * without loosing the order-list
+ *
+ */
void BackupVehicleOrders(Vehicle *v, BackuppedOrders *bak)
{
- Vehicle *u = IsScheduleShared(v);
+ bool shared = IsOrderListShared(v);
- bak->orderindex = v->cur_order_index;
+ /* Save general info */
+ bak->orderindex = v->cur_order_index;
bak->service_interval = v->service_interval;
+ /* Safe custom string, if any */
if ((v->string_id & 0xF800) != 0x7800) {
bak->name[0] = 0;
} else {
GetName(v->string_id & 0x7FF, bak->name);
}
- // stored shared orders in this special way?
- if (u != NULL) {
+ /* If we have shared orders, store it on a special way */
+ if (shared) {
+ Vehicle *u;
+ if (v->next_shared)
+ u = v->next_shared;
+ else
+ u = v->prev_shared;
+
bak->clone = u->index;
} else {
- Order *sched = v->schedule_ptr;
- Order *os = bak->order;
+ /* Else copy the orders */
+ Order *order, *dest;
+
+ dest = bak->order;
+ /* We do not have shared orders */
bak->clone = INVALID_VEHICLE;
- do {
- *os++ = *sched++;
- } while (sched->type != OT_NOTHING);
- /* Make sure the last item is OT_NOTHING */
- os->type = OT_NOTHING;
+ /* Copy the orders */
+ FOR_VEHICLE_ORDERS(v, order) {
+ *dest = *order;
+ dest++;
+ }
+ /* End the list with an OT_NOTHING */
+ dest->type = OT_NOTHING;
}
}
+/**
+ *
+ * Restore vehicle orders that are backupped via BackupVehicleOrders
+ *
+ */
void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *bak)
{
int i;
- if (bak->name[0]) {
+ /* If we have a custom name, process that */
+ if (bak->name[0] != 0) {
strcpy((char*)_decode_parameters, bak->name);
DoCommandP(0, v->index, 0, NULL, CMD_NAME_VEHICLE);
}
- DoCommandP(0, v->index, bak->orderindex|(bak->service_interval<<16) , NULL, CMD_RESTORE_ORDER_INDEX);
+ /* Restore vehicle number and service interval */
+ DoCommandP(0, v->index, bak->orderindex | (bak->service_interval << 16) , NULL, CMD_RESTORE_ORDER_INDEX);
+ /* If we had shared orders, recover that */
if (bak->clone != INVALID_VEHICLE) {
- DoCommandP(0, v->index | bak->clone << 16, 0, NULL, CMD_CLONE_ORDER);
+ DoCommandP(0, v->index | (bak->clone << 16), 0, NULL, CMD_CLONE_ORDER);
return;
}
- // CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
- // order number is one more than the current amount of orders, and because
- // in network the commands are queued before send, the second insert always
- // fails in test mode. By bypassing the test-mode, that no longer is a problem.
- for (i = 0; bak->order[i].type != OT_NOTHING; ++i)
+ /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the
+ order number is one more than the current amount of orders, and because
+ in network the commands are queued before send, the second insert always
+ fails in test mode. By bypassing the test-mode, that no longer is a problem. */
+ for (i = 0; bak->order[i].type != OT_NOTHING; i++)
if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK))
break;
}
-/* p1 = vehicle
- * upper 16 bits p2 = service_interval
- * lower 16 bits p2 = cur_order_index
+/**
+ *
+ * Restore the current-order-index of a vehicle and sets service-interval
+ *
+ * @param vehicle_id The ID of the vehicle
+ * @param data First 16 bits are the current-order-index
+ * The last 16 bits are the service-interval
+ *
*/
-int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+int32 CmdRestoreOrderIndex(int x, int y, uint32 flags, uint32 vehicle_id, uint32 data)
{
- // nonsense to update the windows, since, train rebought will have its window deleted
if (flags & DC_EXEC) {
- Vehicle *v = GetVehicle(p1);
- v->service_interval = (uint16)(p2>>16);
- v->cur_order_index = (byte)(p2&0xFFFF);
+ Vehicle *v = GetVehicle(vehicle_id);
+ v->service_interval = data >> 16;
+ v->cur_order_index = data & 0xFFFF;
}
+
return 0;
}
-int CheckOrders(Vehicle *v)
+/**
+ *
+ * Check the orders of a vehicle, to see if there are invalid orders and stuff
+ *
+ */
+bool CheckOrders(const Vehicle *v)
{
- if (!_patches.order_review_system) //User doesn't want things to be checked
- return 0;
+ /* Does the user wants us to check things? */
+ if (_patches.order_review_system == 0)
+ return false;
+ /* Do nothing for crashed vehicles */
if(v->vehstatus & VS_CRASHED)
- return 0;
+ return false;
+ /* Do nothing for stopped vehicles if setting is '1' */
if ( (_patches.order_review_system == 1) && (v->vehstatus & VS_STOPPED) )
- return 0;
+ return false;
- /* only check every 20 days, so that we don't flood the message log */
+ /* Only check every 20 days, so that we don't flood the message log */
if ( ( ( v->day_counter % 20) == 0 ) && (v->owner == _local_player) ) {
- Order order;
- Order old_order;
- int i, n_st, problem_type = -1;
- Station *st;
- int message=0;
- TileIndex required_tile=-1;
-
- /* check the order list */
- order = v->schedule_ptr[0];
+ int n_st, problem_type = -1;
+ const Order *order;
+ const Station *st;
+ int message = 0;
+
+ /* Check the order list */
n_st = 0;
- old_order.type = OT_NOTHING;
- old_order.flags = 0;
- for (i = 0; order.type != OT_NOTHING; i++) {
- order = v->schedule_ptr[i];
- if (order.type == old_order.type &&
- order.flags == old_order.flags &&
- order.station == old_order.station) {
- problem_type = 2;
- break;
- }
- if (order.type == OT_DUMMY) {
+ FOR_VEHICLE_ORDERS(v, order) {
+ /* Dummy order? */
+ if (order->type == OT_DUMMY) {
problem_type = 1;
break;
}
- if (order.type == OT_GOTO_STATION /*&& (order != old_order) */) {
- //I uncommented this in order not to get two error messages
- //when two identical entries are in the list
+ /* Does station have a load-bay for this vehicle? */
+ if (order->type == OT_GOTO_STATION) {
+ TileIndex required_tile;
+
n_st++;
- st = GetStation(order.station);
- required_tile = GetStationTileForVehicle(v,st);
- if (!required_tile) problem_type = 3;
+ st = GetStation(order->station);
+ required_tile = GetStationTileForVehicle(v, st);
+ if (!required_tile)
+ problem_type = 3;
}
- old_order = order; //store the old order
}
- //Now, check the last and the first order
- //as the last order is the end of order marker, jump back 2
- if (i > 2 &&
- v->schedule_ptr[0].type == v->schedule_ptr[i - 2].type &&
- v->schedule_ptr[0].flags == v->schedule_ptr[i - 2].flags &&
- v->schedule_ptr[0].station == v->schedule_ptr[i - 2].station)
+ /* Check if the last and the first order are the same */
+ if (v->num_orders > 1 &&
+ v->orders->type == GetLastVehicleOrder(v)->type &&
+ v->orders->flags == GetLastVehicleOrder(v)->flags &&
+ v->orders->station == GetLastVehicleOrder(v)->station)
problem_type = 2;
- if ( (n_st < 2) && (problem_type == -1) ) problem_type = 0;
+ /* Do we only have 1 station in our order list? */
+ if ((n_st < 2) && (problem_type == -1))
+ problem_type = 0;
- SetDParam(0, v->unitnumber);
+ /* We don't have a problem */
+ if (problem_type < 0)
+ return false;
message = (STR_TRAIN_HAS_TOO_FEW_ORDERS) + (((v->type) - VEH_Train) << 2) + problem_type;
- if (problem_type < 0) return 0;
-
+ SetDParam(0, v->unitnumber);
AddNewsItem(
message,
- NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
+ NEWS_FLAGS(NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, 0),
v->index,
0);
}
- // End of order check
- return 1;
+ return true;
+}
+
+/**
+ *
+ * Delete a destination (like station, waypoint, ..) from the orders of vehicles
+ *
+ * @param dest type and station has to be set. This order will be removed from all orders of vehicles
+ *
+ */
+void DeleteDestinationFromVehicleOrder(Order dest)
+{
+ Vehicle *v;
+ Order *order;
+ bool need_invalidate;
+
+ /* Go through all vehicles */
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == 0 || v->orders == NULL)
+ continue;
+
+ /* Forget about this station if this station is removed */
+ if (v->last_station_visited == dest.station && dest.type == OT_GOTO_STATION)
+ v->last_station_visited = 0xFFFF;
+
+ /* Check the current order */
+ if (v->current_order.type == dest.type &&
+ v->current_order.station == dest.station) {
+ /* Mark the order as DUMMY */
+ v->current_order.type = OT_DUMMY;
+ v->current_order.flags = 0;
+ InvalidateWindow(WC_VEHICLE_VIEW, v->index);
+ }
+
+ /* Clear the order from the order-list */
+ need_invalidate = false;
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->type == dest.type && order->station == dest.station) {
+ /* Mark the order as DUMMY */
+ order->type = OT_DUMMY;
+ order->flags = 0;
+
+ need_invalidate = true;
+ }
+ }
+
+ /* Only invalidate once, and if needed */
+ if (need_invalidate)
+ InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
+ }
+}
+
+/**
+ *
+ * Checks if a vehicle has a GOTO_DEPOT in his order list
+ *
+ * @return True if this is true (lol ;))
+ *
+ */
+bool VehicleHasDepotOrders(const Vehicle *v)
+{
+ const Order *order;
+
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->type == OT_GOTO_DEPOT)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ *
+ * Delete all orders from a vehicle
+ *
+ */
+void DeleteVehicleOrders(Vehicle *v)
+{
+ Order *order, *cur;
+
+ /* If we have a shared order-list, don't delete the list, but just
+ remove our pointer */
+ if (IsOrderListShared(v)) {
+ const Vehicle *u = v;
+
+ v->orders = NULL;
+ v->num_orders = 0;
+
+ /* Unlink ourself */
+ if (v->prev_shared != NULL) {
+ v->prev_shared->next_shared = v->next_shared;
+ u = v->prev_shared;
+ }
+ if (v->next_shared != NULL) {
+ v->next_shared->prev_shared = v->prev_shared;
+ u = v->next_shared;
+ }
+ v->prev_shared = NULL;
+ v->next_shared = NULL;
+
+ /* We only need to update this-one, because if there is a third
+ vehicle which shares the same order-list, nothing will change. If
+ this is the last vehicle, the last line of the order-window
+ will change from Shared order list, to Order list, so it needs
+ an update */
+ InvalidateVehicleOrder(u);
+ return;
+ }
+
+ /* Remove the orders */
+ cur = v->orders;
+ v->orders = NULL;
+ v->num_orders = 0;
+
+ order = NULL;
+ while (cur != NULL) {
+ if (order != NULL) {
+ order->type = OT_NOTHING;
+ order->next = NULL;
+ }
+
+ order = cur;
+ cur = cur->next;
+ }
+
+ if (order != NULL) {
+ order->type = OT_NOTHING;
+ order->next = NULL;
+ }
+}
+
+/**
+ *
+ * Check if we share our orders with an other vehicle
+ *
+ * @return Returns the vehicle who has the same order
+ *
+ */
+bool IsOrderListShared(const Vehicle *v)
+{
+ if (v->next_shared != NULL)
+ return true;
+
+ if (v->prev_shared != NULL)
+ return true;
+
+ return false;
+}
+
+/**
+ *
+ * Check if a vehicle has any valid orders
+ *
+ * @return false if there are no valid orders
+ *
+ */
+bool CheckForValidOrders(Vehicle *v)
+{
+ const Order *order;
+
+ FOR_VEHICLE_ORDERS(v, order)
+ if (order->type != OT_DUMMY)
+ return true;
+
+ return false;
+}
+
+void InitializeOrders(void)
+{
+ Order *order;
+ int i;
+
+ memset(&_orders, 0, sizeof(_orders[0]) * _orders_size);
+
+ i = 0;
+ FOR_ALL_ORDERS(order)
+ order->index = i++;
+
+ _backup_orders_tile = 0;
+}
+
+static const byte _order_desc[] = {
+ SLE_VAR(Order,type, SLE_UINT8),
+ SLE_VAR(Order,flags, SLE_UINT8),
+ SLE_VAR(Order,station, SLE_UINT16),
+ SLE_REF(Order,next, REF_ORDER),
+
+ // reserve extra space in savegame here. (currently 10 bytes)
+ SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 10, 5, 255),
+ SLE_END()
+};
+
+static void Save_ORDR()
+{
+ Order *order;
+
+ FOR_ALL_ORDERS(order) {
+ if (order->type != OT_NOTHING) {
+ SlSetArrayIndex(order->index);
+ SlObject(order, _order_desc);
+ }
+ }
+}
+
+static void Load_ORDR()
+{
+ if (_sl.full_version <= 0x501) {
+ /* Version older than 0x502 did not have a ->next pointer. Convert them
+ (in the old days, the orderlist was 5000 items big) */
+ uint len = SlGetFieldLength();
+ uint i;
+
+ if (_sl.version < 5) {
+ /* Pre-version 5 had an other layout for orders
+ (uint16 instead of uint32) */
+ uint16 orders[5000];
+
+ len /= sizeof(uint16);
+ assert (len <= _orders_size);
+
+ SlArray(orders, len, SLE_UINT16);
+
+ for (i = 0; i < len; ++i) {
+ AssignOrder(GetOrder(i), UnpackVersion4Order(orders[i]));
+ }
+ } else if (_sl.full_version <= 0x501) {
+ uint32 orders[5000];
+
+ len /= sizeof(uint32);
+ assert (len <= _orders_size);
+
+ SlArray(orders, len, SLE_UINT32);
+
+ for (i = 0; i < len; ++i) {
+ AssignOrder(GetOrder(i), UnpackOrder(orders[i]));
+ }
+ }
+
+ /* Update all the next pointer */
+ for (i = 1; i < len; ++i) {
+ /* The orders were built like this:
+ Vehicle one had order[0], and as long as order++.type was not
+ OT_NOTHING, it was part of the order-list of that vehicle */
+ if (GetOrder(i)->type != OT_NOTHING)
+ GetOrder(i - 1)->next = GetOrder(i);
+ }
+ } else {
+ int index;
+
+ while ((index = SlIterateArray()) != -1) {
+ Order *order = GetOrder(index);
+
+ SlObject(order, _order_desc);
+ }
+ }
}
+
+const ChunkHandler _order_chunk_handlers[] = {
+ { 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
+};
diff --git a/order_gui.c b/order_gui.c
index 9023f3feb..6699e62d9 100644
--- a/order_gui.c
+++ b/order_gui.c
@@ -14,32 +14,23 @@
static int OrderGetSel(Window *w)
{
Vehicle *v = GetVehicle(w->window_number);
- const Order *sched = v->schedule_ptr;
int num = WP(w,order_d).sel;
- int count = 0;
- if (num == 0)
- return 0;
+ if (num < 0 || num > v->num_orders)
+ return v->num_orders;
- while (sched->type != OT_NOTHING) {
- sched++;
- count++;
- if (--num == 0)
- break;
- }
-
- return count;
+ return num;
}
static void DrawOrdersWindow(Window *w)
{
- Vehicle *v;
- int num, sel;
- const Order *sched;
- Order ord;
- int y, i;
+ const Vehicle *v;
+ const Order *order;
StringID str;
- bool shared_schedule;
+ int sel;
+ int y, i;
+ bool shared_orders;
+ byte color;
v = GetVehicle(w->window_number);
@@ -57,40 +48,41 @@ static void DrawOrdersWindow(Window *w)
w->disabled_state |= 1 << 6;
}
- shared_schedule = IsScheduleShared(v) != NULL;
+ shared_orders = IsOrderListShared(v);
- sched = v->schedule_ptr;
- num=0;
- while (sched->type != OT_NOTHING) {
- sched++;
- num++;
- }
-
- if ((uint)num + shared_schedule <= (uint)WP(w,order_d).sel)
+ if ((uint)v->num_orders + shared_orders <= (uint)WP(w,order_d).sel)
SETBIT(w->disabled_state, 5); /* delete */
- if (num == 0)
+ if (v->num_orders == 0)
SETBIT(w->disabled_state, 4); /* skip */
- SetVScrollCount(w, num+1);
+ SetVScrollCount(w, v->num_orders + 1);
sel = OrderGetSel(w);
+ SetDParam(2, STR_8827_FULL_LOAD);
- SetDParam(2,STR_8827_FULL_LOAD);
- switch (v->schedule_ptr[sel].type) {
- case OT_GOTO_STATION:
- break;
- case OT_GOTO_DEPOT:
- SETBIT(w->disabled_state, 9); /* unload */
- SetDParam(2,STR_SERVICE);
- break;
+ order = GetVehicleOrder(v, sel);
- case OT_GOTO_WAYPOINT:
- SETBIT(w->disabled_state, 8); /* full load */
- SETBIT(w->disabled_state, 9); /* unload */
- break;
+ if (order != NULL) {
+ switch (order->type) {
+ case OT_GOTO_STATION:
+ break;
+ case OT_GOTO_DEPOT:
+ SETBIT(w->disabled_state, 9); /* unload */
+ SetDParam(2,STR_SERVICE);
+ break;
+
+ case OT_GOTO_WAYPOINT:
+ SETBIT(w->disabled_state, 8); /* full load */
+ SETBIT(w->disabled_state, 9); /* unload */
+ break;
- default:
+ default:
+ SETBIT(w->disabled_state, 6); /* nonstop */
+ SETBIT(w->disabled_state, 8); /* full load */
+ SETBIT(w->disabled_state, 9); /* unload */
+ }
+ } else {
SETBIT(w->disabled_state, 6); /* nonstop */
SETBIT(w->disabled_state, 8); /* full load */
SETBIT(w->disabled_state, 9); /* unload */
@@ -102,61 +94,62 @@ static void DrawOrdersWindow(Window *w)
y = 15;
- i = 0;
- for(;;) {
- str = ((byte)v->cur_order_index == i) ? STR_8805 : STR_8804;
+ i = w->vscroll.pos;
+ order = GetVehicleOrder(v, i);
+ while (order != NULL) {
+ str = (v->cur_order_index == i) ? STR_8805 : STR_8804;
+
+ if (i - w->vscroll.pos < 6) {
+ SetDParam(1, 6);
+
+ if (order->type == OT_GOTO_STATION) {
+ SetDParam(1, STR_8806_GO_TO + (order->flags >> 1));
+ SetDParam(2, order->station);
+ } else if (order->type == OT_GOTO_DEPOT) {
+ StringID s = STR_NULL;
+ if (v->type == VEH_Aircraft) {
+ s = STR_GO_TO_AIRPORT_HANGAR;
+ SetDParam(2, order->station);
+ } else {
+ SetDParam(2, _depots[order->station].town_index);
+ switch (v->type) {
+ case VEH_Train: s = STR_880E_GO_TO_TRAIN_DEPOT; break;
+ case VEH_Road: s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
+ case VEH_Ship: s = STR_GO_TO_SHIP_DEPOT; break;
+ }
+ }
+ if (v->type == VEH_Train && order->flags & OF_NON_STOP)
+ s += 2;
- ord = v->schedule_ptr[i];
+ if (order->flags & OF_FULL_LOAD)
+ s++; /* XXX service */
- if ( (uint)(i - w->vscroll.pos) < 6) {
+ SetDParam(1, s);
+ } else if (order->type == OT_GOTO_WAYPOINT) {
+ SetDParam(1, (order->flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
+ SetDParam(2, order->station);
+ }
- if (ord.type == OT_NOTHING) {
- str = shared_schedule ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
+ color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
+ SetDParam(0, i + 1);
+ if (order->type != OT_DUMMY) {
+ DrawString(2, y, str, color);
} else {
- SetDParam(1, 6);
-
- if (ord.type == OT_GOTO_STATION) {
- SetDParam(1, STR_8806_GO_TO + (ord.flags >> 1));
- SetDParam(2, ord.station);
- } else if (ord.type == OT_GOTO_DEPOT) {
- StringID s = STR_NULL;
- if (v->type == VEH_Aircraft) {
- s = STR_GO_TO_AIRPORT_HANGAR;
- SetDParam(2, ord.station);
- } else {
- SetDParam(2, _depots[ord.station].town_index);
- switch (v->type) {
- case VEH_Train: s = STR_880E_GO_TO_TRAIN_DEPOT; break;
- case VEH_Road: s = STR_9038_GO_TO_ROADVEH_DEPOT; break;
- case VEH_Ship: s = STR_GO_TO_SHIP_DEPOT; break;
- }
- }
- if (v->type == VEH_Train && ord.flags & OF_NON_STOP) s += 2;
- if (ord.flags & OF_FULL_LOAD) ++s; /* XXX service */
- SetDParam(1, s);
- } else if (ord.type == OT_GOTO_WAYPOINT) {
- SetDParam(2, ord.station);
- SetDParam(1, (ord.flags & OF_NON_STOP) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT);
- }
- }
- {
- byte color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
- SetDParam(0, i+1);
- if (ord.type != OT_DUMMY) {
- DrawString(2, y, str, color);
- } else {
- SetDParam(1, STR_INVALID_ORDER);
- SetDParam(2, ord.station);
- DrawString(2, y, str, color);
- }
+ SetDParam(1, STR_INVALID_ORDER);
+ SetDParam(2, order->station);
+ DrawString(2, y, str, color);
}
y += 10;
}
i++;
+ order = order->next;
+ }
- if (ord.type == OT_NOTHING)
- break;
+ if (i - w->vscroll.pos < 6) {
+ str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
+ color = (i == WP(w,order_d).sel) ? 0xC : 0x10;
+ DrawString(2, y, str, color);
}
}
@@ -317,12 +310,6 @@ static void OrdersPlaceObj(Vehicle *v, uint tile, Window *w)
}
}
-enum OrderFlags {
- FULL_LOAD = 0,
- UNLOAD = 1,
- NON_STOP = 2
-};
-
static void OrderClick_Goto(Window *w, Vehicle *v)
{
InvalidateWidget(w, 7);
@@ -337,27 +324,27 @@ static void OrderClick_Goto(Window *w, Vehicle *v)
static void OrderClick_FullLoad(Window *w, Vehicle *v)
{
- DoCommandP(v->tile, v->index, OrderGetSel(w) | (FULL_LOAD << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_FULL_LOAD, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
static void OrderClick_Unload(Window *w, Vehicle *v)
{
- DoCommandP(v->tile, v->index, OrderGetSel(w) | (UNLOAD << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_UNLOAD, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
-static void OrderClick_Skip(Window *w, Vehicle *v)
+static void OrderClick_Nonstop(Window *w, Vehicle *v)
{
- DoCommandP(v->tile,v->index, 0, NULL, CMD_SKIP_ORDER);
+ DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), OFB_NON_STOP, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
-static void OrderClick_Delete(Window *w, Vehicle *v)
+static void OrderClick_Skip(Window *w, Vehicle *v)
{
- DoCommandP(v->tile,v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
+ DoCommandP(v->tile, v->index, 0, NULL, CMD_SKIP_ORDER);
}
-static void OrderClick_Nonstop(Window *w, Vehicle *v)
+static void OrderClick_Delete(Window *w, Vehicle *v)
{
- DoCommandP(v->tile, v->index, OrderGetSel(w) | (NON_STOP << 8), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
}
typedef void OnButtonClick(Window *w, Vehicle *v);
@@ -399,18 +386,18 @@ static void OrdersWndProc(Window *w, WindowEvent *e)
sel += w->vscroll.pos;
- if (_ctrl_pressed && sel < v->num_orders) { // watch out for schedule_ptr overflow
- Order ord = v->schedule_ptr[sel];
+ if (_ctrl_pressed && sel < v->num_orders) {
+ Order *ord = GetVehicleOrder(v, sel);
int xy = 0;
- switch (ord.type) {
+ switch (ord->type) {
case OT_GOTO_STATION: /* station order */
- xy = GetStation(ord.station)->xy ;
+ xy = GetStation(ord->station)->xy ;
break;
case OT_GOTO_DEPOT: /* goto depot order */
- xy = _depots[ord.station].xy;
+ xy = _depots[ord->station].xy;
break;
case OT_GOTO_WAYPOINT: /* goto waypoint order */
- xy = _waypoints[ord.station].xy;
+ xy = _waypoints[ord->station].xy;
}
if (xy)
@@ -447,7 +434,6 @@ static void OrdersWndProc(Window *w, WindowEvent *e)
case 9: /* unload button */
OrderClick_Unload(w, v);
break;
-
}
} break;
@@ -473,7 +459,7 @@ static void OrdersWndProc(Window *w, WindowEvent *e)
case WE_RCLICK: {
Vehicle *v = GetVehicle(w->window_number);
if (e->click.widget != 8) break;
- if (v->schedule_ptr[OrderGetSel(w)].type == OT_GOTO_DEPOT)
+ if (GetVehicleOrder(v, OrderGetSel(w))->type == OT_GOTO_DEPOT)
GuiShowTooltips(STR_SERVICE_HINT);
else
GuiShowTooltips(STR_8857_MAKE_THE_HIGHLIGHTED_ORDER);
diff --git a/rail_cmd.c b/rail_cmd.c
index d75404e69..5e42ced3a 100644
--- a/rail_cmd.c
+++ b/rail_cmd.c
@@ -768,10 +768,11 @@ static void DoDeleteWaypoint(Waypoint *cp)
{
Order order;
cp->xy = 0;
+
order.type = OT_GOTO_WAYPOINT;
- order.flags = 0;
order.station = cp - _waypoints;
- DeleteCommandFromVehicleSchedule(order);
+ DeleteDestinationFromVehicleOrder(order);
+
if (~cp->town_or_string & 0xC000) DeleteName(cp->town_or_string);
RedrawWaypointSign(cp);
}
diff --git a/roadveh_cmd.c b/roadveh_cmd.c
index 0e8d808c2..957561bdd 100644
--- a/roadveh_cmd.c
+++ b/roadveh_cmd.c
@@ -122,7 +122,7 @@ int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return cost;
v = AllocateVehicle();
- if (v == NULL || _ptr_to_next_order >= endof(_order_array))
+ if (v == NULL || IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
/* find the first free roadveh id */
@@ -172,9 +172,6 @@ int32 CmdBuildRoadVeh(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_new_roadveh_id = v->index;
v->string_id = STR_SV_ROADVEH_NAME;
- _ptr_to_next_order->type = OT_NOTHING;
- _ptr_to_next_order->flags = 0;
- v->schedule_ptr = _ptr_to_next_order++;
v->service_interval = _patches.servint_roadveh;
@@ -554,11 +551,11 @@ static void HandleBrokenRoadVeh(Vehicle *v)
static void ProcessRoadVehOrder(Vehicle *v)
{
- Order order;
- Station *st;
+ const Order *order;
+ const Station *st;
if (v->current_order.type >= OT_GOTO_DEPOT && v->current_order.type <= OT_LEAVESTATION) {
- // Let a depot order in the schedule interrupt.
+ // Let a depot order in the orderlist interrupt.
if (v->current_order.type != OT_GOTO_DEPOT ||
!(v->current_order.flags & OF_UNLOAD))
return;
@@ -573,34 +570,35 @@ static void ProcessRoadVehOrder(Vehicle *v)
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
- order = v->schedule_ptr[v->cur_order_index];
+ order = GetVehicleOrder(v, v->cur_order_index);
- if (order.type == OT_NOTHING) {
+ if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->dest_tile = 0;
return;
}
- if (order.type == v->current_order.type &&
- order.flags == v->current_order.flags &&
- order.station == v->current_order.station)
+ if (order->type == v->current_order.type &&
+ order->flags == v->current_order.flags &&
+ order->station == v->current_order.station)
return;
- v->current_order = order;
+ v->current_order = *order;
v->dest_tile = 0;
- if (order.type == OT_GOTO_STATION) {
- if (order.station == v->last_station_visited)
+ if (order->type == OT_GOTO_STATION) {
+ if (order->station == v->last_station_visited)
v->last_station_visited = 0xFFFF;
- st = GetStation(order.station);
- v->dest_tile = v->cargo_type==CT_PASSENGERS ? st->bus_tile : st->lorry_tile;
- } else if (order.type == OT_GOTO_DEPOT) {
- v->dest_tile = _depots[order.station].xy;
+
+ st = GetStation(order->station);
+ v->dest_tile = v->cargo_type == CT_PASSENGERS ? st->bus_tile : st->lorry_tile;
+ } else if (order->type == OT_GOTO_DEPOT) {
+ v->dest_tile = _depots[order->station].xy;
}
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
}
static void HandleRoadVehLoading(Vehicle *v)
@@ -634,7 +632,7 @@ static void HandleRoadVehLoading(Vehicle *v)
}
v->cur_order_index++;
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
}
static void StartRoadVehSound(Vehicle *v)
@@ -1390,7 +1388,7 @@ void RoadVehEnterDepot(Vehicle *v)
v->current_order.type = OT_DUMMY;
v->current_order.flags = 0;
- // Part of the schedule?
+ // Part of the orderlist?
if (t.flags & OF_UNLOAD) {
v->cur_order_index++;
} else if (t.flags & OF_FULL_LOAD) {
@@ -1436,7 +1434,7 @@ static void CheckIfRoadVehNeedsService(Vehicle *v)
if (v->vehstatus & VS_STOPPED)
return;
- if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
+ if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
// Don't interfere with a depot visit scheduled by the user, or a
diff --git a/saveload.c b/saveload.c
index bfba0ff7b..4d44f4d3d 100644
--- a/saveload.c
+++ b/saveload.c
@@ -8,7 +8,7 @@
enum {
SAVEGAME_MAJOR_VERSION = 5,
- SAVEGAME_MINOR_VERSION = 1,
+ SAVEGAME_MINOR_VERSION = 2,
SAVEGAME_LOADABLE_VERSION = (SAVEGAME_MAJOR_VERSION << 8) + SAVEGAME_MINOR_VERSION
};
@@ -869,6 +869,7 @@ static void UninitWriteZlib()
extern const ChunkHandler _misc_chunk_handlers[];
extern const ChunkHandler _player_chunk_handlers[];
extern const ChunkHandler _veh_chunk_handlers[];
+extern const ChunkHandler _order_chunk_handlers[];
extern const ChunkHandler _town_chunk_handlers[];
extern const ChunkHandler _sign_chunk_handlers[];
extern const ChunkHandler _station_chunk_handlers[];
@@ -880,6 +881,7 @@ extern const ChunkHandler _animated_tile_chunk_handlers[];
static const ChunkHandler * const _chunk_handlers[] = {
_misc_chunk_handlers,
_veh_chunk_handlers,
+ _order_chunk_handlers,
_industry_chunk_handlers,
_economy_chunk_handlers,
_engine_chunk_handlers,
@@ -912,9 +914,7 @@ static uint ReferenceToInt(void *v, uint t)
case REF_VEHICLE: return ((Vehicle *)v)->index + 1;
case REF_STATION: return ((Station *)v)->index + 1;
case REF_TOWN: return ((Town *)v)->index + 1;
-
- case REF_SCHEDULE:
- return ((byte*)v - (byte*)_order_array) / sizeof(_order_array[0]) + 1;
+ case REF_ORDER: return ((Order *)v)->index + 1;
default:
NOT_REACHED();
@@ -935,13 +935,11 @@ void *IntToReference(uint r, uint t)
return NULL;
switch (t) {
+ case REF_ORDER: return GetOrder(r - 1);
case REF_VEHICLE: return GetVehicle(r - 1);
case REF_STATION: return GetStation(r - 1);
case REF_TOWN: return GetTown(r - 1);
- case REF_SCHEDULE:
- return (byte*)_order_array + (r - 1) * sizeof(_order_array[0]);
-
case REF_VEHICLE_OLD: {
/* Old vehicles were saved differently: invalid vehicle was 0xFFFF,
and the index was not - 1.. correct for this */
diff --git a/saveload.h b/saveload.h
index 159252590..86d41f1c5 100644
--- a/saveload.h
+++ b/saveload.h
@@ -70,11 +70,11 @@ typedef struct {
extern SaverLoader _sl;
enum {
- REF_SCHEDULE = 0,
- REF_VEHICLE = 1,
- REF_STATION = 2,
- REF_TOWN = 3,
- REF_VEHICLE_OLD = 4,
+ REF_ORDER = 0,
+ REF_VEHICLE = 1,
+ REF_STATION = 2,
+ REF_TOWN = 3,
+ REF_VEHICLE_OLD = 4
};
diff --git a/ship_cmd.c b/ship_cmd.c
index 3ed827fa1..161939be2 100644
--- a/ship_cmd.c
+++ b/ship_cmd.c
@@ -23,13 +23,13 @@ static byte GetTileShipTrackStatus(uint tile) {
void InvalidateShipWindows(const Vehicle *v)
{
- const Order *o;
+ const Order *order;
InvalidateWindow(WC_SHIPS_LIST, v->owner);
- for ( o = v->schedule_ptr; o->type != OT_NOTHING; o++) {
- if (o->type == OT_GOTO_STATION ) {
- InvalidateWindow(WC_SHIPS_LIST, o->station << 16 | v->owner);
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->type == OT_GOTO_STATION ) {
+ InvalidateWindow(WC_SHIPS_LIST, (order->station << 16) | v->owner);
}
}
}
@@ -113,7 +113,7 @@ static void CheckIfShipNeedsService(Vehicle *v)
v->current_order.flags & OF_FULL_LOAD)
return;
- if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
+ if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
i = FindClosestShipDepot(v);
@@ -215,8 +215,7 @@ static const TileIndexDiffC _dock_offs[] = {
static void ProcessShipOrder(Vehicle *v)
{
- Order order;
- Station *st;
+ const Order *order;
if (v->current_order.type >= OT_GOTO_DEPOT &&
v->current_order.type <= OT_LEAVESTATION) {
@@ -235,36 +234,39 @@ static void ProcessShipOrder(Vehicle *v)
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
- order = v->schedule_ptr[v->cur_order_index];
+ order = GetVehicleOrder(v, v->cur_order_index);
- if (order.type == OT_NOTHING) {
- v->current_order.type = OT_NOTHING;
+ if (order == NULL) {
+ v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->dest_tile = 0;
return;
}
- if (order.type == v->current_order.type &&
- order.flags == v->current_order.flags &&
- order.station == v->current_order.station)
+ if (order->type == v->current_order.type &&
+ order->flags == v->current_order.flags &&
+ order->station == v->current_order.station)
return;
- v->current_order = order;
+ v->current_order = *order;
- if (order.type == OT_GOTO_STATION) {
- if (order.station == v->last_station_visited)
+ if (order->type == OT_GOTO_STATION) {
+ const Station *st;
+
+ if (order->station == v->last_station_visited)
v->last_station_visited = 0xFFFF;
- st = GetStation(order.station);
+ st = GetStation(order->station);
if (st->dock_tile != 0) {
v->dest_tile = TILE_ADD(st->dock_tile, ToTileIndexDiff(_dock_offs[_map5[st->dock_tile]-0x4B]));
}
- } else if (order.type == OT_GOTO_DEPOT) {
- v->dest_tile = _depots[order.station].xy;
+ } else if (order->type == OT_GOTO_DEPOT) {
+ v->dest_tile = _depots[order->station].xy;
} else {
v->dest_tile = 0;
}
- InvalidateVehicleOrderWidget(v);
+
+ InvalidateVehicleOrder(v);
InvalidateShipWindows(v);
}
@@ -301,7 +303,7 @@ static void HandleShipLoading(Vehicle *v)
}
v->cur_order_index++;
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
}
static void UpdateShipDeltaXY(Vehicle *v, int dir)
@@ -692,7 +694,7 @@ static void ShipController(Vehicle *v)
v->last_station_visited = v->current_order.station;
- /* Process station in the schedule. Don't do that for buoys (HVOT_BUOY) */
+ /* Process station in the orderlist. Don't do that for buoys (HVOT_BUOY) */
st = GetStation(v->current_order.station);
if (!(st->had_vehicle_of_type & HVOT_BUOY)
&& (st->facilities & FACIL_DOCK)) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
@@ -711,7 +713,7 @@ static void ShipController(Vehicle *v)
v->current_order.type = OT_LEAVESTATION;
v->current_order.flags = 0;
v->cur_order_index++;
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
}
goto else_end;
}
@@ -830,7 +832,7 @@ int32 CmdBuildShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
return value;
v = AllocateVehicle();
- if (v == NULL || _ptr_to_next_order >= endof(_order_array) ||
+ if (v == NULL || IsOrderPoolFull() ||
(unit_num = GetFreeUnitNumber(VEH_Ship)) > _patches.max_ships)
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
@@ -871,9 +873,6 @@ int32 CmdBuildShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->string_id = STR_SV_SHIP_NAME;
v->u.ship.state = 0x80;
- _ptr_to_next_order->type = OT_NOTHING;
- _ptr_to_next_order->flags = 0;
- v->schedule_ptr = _ptr_to_next_order++;
v->service_interval = _patches.servint_ships;
v->date_of_last_service = _date;
diff --git a/ship_gui.c b/ship_gui.c
index f7c54a10f..92b6cffd0 100644
--- a/ship_gui.c
+++ b/ship_gui.c
@@ -863,15 +863,14 @@ void ShowShipDepotWindow(uint tile)
}
-static void DrawSmallShipSchedule(Vehicle *v, int x, int y) {
- Order *sched;
- int sel;
- Station *st;
- int i = 0;
+static void DrawSmallOrderList(Vehicle *v, int x, int y) {
+ const Order *order;
+ int sel, i = 0;
sel = v->cur_order_index;
+ order = v->orders;
- for (sched = v->schedule_ptr; sched->type != OT_NOTHING; ++sched) {
+ while (order != NULL) {
if (sel == 0) {
_stringwidth_base = 0xE0;
DoDrawString( "\xAF", x-6, y, 16);
@@ -879,11 +878,9 @@ static void DrawSmallShipSchedule(Vehicle *v, int x, int y) {
}
sel--;
- if (sched->type == OT_GOTO_STATION) {
- st = GetStation(sched->station);
-
- if (!(st->had_vehicle_of_type & HVOT_BUOY)) {
- SetDParam(0, sched->station);
+ if (order->type == OT_GOTO_STATION) {
+ if (!(GetStation(order->station)->had_vehicle_of_type & HVOT_BUOY)) {
+ SetDParam(0, order->station);
DrawString(x, y, STR_A036, 0);
y += 6;
@@ -891,6 +888,8 @@ static void DrawSmallShipSchedule(Vehicle *v, int x, int y) {
break;
}
}
+
+ order = order->next;
}
}
@@ -998,7 +997,7 @@ static void PlayerShipsWndProc(Window *w, WindowEvent *e)
DrawString(x + 12, y, STR_01AB, 0);
}
- DrawSmallShipSchedule(v, x + 138, y);
+ DrawSmallOrderList(v, x + 138, y);
y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
}
diff --git a/station.h b/station.h
index 17a0bb4da..34e48b91e 100644
--- a/station.h
+++ b/station.h
@@ -88,7 +88,7 @@ enum {
void ModifyStationRatingAround(TileIndex tile, byte owner, int amount, uint radius);
-TileIndex GetStationTileForVehicle(Vehicle *v, Station *st);
+TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st);
void ShowStationViewWindow(int station);
void UpdateAllStationVirtCoord();
diff --git a/station_cmd.c b/station_cmd.c
index 29b23855c..9ee23292b 100644
--- a/station_cmd.c
+++ b/station_cmd.c
@@ -94,7 +94,7 @@ static Station *GetStationAround(uint tile, int w, int h, int closest_station)
return (closest_station == -1) ? NULL : GetStation(closest_station);
}
-TileIndex GetStationTileForVehicle(Vehicle *v, Station *st)
+TileIndex GetStationTileForVehicle(const Vehicle *v, const Station *st)
{
switch (v->type) {
case VEH_Train: return st->train_tile;
@@ -2257,10 +2257,11 @@ static void DeleteStation(Station *st)
index = st->index;
DeleteWindowById(WC_STATION_VIEW, index);
+
order.type = OT_GOTO_STATION;
- order.flags = 0;
order.station = index;
- DeleteCommandFromVehicleSchedule(order);
+ DeleteDestinationFromVehicleOrder(order);
+
DeleteSubsidyWithStation(index);
}
diff --git a/train_cmd.c b/train_cmd.c
index e11656e2d..228d1c18e 100644
--- a/train_cmd.c
+++ b/train_cmd.c
@@ -395,7 +395,7 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
if (!(flags & DC_QUERY_COST)) {
v = AllocateVehicle();
- if (v == NULL || _ptr_to_next_order >= endof(_order_array))
+ if (v == NULL || IsOrderPoolFull())
return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
unit_num = GetFreeUnitNumber(VEH_Train);
@@ -417,24 +417,13 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->u.rail.track = 0x80;
v->u.rail.first_engine = 0xffff;
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
-// v->subtype = 0;
v->spritenum = rvi->image_index;
v->cargo_type = rvi->cargo_type;
v->cargo_cap = rvi->capacity;
v->max_speed = rvi->max_speed;
-// v->cargo_count = 0;
v->value = value;
-// v->day_counter = 0;
-// v->current_order = 0;
-// v->next_station = 0;
-// v->load_unload_time_rem = 0;
-// v->progress = 0;
-// v->targetairport = 0;
-// v->crash_anim_pos = 0;
v->last_station_visited = 0xFFFF;
v->dest_tile = 0;
-// v->profit_last_year = 0;
-// v->profit_this_year = 0;
v->engine_type = (byte)p1;
e = &_engines[p1];
@@ -444,23 +433,10 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
v->max_age = e->lifelength * 366;
v->string_id = STR_SV_TRAIN_NAME;
-// v->cur_speed = 0;
-// v->subspeed = 0;
v->u.rail.railtype = e->railtype;
_new_train_id = v->index;
-// v->cur_order_index = 0;
-// v->num_orders = 0;
-
- _ptr_to_next_order->type = OT_NOTHING;
- _ptr_to_next_order->flags = 0;
- v->schedule_ptr = _ptr_to_next_order++;
-// v->next_in_chain = 0xffff;
-// v->next = NULL;
v->service_interval = _patches.servint_trains;
-// v->breakdown_ctr = 0;
-// v->breakdowns_since_last_service = 0;
-// v->unk4D = 0;
v->date_of_last_service = _date;
v->build_year = _cur_year;
v->type = VEH_Train;
@@ -680,12 +656,9 @@ int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
// move the train to an empty line. for locomotives, we set the type to 0. for wagons, 4.
if (is_loco) {
if (src->subtype != 0) {
- // setting the type to 0 also involves setting up the schedule_ptr field.
+ // setting the type to 0 also involves setting up the orders field.
src->subtype = 0;
- assert(src->schedule_ptr == NULL);
- _ptr_to_next_order->type = OT_NOTHING;
- _ptr_to_next_order->flags = 0;
- src->schedule_ptr = _ptr_to_next_order++;
+ assert(src->orders == NULL);
src->num_orders = 0;
}
dst_head = src;
@@ -695,9 +668,9 @@ int32 CmdMoveRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
src->u.rail.first_engine = 0xffff;
} else {
if (src->subtype == 0) {
- // the vehicle was previously a loco. need to free the schedule list and delete vehicle windows etc.
+ // the vehicle was previously a loco. need to free the order list and delete vehicle windows etc.
DeleteWindowById(WC_VEHICLE_VIEW, src->index);
- DeleteVehicleSchedule(src);
+ DeleteVehicleOrders(src);
}
src->subtype = 2;
@@ -1644,13 +1617,13 @@ bad:;
static bool ProcessTrainOrder(Vehicle *v)
{
- Order order;
+ const Order *order;
bool result;
// These are un-interruptible
if (v->current_order.type >= OT_GOTO_DEPOT &&
v->current_order.type <= OT_LEAVESTATION) {
- // Let a depot order in the schedule interrupt.
+ // Let a depot order in the orderlist interrupt.
if (v->current_order.type != OT_GOTO_DEPOT ||
!(v->current_order.flags & OF_UNLOAD))
return false;
@@ -1676,10 +1649,11 @@ static bool ProcessTrainOrder(Vehicle *v)
// Get the current order
if (v->cur_order_index >= v->num_orders)
v->cur_order_index = 0;
- order = v->schedule_ptr[v->cur_order_index];
+
+ order = GetVehicleOrder(v, v->cur_order_index);
// If no order, do nothing.
- if (order.type == OT_NOTHING) {
+ if (order == NULL) {
v->current_order.type = OT_NOTHING;
v->current_order.flags = 0;
v->dest_tile = 0;
@@ -1687,31 +1661,37 @@ static bool ProcessTrainOrder(Vehicle *v)
}
// If it is unchanged, keep it.
- if (order.type == v->current_order.type &&
- order.flags == v->current_order.flags &&
- order.station == v->current_order.station)
+ if (order->type == v->current_order.type &&
+ order->flags == v->current_order.flags &&
+ order->station == v->current_order.station)
return false;
// Otherwise set it, and determine the destination tile.
- v->current_order = order;
+ v->current_order = *order;
v->dest_tile = 0;
result = false;
- if (order.type == OT_GOTO_STATION) {
- if (order.station == v->last_station_visited)
- v->last_station_visited = 0xFFFF;
- v->dest_tile = GetStation(order.station)->xy;
- result = CheckReverseTrain(v);
- } else if (order.type == OT_GOTO_DEPOT) {
- v->dest_tile = _depots[order.station].xy;
- result = CheckReverseTrain(v);
- } else if (order.type == OT_GOTO_WAYPOINT) {
- v->dest_tile = _waypoints[order.station].xy;
- result = CheckReverseTrain(v);
+ switch (order->type) {
+ case OT_GOTO_STATION:
+ if (order->station == v->last_station_visited)
+ v->last_station_visited = 0xFFFF;
+ v->dest_tile = GetStation(order->station)->xy;
+ result = CheckReverseTrain(v);
+ break;
+
+ case OT_GOTO_DEPOT:
+ v->dest_tile = _depots[order->station].xy;
+ result = CheckReverseTrain(v);
+ break;
+
+ case OT_GOTO_WAYPOINT:
+ v->dest_tile = _waypoints[order->station].xy;
+ result = CheckReverseTrain(v);
+ break;
}
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
return result;
}
@@ -1771,7 +1751,7 @@ static void HandleTrainLoading(Vehicle *v, bool mode)
v->u.rail.days_since_order_progr = 0;
v->cur_order_index++;
- InvalidateVehicleOrderWidget(v);
+ InvalidateVehicleOrder(v);
}
static int UpdateTrainSpeed(Vehicle *v)
@@ -2669,7 +2649,7 @@ void TrainEnterDepot(Vehicle *v, uint tile)
v->current_order.type = OT_DUMMY;
v->current_order.flags = 0;
- if (t.flags & OF_UNLOAD) { // Part of the schedule?
+ if (t.flags & OF_UNLOAD) { // Part of the orderlist?
v->u.rail.days_since_order_progr = 0;
v->cur_order_index++;
} else if (t.flags & OF_FULL_LOAD) { // User initiated?
@@ -2701,7 +2681,7 @@ static void CheckIfTrainNeedsService(Vehicle *v)
if (v->vehstatus & VS_STOPPED)
return;
- if (_patches.gotodepot && ScheduleHasDepotOrders(v->schedule_ptr))
+ if (_patches.gotodepot && VehicleHasDepotOrders(v))
return;
// Don't interfere with a depot visit scheduled by the user, or a
@@ -2834,11 +2814,3 @@ void InitializeTrains()
{
_age_cargo_skip_counter = 1;
}
-
-int ScheduleHasDepotOrders(const Order *schedule)
-{
- for (; schedule->type != OT_NOTHING; schedule++)
- if (schedule->type == OT_GOTO_DEPOT)
- return true;
- return false;
-}
diff --git a/ttd.c b/ttd.c
index 82dbd4e9c..df0d7a5e4 100644
--- a/ttd.c
+++ b/ttd.c
@@ -496,6 +496,7 @@ static void InitializeDynamicVariables(void)
_industry_sort = NULL;
_sign_size = lengthof(_sign_list);
+ _orders_size = lengthof(_orders);
}
static void UnInitializeDynamicVariables(void)
diff --git a/vehicle.c b/vehicle.c
index 318bfdc57..746b724d3 100644
--- a/vehicle.c
+++ b/vehicle.c
@@ -33,24 +33,6 @@ bool VehicleNeedsService(const Vehicle *v)
(v->date_of_last_service + v->service_interval < _date);
}
-Order UnpackOldOrder(uint16 packed)
-{
- Order order;
- order.type = (packed & 0x000f);
- order.flags = (packed & 0x00f0) >> 4;
- order.station = (packed & 0xff00) >> 8;
-
- // Sanity check
- // TTD stores invalid orders as OT_NOTHING with non-zero flags/station
- if (order.type == OT_NOTHING && (order.flags != 0 || order.station != 0)) {
- order.type = OT_DUMMY;
- order.flags = 0;
- }
-
- return order;
-}
-
-
void VehicleInTheWayErrMsg(Vehicle *v)
{
StringID id;
@@ -177,11 +159,6 @@ void AfterLoadVehicles()
if (v->subtype == 0)
UpdateTrainAcceleration(v);
}
-
-#if defined(_DEBUG)
- if (!(v->schedule_ptr == NULL || (v->schedule_ptr >= _order_array && v->schedule_ptr < _ptr_to_next_order)))
- v->schedule_ptr = NULL;
-#endif
}
}
@@ -196,7 +173,7 @@ static Vehicle *InitializeVehicle(Vehicle *v)
memset(v, 0, sizeof(Vehicle));
v->index = index;
- assert(v->schedule_ptr == NULL);
+ assert(v->orders == NULL);
v->left_coord = INVALID_COORD;
v->next = NULL;
@@ -353,8 +330,6 @@ void InitializeVehicles()
v->index = i++;
memset(_vehicle_position_hash, -1, sizeof(_vehicle_position_hash));
-
- _ptr_to_next_order = _order_array;
}
Vehicle *GetLastVehicleInChain(Vehicle *v)
@@ -439,91 +414,6 @@ uint GetWaypointByTile(uint tile)
return i;
}
-
-Vehicle *IsScheduleShared(Vehicle *u)
-{
- const Order *sched = u->schedule_ptr;
- Vehicle *v;
-
- FOR_ALL_VEHICLES(v) {
- if (v->schedule_ptr == sched && u != v && v->type != 0)
- return v;
- }
- return NULL;
-}
-
-void DeleteVehicleSchedule(Vehicle *v)
-{
- Order *sched;
- Order *cur;
- int num;
- Vehicle *u;
-
- // if the schedule is shared, don't delete it.
- if ((u = IsScheduleShared(v)) != NULL) {
- v->schedule_ptr = NULL;
- InvalidateWindow(WC_VEHICLE_ORDERS, u->index);
- return;
- }
-
- sched = v->schedule_ptr;
- v->schedule_ptr = NULL;
-
- num = v->num_orders + 1;
-
- _ptr_to_next_order -= num;
-
- cur = sched;
- while (cur != _ptr_to_next_order) {
- assert(cur < _ptr_to_next_order);
- cur[0] = cur[num];
- cur++;
- }
-
- FOR_ALL_VEHICLES(v) {
- if (v->schedule_ptr != NULL && sched < v->schedule_ptr) {
- v->schedule_ptr -= num;
- }
- }
-}
-
-void DeleteCommandFromVehicleSchedule(Order cmd)
-{
- Vehicle *v;
- bool need_invalidate;
-
- FOR_ALL_VEHICLES(v) {
- if (v->type != 0 && v->schedule_ptr != NULL) {
- Order *sched;
-
- // clear last station visited
- if (v->last_station_visited == cmd.station && cmd.type == OT_GOTO_STATION)
- v->last_station_visited = 0xFFFF;
-
- // check the next order
- if (v->current_order.type == cmd.type &&
- v->current_order.station == cmd.station) {
- v->current_order.type = OT_DUMMY;
- v->current_order.flags = 0;
- InvalidateWindow(WC_VEHICLE_VIEW, v->index);
- }
-
- // clear the order list
- need_invalidate = false;
- for (sched = v->schedule_ptr; sched->type != OT_NOTHING; ++sched) {
- if (sched->type == cmd.type && sched->station == cmd.station) {
- sched->type = OT_DUMMY;
- sched->flags = 0;
- need_invalidate = true;
- }
- }
-
- if (need_invalidate)
- InvalidateWindow(WC_VEHICLE_ORDERS, v->index);
- }
- }
-}
-
void DoDeleteDepot(uint tile)
{
Order order;
@@ -538,9 +428,8 @@ void DoDeleteDepot(uint tile)
d->xy = 0;
order.type = OT_GOTO_DEPOT;
- order.flags = 0;
order.station = dep_index;
- DeleteCommandFromVehicleSchedule(order);
+ DeleteDestinationFromVehicleOrder(order);
// Delete the depot
DeleteWindowById(WC_VEHICLE_DEPOT, tile);
@@ -553,8 +442,8 @@ void DeleteVehicle(Vehicle *v)
UpdateVehiclePosHash(v, INVALID_COORD, 0);
v->next_hash = 0xffff;
- if (v->schedule_ptr != NULL)
- DeleteVehicleSchedule(v);
+ if (v->orders != NULL)
+ DeleteVehicleOrders(v);
}
void DeleteVehicleChain(Vehicle *v)
@@ -1699,12 +1588,6 @@ void EndVehicleMove(Vehicle *v)
);
}
-void InvalidateVehicleOrderWidget(Vehicle *v)
-{
- InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
- InvalidateWindowWidget(WC_VEHICLE_ORDERS, v->index, 2);
-}
-
/* returns true if staying in the same tile */
bool GetNewVehiclePos(Vehicle *v, GetNewVehiclePosResult *gp)
{
@@ -1846,7 +1729,7 @@ const byte _common_veh_desc[] = {
SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, flags), SLE_UINT8, 5, 255),
SLE_CONDVARX(offsetof(Vehicle, current_order) + offsetof(Order, station), SLE_UINT16, 5, 255),
- SLE_REF(Vehicle,schedule_ptr, REF_SCHEDULE),
+ SLE_REF(Vehicle,orders, REF_ORDER),
SLE_VAR(Vehicle,age, SLE_UINT16),
SLE_VAR(Vehicle,max_age, SLE_UINT16),
@@ -1869,9 +1752,11 @@ const byte _common_veh_desc[] = {
SLE_VAR(Vehicle,random_bits, SLE_UINT8),
SLE_VAR(Vehicle,waiting_triggers, SLE_UINT8),
- // reserve extra space in savegame here. (currently 14 bytes)
+ SLE_REF(Vehicle,next_shared, REF_VEHICLE),
+ SLE_REF(Vehicle,prev_shared, REF_VEHICLE),
+
+ // reserve extra space in savegame here. (currently 10 bytes)
SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 2, 2, 255), /* 2 */
- SLE_CONDARR(NullStruct,null,SLE_FILE_U16 | SLE_VAR_NULL, 2, 2, 255), /* 4 */
SLE_CONDARR(NullStruct,null,SLE_FILE_U32 | SLE_VAR_NULL, 2, 2, 255), /* 8 */
SLE_END()
@@ -2068,6 +1953,29 @@ static void Load_VEHS()
w->u.rail.first_engine = v->engine_type;
}
+ /* Check for shared order-lists (we now use pointers for that) */
+ if (_sl.full_version < 0x502) {
+ FOR_ALL_VEHICLES(v) {
+ Vehicle *u;
+
+ if (v->type == 0)
+ continue;
+
+ FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
+ if (u->type == 0)
+ continue;
+
+ /* If a vehicle has the same orders, add the link to eachother
+ in both vehicles */
+ if (v->orders == u->orders) {
+ v->next_shared = u;
+ u->prev_shared = v;
+ break;
+ }
+ }
+ }
+ }
+
/* This is to ensure all pointers are within the limits of
_vehicles_size */
if (_vehicle_id_ctr_day >= _vehicles_size)
@@ -2131,55 +2039,8 @@ static void Load_CHKP()
}
}
-
-static void Save_ORDR()
-{
- uint32 orders[lengthof(_order_array)];
- uint len = _ptr_to_next_order - _order_array;
- uint i;
-
- assert (len <= lengthof(orders));
-
- for (i = 0; i < len; ++i)
- orders[i] = PackOrder(&_order_array[i]);
-
- SlArray(orders, len, SLE_UINT32);
-}
-
-static void Load_ORDR()
-{
- uint len = SlGetFieldLength();
- uint i;
-
- if (_sl.version < 5) {
- /* Older version had an other layout for orders.. convert them correctly */
- uint16 orders[lengthof(_order_array)];
-
- len /= sizeof(uint16);
- assert (len <= lengthof(orders));
-
- SlArray(orders, len, SLE_UINT16);
-
- for (i = 0; i < len; ++i)
- _order_array[i] = UnpackVersion4Order(orders[i]);
- } else {
- uint32 orders[lengthof(_order_array)];
-
- len /= sizeof(uint32);
- assert (len <= lengthof(orders));
-
- SlArray(orders, len, SLE_UINT32);
-
- for (i = 0; i < len; ++i)
- _order_array[i] = UnpackOrder(orders[i]);
- }
-
- _ptr_to_next_order = _order_array + len;
-}
-
const ChunkHandler _veh_chunk_handlers[] = {
{ 'VEHS', Save_VEHS, Load_VEHS, CH_SPARSE_ARRAY},
- { 'ORDR', Save_ORDR, Load_ORDR, CH_RIFF},
{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY},
{ 'CHKP', Save_CHKP, Load_CHKP, CH_ARRAY | CH_LAST},
};
diff --git a/vehicle.h b/vehicle.h
index bdc9ca853..8a0aae4bd 100644
--- a/vehicle.h
+++ b/vehicle.h
@@ -2,42 +2,7 @@
#define VEHICLE_H
#include "vehicle_gui.h"
-
-/* If you change this, keep in mind that it is saved on 3 places:
- - Load_ORDR, all the global orders
- - Vehicle -> current_order
- - REF_SHEDULE (all REFs are currently limited to 16 bits!!) */
-typedef struct Order {
- uint8 type;
- uint8 flags;
- uint16 station;
-} Order;
-
-static inline uint32 PackOrder(const Order *order)
-{
- return order->station << 16 | order->flags << 8 | order->type;
-}
-
-static inline Order UnpackOrder(uint32 packed)
-{
- Order order;
- order.type = (packed & 0x000000FF);
- order.flags = (packed & 0x0000FF00) >> 8;
- order.station = (packed & 0xFFFF0000) >> 16;
- return order;
-}
-
-static inline Order UnpackVersion4Order(uint16 packed)
-{
- Order order;
- order.type = (packed & 0x000F);
- order.flags = (packed & 0x00F0) >> 4;
- order.station = (packed & 0xFF00) >> 8;
- return order;
-}
-
-Order UnpackOldOrder(uint16 packed);
-
+#include "order.h"
typedef struct VehicleRail {
uint16 last_speed; // NOSAVE: only used in UI
@@ -177,11 +142,16 @@ struct Vehicle {
byte day_counter; // increased by one for each day
byte tick_counter;// increased by one for each tick
- // related to the current order
- byte cur_order_index;
- byte num_orders;
- Order current_order;
- Order *schedule_ptr;
+ /* Begin Order-stuff */
+ Order current_order; //! The current order (+ status, like: loading)
+ byte cur_order_index; //! The index to the current order
+
+ Order *orders; //! Pointer to the first order for this vehicle
+ byte num_orders; //! How many orders there are in the list
+
+ Vehicle *next_shared; //! If not NULL, this points to the next vehicle that shared the order
+ Vehicle *prev_shared; //! If not NULL, this points to the prev vehicle that shared the order
+ /* End Order-stuff */
// Boundaries for the current position in the world and a next hash link.
// NOSAVE: All of those can be updated with VehiclePositionChanged()
@@ -248,25 +218,6 @@ enum {
VEH_Disaster = 0x15,
};
-/* Order types */
-enum {
- OT_NOTHING = 0,
- OT_GOTO_STATION = 1,
- OT_GOTO_DEPOT = 2,
- OT_LOADING = 3,
- OT_LEAVESTATION = 4,
- OT_DUMMY = 5,
- OT_GOTO_WAYPOINT = 6,
-};
-
-/* Order flags */
-enum {
- OF_UNLOAD = 0x2,
- OF_FULL_LOAD = 0x4, // Also used when to force an aircraft into a depot
- OF_NON_STOP = 0x8
-};
-
-
enum VehStatus {
VS_HIDDEN = 1,
VS_STOPPED = 2,
@@ -302,22 +253,11 @@ enum {
typedef void VehicleTickProc(Vehicle *v);
typedef void *VehicleFromPosProc(Vehicle *v, void *data);
-typedef struct {
- VehicleID clone;
- byte orderindex;
- Order order[41];
- uint16 service_interval;
- char name[32];
-} BackuppedOrders;
-
void VehicleServiceInDepot(Vehicle *v);
-void BackupVehicleOrders(Vehicle *v, BackuppedOrders *order);
-void RestoreVehicleOrders(Vehicle *v, BackuppedOrders *order);
Vehicle *AllocateVehicle();
Vehicle *ForceAllocateVehicle();
Vehicle *ForceAllocateSpecialVehicle();
void UpdateVehiclePosHash(Vehicle *v, int x, int y);
-void InitializeVehicles();
void VehiclePositionChanged(Vehicle *v);
void AfterLoadVehicles();
Vehicle *GetLastVehicleInChain(Vehicle *v);
@@ -328,8 +268,6 @@ void DeleteVehicle(Vehicle *v);
void DeleteVehicleChain(Vehicle *v);
void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks();
-void DeleteVehicleSchedule(Vehicle *v);
-Vehicle *IsScheduleShared(Vehicle *v);
Depot *AllocateDepot();
Waypoint *AllocateWaypoint();
@@ -373,16 +311,12 @@ void CheckVehicleBreakdown(Vehicle *v);
void AgeVehicle(Vehicle *v);
void MaybeReplaceVehicle(Vehicle *v);
-void DeleteCommandFromVehicleSchedule(Order cmd);
-
void BeginVehicleMove(Vehicle *v);
void EndVehicleMove(Vehicle *v);
bool IsAircraftHangarTile(TileIndex tile);
void ShowAircraftViewWindow(Vehicle *v);
-void InvalidateVehicleOrderWidget(Vehicle *v);
-
bool IsShipDepotTile(TileIndex tile);
uint GetFreeUnitNumber(byte type);
@@ -397,9 +331,6 @@ int32 GetTrainRunningCost(Vehicle *v);
int CheckStoppedInDepot(Vehicle *v);
-int ScheduleHasDepotOrders(const Order *schedule);
-int CheckOrders(Vehicle *v);
-
bool VehicleNeedsService(const Vehicle *v);
void InvalidateAircraftWindows(const Vehicle *v);
@@ -439,8 +370,43 @@ static inline Vehicle *GetVehicle(uint index)
#define FOR_ALL_VEHICLES(v) for(v = _vehicles; v != &_vehicles[_vehicles_size]; v++)
#define FOR_ALL_VEHICLES_FROM(v, from) for(v = GetVehicle(from); v != &_vehicles[_vehicles_size]; v++)
-VARDEF Order _order_array[5000];
-VARDEF Order *_ptr_to_next_order;
+/* Returns order 'index' of a vehicle or NULL when it doesn't exists */
+static inline Order *GetVehicleOrder(const Vehicle *v, int index)
+{
+ Order *order = v->orders;
+
+ if (index < 0)
+ return NULL;
+
+ while (order != NULL && index-- > 0)
+ order = order->next;
+
+ return order;
+}
+
+/* Returns the last order of a vehicle, or NULL if it doesn't exists */
+static inline Order *GetLastVehicleOrder(const Vehicle *v)
+{
+ Order *order = v->orders;
+
+ if (order == NULL)
+ return NULL;
+
+ while (order->next != NULL)
+ order = order->next;
+
+ return order;
+}
+
+/* Get the first vehicle of a shared-list, so we only have to walk forwards */
+static inline Vehicle *GetFirstVehicleFromSharedList(Vehicle *v)
+{
+ Vehicle *u = v;
+ while (u->prev_shared != NULL)
+ u = u->prev_shared;
+
+ return u;
+}
VARDEF Depot _depots[255];
@@ -465,8 +431,6 @@ VARDEF TileIndex _last_built_train_depot_tile;
VARDEF TileIndex _last_built_road_depot_tile;
VARDEF TileIndex _last_built_aircraft_depot_tile;
VARDEF TileIndex _last_built_ship_depot_tile;
-VARDEF TileIndex _backup_orders_tile;
-VARDEF BackuppedOrders _backup_orders_data[1];
// for each player, for each vehicle type, keep a list of the vehicles.
//VARDEF Vehicle *_vehicle_arr[8][4];
diff --git a/vehicle_gui.c b/vehicle_gui.c
index 6166db2b9..601e7730c 100644
--- a/vehicle_gui.c
+++ b/vehicle_gui.c
@@ -90,14 +90,16 @@ void BuildVehicleList(vehiclelist_d *vl, int type, int owner, int station)
const Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v->type == type && v->subtype <= subtype) {
- const Order *ord;
- for (ord = v->schedule_ptr; ord->type != OT_NOTHING; ++ord)
- if (ord->type == OT_GOTO_STATION && ord->station == station) {
+ const Order *order;
+
+ FOR_VEHICLE_ORDERS(v, order) {
+ if (order->type == OT_GOTO_STATION && order->station == station) {
_vehicle_sort[n].index = v->index;
_vehicle_sort[n].owner = v->owner;
++n;
break;
}
+ }
}
}
} else {