mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 14:27:16 +00:00
(svn r14803) -Codechange: move order list management into it's own class and remove the order count from the savegame as we can easily count that (PhilSophus)
This commit is contained in:
parent
fa2bf69a53
commit
0d54db5f9f
@ -329,12 +329,9 @@ static StringID *_old_vehicle_names = NULL;
|
||||
|
||||
static void FixOldVehicles()
|
||||
{
|
||||
/* Check for shared orders, and link them correctly */
|
||||
Vehicle* v;
|
||||
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
Vehicle *u;
|
||||
|
||||
v->name = CopyFromOldName(_old_vehicle_names[v->index]);
|
||||
|
||||
/* We haven't used this bit for stations for ages */
|
||||
@ -356,14 +353,7 @@ static void FixOldVehicles()
|
||||
v->current_order.MakeDummy();
|
||||
}
|
||||
|
||||
FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
|
||||
/* If a vehicle has the same orders, add the link to eachother
|
||||
* in both vehicles */
|
||||
if (v->orders == u->orders) {
|
||||
u->AddToShared(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Shared orders are fixed in AfterLoadVehicles now */
|
||||
}
|
||||
}
|
||||
|
||||
@ -1144,7 +1134,7 @@ static const OldChunks vehicle_chunk[] = {
|
||||
OCL_VAR ( OC_UINT32, 1, &_old_order_ptr ),
|
||||
OCL_VAR ( OC_UINT16, 1, &_old_order ),
|
||||
|
||||
OCL_SVAR( OC_UINT8, Vehicle, num_orders ),
|
||||
OCL_NULL ( 1 ), ///< num_orders, now calculated
|
||||
OCL_SVAR( OC_UINT8, Vehicle, cur_order_index ),
|
||||
OCL_SVAR( OC_TILE, Vehicle, dest_tile ),
|
||||
OCL_SVAR( OC_UINT16, Vehicle, load_unload_time_rem ),
|
||||
@ -1250,7 +1240,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num)
|
||||
* we go over that limit something is very wrong. In that case
|
||||
* we just assume there are no orders for the vehicle.
|
||||
*/
|
||||
if (old_id < 5000) v->orders = GetOrder(old_id);
|
||||
if (old_id < 5000) v->orders.old = GetOrder(old_id);
|
||||
}
|
||||
v->current_order.AssignOrder(UnpackOldOrder(_old_order));
|
||||
|
||||
|
@ -2386,7 +2386,10 @@ bool AfterLoadGame()
|
||||
|
||||
Vehicle *v;
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (v->orders != NULL && !v->orders->IsValid()) v->orders = NULL;
|
||||
if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && !v->orders.list->GetFirstOrder()->IsValid()) {
|
||||
v->orders.list->FreeChain();
|
||||
v->orders.list = NULL;
|
||||
}
|
||||
|
||||
v->current_order.ConvertFromOldSavegame();
|
||||
if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) {
|
||||
|
189
src/order_base.h
189
src/order_base.h
@ -15,6 +15,7 @@
|
||||
#include "waypoint_type.h"
|
||||
|
||||
DECLARE_OLD_POOL(Order, Order, 6, 1000)
|
||||
DECLARE_OLD_POOL(OrderList, OrderList, 4, 4000)
|
||||
|
||||
/* If you change this, keep in mind that it is saved on 3 places:
|
||||
* - Load_ORDR, all the global orders
|
||||
@ -118,12 +119,6 @@ public:
|
||||
*/
|
||||
void MakeConditional(VehicleOrderID order);
|
||||
|
||||
/**
|
||||
* Free a complete order chain.
|
||||
* @note do not use on "current_order" vehicle orders!
|
||||
*/
|
||||
void FreeChain();
|
||||
|
||||
/**
|
||||
* Gets the destination of this order.
|
||||
* @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION).
|
||||
@ -207,6 +202,14 @@ public:
|
||||
|
||||
bool ShouldStopAtStation(const Vehicle *v, StationID station) const;
|
||||
|
||||
/** Checks if this order has travel_time and if needed wait_time set. */
|
||||
inline bool IsCompletelyTimetabled() const
|
||||
{
|
||||
if (this->travel_time == 0 && !this->IsType(OT_CONDITIONAL)) return false;
|
||||
if (this->wait_time == 0 && this->IsType(OT_GOTO_STATION) && !(this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the given order to this one.
|
||||
* @param other the data to copy (except next pointer).
|
||||
@ -250,11 +253,183 @@ static inline VehicleOrderID GetNumOrders()
|
||||
return GetOrderPoolSize();
|
||||
}
|
||||
|
||||
/** Shared order list linking together the linked list of orders and the list
|
||||
* of vehicles sharing this order list.
|
||||
*/
|
||||
struct OrderList : PoolItem<OrderList, OrderListID, &_OrderList_pool> {
|
||||
private:
|
||||
friend void AfterLoadVehicles(bool part_of_load); ///< For instantiating the shared vehicle chain
|
||||
friend const struct SaveLoad *GetOrderListDescription(); ///< Saving and loading of order lists.
|
||||
|
||||
Order *first; ///< First order of the order list
|
||||
VehicleOrderID num_orders; ///< NOSAVE: How many orders there are in the list
|
||||
unsigned num_vehicles; ///< NOSAVE: Number of vehicles that share this order list
|
||||
Vehicle *first_shared; ///< NOSAVE: pointer to the first vehicle in the shared order chain
|
||||
|
||||
unsigned timetable_duration; ///< NOSAVE: Total duration of the order list
|
||||
|
||||
public:
|
||||
/** Default constructor producing an invalid order list. */
|
||||
OrderList()
|
||||
: first(NULL), num_orders(INVALID_VEH_ORDER_ID), num_vehicles(0), first_shared(NULL),
|
||||
timetable_duration(0) { }
|
||||
|
||||
/** Create an order list with the given order chain for the given vehicle.
|
||||
* @param chain is the pointer to the first order of the order chain
|
||||
* @param v is any vehicle of the shared order vehicle chain (does not need to be the first)
|
||||
*/
|
||||
OrderList(Order *chain, Vehicle *v);
|
||||
|
||||
/** Destructor. Invalidates OrderList for re-usage by the pool. */
|
||||
~OrderList() { this->num_orders = INVALID_VEH_ORDER_ID; }
|
||||
|
||||
/** Checks, if this is a valid order list. */
|
||||
inline bool IsValid() const { return this->num_orders != INVALID_VEH_ORDER_ID; }
|
||||
|
||||
/**
|
||||
* Get the first order of the order chain.
|
||||
* @return the first order of the chain.
|
||||
*/
|
||||
inline Order *GetFirstOrder() const { return this->first; }
|
||||
|
||||
/**
|
||||
* Get a certain order of the order chain.
|
||||
* @param index zero-based index of the order within the chain.
|
||||
* @return the order at position index.
|
||||
*/
|
||||
Order *GetOrderAt(int index) const;
|
||||
|
||||
/**
|
||||
* Get the last order of the order chain.
|
||||
* @return the last order of the chain.
|
||||
*/
|
||||
inline Order *GetLastOrder() const { return this->GetOrderAt(this->num_orders - 1); }
|
||||
|
||||
/**
|
||||
* Get number of orders in the order list.
|
||||
* @return number of orders in the chain. */
|
||||
inline VehicleOrderID GetNumOrders() const { return this->num_orders; }
|
||||
|
||||
/**
|
||||
* Insert a new order into the order chain.
|
||||
* @param new_order is the order to insert into the chain.
|
||||
* @param index is the position where the order is supposed to be inserted. */
|
||||
void InsertOrderAt(Order *new_order, int index);
|
||||
|
||||
/**
|
||||
* Remove an order from the order list and delete it.
|
||||
* @param index is the position of the order which is to be deleted.
|
||||
*/
|
||||
void DeleteOrderAt(int index);
|
||||
|
||||
/**
|
||||
* Move an order to another position within the order list.
|
||||
* @param from is the zero-based position of the order to move.
|
||||
* @param to is the zero-based position where the order is moved to. */
|
||||
void MoveOrder(int from, int to);
|
||||
|
||||
/**
|
||||
* Is this a shared order list?
|
||||
* @return whether this order list is shared among multiple vehicles
|
||||
*/
|
||||
inline bool IsShared() const { return this->num_vehicles > 1; };
|
||||
|
||||
/**
|
||||
* Get the first vehicle of this vehicle chain.
|
||||
* @return the first vehicle of the chain.
|
||||
*/
|
||||
inline Vehicle *GetFirstSharedVehicle() const { return this->first_shared; }
|
||||
|
||||
/**
|
||||
* Return the number of vehicles that share this orders list
|
||||
* @return the count of vehicles that use this shared orders list
|
||||
*/
|
||||
inline unsigned GetNumVehicles() const { return this->num_vehicles; }
|
||||
|
||||
/**
|
||||
* Checks whether a vehicle is part of the shared vehicle chain.
|
||||
* @param v is the vehicle to search in the shared vehicle chain.
|
||||
*/
|
||||
bool IsVehicleInSharedOrdersList(const Vehicle *v) const;
|
||||
|
||||
/**
|
||||
* Gets the position of the given vehicle within the shared order vehicle list.
|
||||
* @param v is the vehicle of which to get the position
|
||||
* @return position of v within the shared vehicle chain.
|
||||
*/
|
||||
int GetPositionInSharedOrderList(const Vehicle *v) const;
|
||||
|
||||
/**
|
||||
* Adds the given vehicle to this shared order list.
|
||||
* @note This is supposed to be called after the vehicle has been inserted
|
||||
* into the shared vehicle chain.
|
||||
* @param v vehicle to add to the list
|
||||
*/
|
||||
inline void AddVehicle(Vehicle *v) { ++this->num_vehicles; }
|
||||
|
||||
/**
|
||||
* Removes the vehicle from the shared order list.
|
||||
* @note This is supposed to be called when the vehicle is still in the chain
|
||||
* @param v vehicle to remove from the list
|
||||
*/
|
||||
void RemoveVehicle(Vehicle *v);
|
||||
|
||||
/**
|
||||
* Checks whether all orders of the list have a filled timetable.
|
||||
* @return whether all orders have a filled timetable.
|
||||
*/
|
||||
bool IsCompleteTimetable() const;
|
||||
|
||||
/**
|
||||
* Gets the total duration of the vehicles timetable or -1 is the timetable is not complete.
|
||||
* @return total timetable duration or -1 for incomplete timetables
|
||||
*/
|
||||
inline int GetTimetableTotalDuration() const { return this->IsCompleteTimetable() ? this->timetable_duration : -1; }
|
||||
|
||||
/**
|
||||
* Gets the known duration of the vehicles timetable even if the timetable is not complete.
|
||||
* @return known timetable duration
|
||||
*/
|
||||
inline int GetTimetableDurationIncomplete() const { return this->timetable_duration; }
|
||||
|
||||
/**
|
||||
* Must be called if an order's timetable is changed to update internal book keeping.
|
||||
* @param delta By how many ticks has the timetable duration changed
|
||||
*/
|
||||
void UpdateOrderTimetable(int delta) { this->timetable_duration += delta; }
|
||||
|
||||
/**
|
||||
* Must be called if the whole timetable is cleared to update internal book keeping.
|
||||
*/
|
||||
void ResetOrderTimetable() { this->timetable_duration = 0; }
|
||||
|
||||
/**
|
||||
* Free a complete order chain.
|
||||
* @param keep_orderlist If this is true only delete the orders, otherwise also delete the OrderList.
|
||||
* @note do not use on "current_order" vehicle orders!
|
||||
*/
|
||||
void FreeChain(bool keep_orderlist = false);
|
||||
|
||||
/**
|
||||
* Checks for internal consistency of order list. Triggers assertion if something is wrong.
|
||||
*/
|
||||
void DebugCheckSanity() const;
|
||||
};
|
||||
|
||||
static inline bool IsValidOrderListID(uint index)
|
||||
{
|
||||
return index < GetOrderListPoolSize() && GetOrderList(index)->IsValid();
|
||||
}
|
||||
|
||||
#define FOR_ALL_ORDERS_FROM(order, start) for (order = GetOrder(start); order != NULL; order = (order->index + 1U < GetOrderPoolSize()) ? GetOrder(order->index + 1U) : NULL) if (order->IsValid())
|
||||
#define FOR_ALL_ORDERS(order) FOR_ALL_ORDERS_FROM(order, 0)
|
||||
|
||||
|
||||
#define FOR_VEHICLE_ORDERS(v, order) for (order = v->orders; order != NULL; order = order->next)
|
||||
#define FOR_VEHICLE_ORDERS(v, order) for (order = (v->orders.list == NULL) ? NULL : v->orders.list->GetFirstOrder(); order != NULL; order = order->next)
|
||||
|
||||
|
||||
#define FOR_ALL_ORDER_LISTS_FROM(ol, start) for (ol = GetOrderList(start); ol != NULL; ol = (ol->index + 1U < GetOrderListPoolSize()) ? GetOrderList(ol->index + 1U) : NULL) if (ol->IsValid())
|
||||
#define FOR_ALL_ORDER_LISTS(ol) FOR_ALL_ORDER_LISTS_FROM(ol, 0)
|
||||
|
||||
/* (Un)pack routines */
|
||||
Order UnpackOldOrder(uint16 packed);
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "openttd.h"
|
||||
#include "debug.h"
|
||||
#include "order_base.h"
|
||||
#include "order_func.h"
|
||||
#include "airport.h"
|
||||
@ -41,6 +42,7 @@ TileIndex _backup_orders_tile;
|
||||
BackuppedOrders _backup_orders_data;
|
||||
|
||||
DEFINE_OLD_POOL_GENERIC(Order, Order);
|
||||
DEFINE_OLD_POOL_GENERIC(OrderList, OrderList);
|
||||
|
||||
void Order::Free()
|
||||
{
|
||||
@ -107,12 +109,6 @@ void Order::SetRefit(CargoID cargo, byte subtype)
|
||||
this->refit_subtype = subtype;
|
||||
}
|
||||
|
||||
void Order::FreeChain()
|
||||
{
|
||||
if (next != NULL) next->FreeChain();
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool Order::Equals(const Order &other) const
|
||||
{
|
||||
/* In case of go to nearest depot orders we need "only" compare the flags
|
||||
@ -247,22 +243,6 @@ void InvalidateVehicleOrder(const Vehicle *v, int data)
|
||||
InvalidateWindow(WC_VEHICLE_TIMETABLE, v->index);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Swap two orders
|
||||
*
|
||||
*/
|
||||
static void SwapOrders(Order *order1, Order *order2)
|
||||
{
|
||||
Order temp_order;
|
||||
|
||||
temp_order = *order1;
|
||||
order1->AssignOrder(*order2);
|
||||
order1->next = order2->next;
|
||||
order2->AssignOrder(temp_order);
|
||||
order2->next = temp_order.next;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Assign data to an order (from an other order)
|
||||
@ -283,6 +263,176 @@ void Order::AssignOrder(const Order &other)
|
||||
}
|
||||
|
||||
|
||||
OrderList::OrderList(Order *chain, Vehicle *v) :
|
||||
first(chain), num_orders(0), num_vehicles(1), first_shared(v),
|
||||
timetable_duration(0)
|
||||
{
|
||||
for (Order *o = this->first; o != NULL; o = o->next) {
|
||||
++this->num_orders;
|
||||
this->timetable_duration += o->wait_time + o->travel_time;
|
||||
}
|
||||
|
||||
for (Vehicle *u = v->PreviousShared(); u != NULL; u = u->PreviousShared()) {
|
||||
++this->num_vehicles;
|
||||
this->first_shared = u;
|
||||
}
|
||||
|
||||
for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles;
|
||||
}
|
||||
|
||||
void OrderList::FreeChain(bool keep_orderlist)
|
||||
{
|
||||
Order *next;
|
||||
for(Order *o = this->first; o != NULL; o = next) {
|
||||
next = o->next;
|
||||
delete o;
|
||||
}
|
||||
|
||||
if (keep_orderlist) {
|
||||
this->first = NULL;
|
||||
this->num_orders = 0;
|
||||
this->timetable_duration = 0;
|
||||
} else {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
Order *OrderList::GetOrderAt(int index) const
|
||||
{
|
||||
if (index < 0) return NULL;
|
||||
|
||||
Order *order = this->first;
|
||||
|
||||
while (order != NULL && index-- > 0)
|
||||
order = order->next;
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
void OrderList::InsertOrderAt(Order *new_order, int index)
|
||||
{
|
||||
if (this->first == NULL) {
|
||||
this->first = new_order;
|
||||
} else {
|
||||
if (index == 0) {
|
||||
/* Insert as first or only order */
|
||||
new_order->next = this->first;
|
||||
this->first = new_order;
|
||||
} else if (index >= this->num_orders) {
|
||||
/* index is after the last order, add it to the end */
|
||||
this->GetLastOrder()->next = new_order;
|
||||
} else {
|
||||
/* Put the new order in between */
|
||||
Order *order = this->GetOrderAt(index - 1);
|
||||
new_order->next = order->next;
|
||||
order->next = new_order;
|
||||
}
|
||||
}
|
||||
++this->num_orders;
|
||||
this->timetable_duration += new_order->wait_time + new_order->travel_time;
|
||||
}
|
||||
|
||||
|
||||
void OrderList::DeleteOrderAt(int index)
|
||||
{
|
||||
if (index >= this->num_orders) return;
|
||||
|
||||
Order *to_remove;
|
||||
|
||||
if (index == 0) {
|
||||
to_remove = this->first;
|
||||
this->first = to_remove->next;
|
||||
} else {
|
||||
Order *prev = GetOrderAt(index - 1);
|
||||
to_remove = prev->next;
|
||||
prev->next = to_remove->next;
|
||||
}
|
||||
--this->num_orders;
|
||||
this->timetable_duration -= (to_remove->wait_time + to_remove->travel_time);
|
||||
delete to_remove;
|
||||
}
|
||||
|
||||
void OrderList::MoveOrder(int from, int to)
|
||||
{
|
||||
if (from >= this->num_orders || to >= this->num_orders || from == to) return;
|
||||
|
||||
Order *moving_one;
|
||||
|
||||
/* Take the moving order out of the pointer-chain */
|
||||
if (from == 0) {
|
||||
moving_one = this->first;
|
||||
this->first = moving_one->next;
|
||||
} else {
|
||||
Order *one_before = GetOrderAt(from - 1);
|
||||
moving_one = one_before->next;
|
||||
one_before->next = moving_one->next;
|
||||
}
|
||||
|
||||
/* Insert the moving_order again in the pointer-chain */
|
||||
if (to == 0) {
|
||||
moving_one->next = this->first;
|
||||
this->first = moving_one;
|
||||
} else {
|
||||
Order *one_before = GetOrderAt(to - 1);
|
||||
moving_one->next = one_before->next;
|
||||
one_before->next = moving_one;
|
||||
}
|
||||
}
|
||||
|
||||
void OrderList::RemoveVehicle(Vehicle *v)
|
||||
{
|
||||
--this->num_vehicles;
|
||||
if (v == this->first_shared) this->first_shared = v->NextShared();
|
||||
}
|
||||
|
||||
bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const
|
||||
{
|
||||
for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) {
|
||||
if (v_shared == v) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const
|
||||
{
|
||||
int count = 0;
|
||||
for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
bool OrderList::IsCompleteTimetable() const
|
||||
{
|
||||
for (Order *o = this->first; o != NULL; o = o->next) {
|
||||
if (!o->IsCompletelyTimetabled()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OrderList::DebugCheckSanity() const
|
||||
{
|
||||
VehicleOrderID check_num_orders = 0;
|
||||
unsigned check_num_vehicles = 0;
|
||||
unsigned check_timetable_duration = 0;
|
||||
|
||||
DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
|
||||
|
||||
for (const Order *o = this->first; o != NULL; o = o->next) {
|
||||
++check_num_orders;
|
||||
check_timetable_duration += o->wait_time + o->travel_time;
|
||||
}
|
||||
assert(this->num_orders == check_num_orders);
|
||||
assert(this->timetable_duration == check_timetable_duration);
|
||||
|
||||
for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) {
|
||||
++check_num_vehicles;
|
||||
assert(v->orders.list == this);
|
||||
}
|
||||
assert(this->num_vehicles == check_num_vehicles);
|
||||
DEBUG(misc, 6, "... detected %u orders, %u vehicles, %u ticks", (unsigned)this->num_orders,
|
||||
this->num_vehicles, this->timetable_duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all news items regarding defective orders about a vehicle
|
||||
* This could kill still valid warnings (for example about void order when just
|
||||
@ -315,7 +465,7 @@ static uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle
|
||||
conditional_depth++;
|
||||
|
||||
int dist1 = GetOrderDistance(prev, GetVehicleOrder(v, cur->GetConditionSkipToOrder()), v, conditional_depth);
|
||||
int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders : cur->next, v, conditional_depth);
|
||||
int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
|
||||
return max(dist1, dist2);
|
||||
}
|
||||
|
||||
@ -495,6 +645,7 @@ CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, c
|
||||
if (sel_ord > v->GetNumOrders()) return CMD_ERROR;
|
||||
|
||||
if (!Order::CanAllocateItem()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
|
||||
if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
|
||||
|
||||
if (v->type == VEH_SHIP && IsHumanCompany(v->owner) && _settings_game.pf.pathfinder_for_ships != VPF_NPF) {
|
||||
/* Make sure the new destination is not too far away from the previous */
|
||||
@ -504,7 +655,8 @@ CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, c
|
||||
/* Find the last goto station or depot order before the insert location.
|
||||
* If the order is to be inserted at the beginning of the order list this
|
||||
* finds the last order in the list. */
|
||||
for (const Order *o = v->orders; o != NULL; o = o->next) {
|
||||
const Order *o;
|
||||
FOR_VEHICLE_ORDERS(v, o) {
|
||||
if (o->IsType(OT_GOTO_STATION) || o->IsType(OT_GOTO_DEPOT)) prev = o;
|
||||
if (++n == sel_ord && prev != NULL) break;
|
||||
}
|
||||
@ -521,42 +673,16 @@ CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, c
|
||||
new_o->AssignOrder(new_order);
|
||||
|
||||
/* Create new order and link in list */
|
||||
if (v->orders == NULL) {
|
||||
v->orders = new_o;
|
||||
if (v->orders.list == NULL) {
|
||||
v->orders.list = new OrderList(new_o, v);
|
||||
} else {
|
||||
/* Try to get the previous item (we are inserting above the
|
||||
selected) */
|
||||
Order *order = GetVehicleOrder(v, sel_ord - 1);
|
||||
|
||||
if (order == NULL && GetVehicleOrder(v, sel_ord) != 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_o);
|
||||
/* Now update the next pointers */
|
||||
v->orders->next = new_o;
|
||||
} else if (order == NULL) {
|
||||
/* 'sel' is a non-existing order, add him to the end */
|
||||
order = GetLastVehicleOrder(v);
|
||||
order->next = new_o;
|
||||
} else {
|
||||
/* Put the new order in between */
|
||||
new_o->next = order->next;
|
||||
order->next = new_o;
|
||||
}
|
||||
v->orders.list->InsertOrderAt(new_o, sel_ord);
|
||||
}
|
||||
|
||||
Vehicle *u = v->FirstShared();
|
||||
DeleteOrderWarnings(u);
|
||||
for (; u != NULL; u = u->NextShared()) {
|
||||
/* Increase amount of orders */
|
||||
u->num_orders++;
|
||||
|
||||
/* If the orderlist was empty, assign it */
|
||||
if (u->orders == NULL) u->orders = v->orders;
|
||||
|
||||
assert(v->orders == u->orders);
|
||||
assert(v->orders.list == u->orders.list);
|
||||
|
||||
/* If there is added an order before the current one, we need
|
||||
to update the selected order */
|
||||
@ -634,37 +760,15 @@ CommandCost CmdDeleteOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, c
|
||||
if (order == NULL) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
if (GetVehicleOrder(v, sel_ord - 1) == NULL) {
|
||||
if (GetVehicleOrder(v, sel_ord + 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_ord + 1);
|
||||
SwapOrders(v->orders, order);
|
||||
} else {
|
||||
/* Last item, so clean the list */
|
||||
v->orders = NULL;
|
||||
}
|
||||
} else {
|
||||
GetVehicleOrder(v, sel_ord - 1)->next = order->next;
|
||||
}
|
||||
|
||||
/* Give the item free */
|
||||
delete order;
|
||||
v->orders.list->DeleteOrderAt(sel_ord);
|
||||
|
||||
Vehicle *u = v->FirstShared();
|
||||
DeleteOrderWarnings(u);
|
||||
for (; u != NULL; u = u->NextShared()) {
|
||||
u->num_orders--;
|
||||
|
||||
if (sel_ord < 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);
|
||||
assert(v->orders.list == u->orders.list);
|
||||
|
||||
/* NON-stop flag is misused to see if a train is in a station that is
|
||||
* on his order list or not */
|
||||
@ -764,30 +868,7 @@ CommandCost CmdMoveOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, con
|
||||
if (moving_one == NULL) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
/* Take the moving order out of the pointer-chain */
|
||||
Order *one_before = GetVehicleOrder(v, moving_order - 1);
|
||||
Order *one_past = GetVehicleOrder(v, moving_order + 1);
|
||||
|
||||
if (one_before == NULL) {
|
||||
/* First order edit */
|
||||
v->orders = moving_one->next;
|
||||
} else {
|
||||
one_before->next = moving_one->next;
|
||||
}
|
||||
|
||||
/* Insert the moving_order again in the pointer-chain */
|
||||
one_before = GetVehicleOrder(v, target_order - 1);
|
||||
one_past = GetVehicleOrder(v, target_order);
|
||||
|
||||
moving_one->next = one_past;
|
||||
|
||||
if (one_before == NULL) {
|
||||
/* first order edit */
|
||||
SwapOrders(v->orders, moving_one);
|
||||
v->orders->next = moving_one;
|
||||
} else {
|
||||
one_before->next = moving_one;
|
||||
}
|
||||
v->orders.list->MoveOrder(moving_order, target_order);
|
||||
|
||||
/* Update shared list */
|
||||
Vehicle *u = v->FirstShared();
|
||||
@ -795,9 +876,6 @@ CommandCost CmdMoveOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, con
|
||||
DeleteOrderWarnings(u);
|
||||
|
||||
for (; u != NULL; u = u->NextShared()) {
|
||||
/* Update the first order */
|
||||
if (u->orders != v->orders) u->orders = v->orders;
|
||||
|
||||
/* Update the current order */
|
||||
if (u->cur_order_index == moving_order) {
|
||||
u->cur_order_index = target_order;
|
||||
@ -807,7 +885,7 @@ CommandCost CmdMoveOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, con
|
||||
u->cur_order_index++;
|
||||
}
|
||||
|
||||
assert(v->orders == u->orders);
|
||||
assert(v->orders.list == u->orders.list);
|
||||
/* Update any possible open window of the vehicle */
|
||||
InvalidateVehicleOrder(u, moving_order | (target_order << 8));
|
||||
}
|
||||
@ -1101,8 +1179,7 @@ CommandCost CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, co
|
||||
/* If the destination vehicle had a OrderList, destroy it */
|
||||
DeleteVehicleOrders(dst);
|
||||
|
||||
dst->orders = src->orders;
|
||||
dst->num_orders = src->GetNumOrders();
|
||||
dst->orders.list = src->orders.list;
|
||||
|
||||
/* Link this vehicle in the shared-list */
|
||||
dst->AddToShared(src);
|
||||
@ -1148,25 +1225,30 @@ CommandCost CmdCloneOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2, co
|
||||
|
||||
/* make sure there are orders available */
|
||||
delta = dst->IsOrderListShared() ? src->GetNumOrders() + 1 : src->GetNumOrders() - dst->GetNumOrders();
|
||||
if (!Order::CanAllocateItem(delta)) {
|
||||
if (!Order::CanAllocateItem(delta) ||
|
||||
((dst->orders.list == NULL || dst->IsOrderListShared()) && !OrderList::CanAllocateItem())) {
|
||||
return_cmd_error(STR_8831_NO_MORE_SPACE_FOR_ORDERS);
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
const Order *order;
|
||||
Order *first = NULL;
|
||||
Order **order_dst;
|
||||
|
||||
/* If the destination vehicle had a OrderList, destroy it */
|
||||
DeleteVehicleOrders(dst);
|
||||
/* If the destination vehicle had an order list, destroy the chain but keep the OrderList */
|
||||
DeleteVehicleOrders(dst, true);
|
||||
|
||||
order_dst = &dst->orders;
|
||||
order_dst = &first;
|
||||
FOR_VEHICLE_ORDERS(src, order) {
|
||||
*order_dst = new Order();
|
||||
(*order_dst)->AssignOrder(*order);
|
||||
order_dst = &(*order_dst)->next;
|
||||
}
|
||||
|
||||
dst->num_orders = src->GetNumOrders();
|
||||
if (dst->orders.list == NULL) dst->orders.list = new OrderList(first, dst);
|
||||
else {
|
||||
assert(dst->orders.list->GetFirstOrder() == NULL);
|
||||
new (dst->orders.list) OrderList(first, dst);
|
||||
}
|
||||
|
||||
InvalidateVehicleOrder(dst, -1);
|
||||
|
||||
@ -1435,7 +1517,7 @@ void CheckOrders(const Vehicle* v)
|
||||
if (v->GetNumOrders() > 1) {
|
||||
const Order* last = GetLastVehicleOrder(v);
|
||||
|
||||
if (v->orders->Equals(*last)) {
|
||||
if (v->orders.list->GetFirstOrder()->Equals(*last)) {
|
||||
problem_type = 2;
|
||||
}
|
||||
}
|
||||
@ -1443,6 +1525,11 @@ void CheckOrders(const Vehicle* v)
|
||||
/* Do we only have 1 station in our order list? */
|
||||
if (n_st < 2 && problem_type == -1) problem_type = 0;
|
||||
|
||||
assert(v->orders.list); // otherwise the check for v->FirstShared() != v would have been true
|
||||
#ifndef NDEBUG
|
||||
v->orders.list->DebugCheckSanity();
|
||||
#endif
|
||||
|
||||
/* We don't have a problem */
|
||||
if (problem_type < 0) return;
|
||||
|
||||
@ -1530,20 +1617,19 @@ bool VehicleHasDepotOrders(const Vehicle *v)
|
||||
* Delete all orders from a vehicle
|
||||
*
|
||||
*/
|
||||
void DeleteVehicleOrders(Vehicle *v)
|
||||
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist)
|
||||
{
|
||||
DeleteOrderWarnings(v);
|
||||
|
||||
if (v->IsOrderListShared()) {
|
||||
/* Remove ourself from the shared order list. */
|
||||
v->RemoveFromShared();
|
||||
} else if (v->orders != NULL) {
|
||||
v->orders.list = NULL;
|
||||
} else if (v->orders.list != NULL) {
|
||||
/* Remove the orders */
|
||||
v->orders->FreeChain();
|
||||
v->orders.list->FreeChain(keep_orderlist);
|
||||
if (!keep_orderlist) v->orders.list = NULL;
|
||||
}
|
||||
|
||||
v->orders = NULL;
|
||||
v->num_orders = 0;
|
||||
}
|
||||
|
||||
Date GetServiceIntervalClamped(uint index)
|
||||
@ -1807,6 +1893,9 @@ void InitializeOrders()
|
||||
_Order_pool.CleanPool();
|
||||
_Order_pool.AddBlockToPool();
|
||||
|
||||
_OrderList_pool.CleanPool();
|
||||
_OrderList_pool.AddBlockToPool();
|
||||
|
||||
_backup_orders_tile = 0;
|
||||
}
|
||||
|
||||
@ -1892,6 +1981,35 @@ static void Load_ORDR()
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler _order_chunk_handlers[] = {
|
||||
{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY | CH_LAST},
|
||||
const SaveLoad *GetOrderListDescription() {
|
||||
static const SaveLoad _orderlist_desc[] = {
|
||||
SLE_REF(OrderList, first, REF_ORDER),
|
||||
SLE_END()
|
||||
};
|
||||
return _orderlist_desc;
|
||||
}
|
||||
|
||||
static void Save_ORDL()
|
||||
{
|
||||
OrderList *list;
|
||||
|
||||
FOR_ALL_ORDER_LISTS(list) {
|
||||
SlSetArrayIndex(list->index);
|
||||
SlObject(list, GetOrderListDescription());
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_ORDL()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
OrderList *list = new (index) OrderList();
|
||||
SlObject(list, GetOrderListDescription());
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler _order_chunk_handlers[] = {
|
||||
{ 'ORDR', Save_ORDR, Load_ORDR, CH_ARRAY},
|
||||
{ 'ORDL', Save_ORDL, Load_ORDL, CH_ARRAY | CH_LAST},
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination);
|
||||
void InvalidateVehicleOrder(const Vehicle *v, int data);
|
||||
bool VehicleHasDepotOrders(const Vehicle *v);
|
||||
void CheckOrders(const Vehicle*);
|
||||
void DeleteVehicleOrders(Vehicle *v);
|
||||
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist = false);
|
||||
bool ProcessOrders(Vehicle *v);
|
||||
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth = 0);
|
||||
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v);
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
typedef byte VehicleOrderID; ///< The index of an order within its current vehicle (not pool related)
|
||||
typedef uint16 OrderID;
|
||||
typedef uint16 OrderListID;
|
||||
typedef uint16 DestinationID;
|
||||
|
||||
enum {
|
||||
@ -149,5 +150,6 @@ enum {
|
||||
};
|
||||
|
||||
struct Order;
|
||||
struct OrderList;
|
||||
|
||||
#endif /* ORDER_TYPE_H */
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
extern const uint16 SAVEGAME_VERSION = 104;
|
||||
extern const uint16 SAVEGAME_VERSION = 105;
|
||||
|
||||
SavegameType _savegame_type; ///< type of savegame we are loading
|
||||
|
||||
@ -1367,6 +1367,7 @@ static uint ReferenceToInt(const void *obj, SLRefType rt)
|
||||
case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
|
||||
case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
|
||||
case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
|
||||
case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
@ -1399,6 +1400,10 @@ static void *IntToReference(uint index, SLRefType rt)
|
||||
index--; // correct for the NULL index
|
||||
|
||||
switch (rt) {
|
||||
case REF_ORDERLIST:
|
||||
if (_OrderList_pool.AddBlockIfNeeded(index)) return GetOrderList(index);
|
||||
error("Orders: failed loading savegame: too many order lists");
|
||||
|
||||
case REF_ORDER:
|
||||
if (_Order_pool.AddBlockIfNeeded(index)) return GetOrder(index);
|
||||
error("Orders: failed loading savegame: too many orders");
|
||||
|
@ -66,6 +66,7 @@ enum SLRefType {
|
||||
REF_ROADSTOPS = 5,
|
||||
REF_ENGINE_RENEWS = 6,
|
||||
REF_CARGO_PACKET = 7,
|
||||
REF_ORDERLIST = 8,
|
||||
};
|
||||
|
||||
#define SL_MAX_VERSION 255
|
||||
|
@ -17,12 +17,16 @@
|
||||
static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 time, bool is_journey)
|
||||
{
|
||||
Order *order = GetVehicleOrder(v, order_number);
|
||||
int delta;
|
||||
|
||||
if (is_journey) {
|
||||
delta = time - order->travel_time;
|
||||
order->travel_time = time;
|
||||
} else {
|
||||
delta = time - order->wait_time;
|
||||
order->wait_time = time;
|
||||
}
|
||||
v->orders.list->UpdateOrderTimetable(delta);
|
||||
|
||||
for (v = v->FirstShared(); v != NULL; v = v->NextShared()) {
|
||||
if (v->cur_order_index == order_number && v->current_order.Equals(*order)) {
|
||||
|
@ -1274,8 +1274,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p
|
||||
if (!IsFrontEngine(src)) {
|
||||
/* setting the type to 0 also involves setting up the orders field. */
|
||||
SetFrontEngine(src);
|
||||
assert(src->orders == NULL);
|
||||
src->num_orders = 0;
|
||||
assert(src->orders.list == NULL);
|
||||
|
||||
/* Decrease the engines number of the src engine_type */
|
||||
if (!IsDefaultGroupID(src->group_id) && IsValidGroupID(src->group_id)) {
|
||||
@ -1453,8 +1452,7 @@ CommandCost CmdSellRailWagon(TileIndex tile, uint32 flags, uint32 p1, uint32 p2,
|
||||
first->group_id = DEFAULT_GROUP;
|
||||
|
||||
/* Copy orders (by sharing) */
|
||||
new_f->orders = first->orders;
|
||||
new_f->num_orders = first->GetNumOrders();
|
||||
new_f->orders.list = first->orders.list;
|
||||
new_f->AddToShared(first);
|
||||
DeleteVehicleOrders(first);
|
||||
|
||||
|
110
src/vehicle.cpp
110
src/vehicle.cpp
@ -59,6 +59,8 @@
|
||||
#include "table/sprites.h"
|
||||
#include "table/strings.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#define INVALID_COORD (0x7fffffff)
|
||||
#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
|
||||
|
||||
@ -221,7 +223,7 @@ void VehiclePositionChanged(Vehicle *v)
|
||||
}
|
||||
|
||||
/** Called after load to update coordinates */
|
||||
void AfterLoadVehicles(bool clear_te_id)
|
||||
void AfterLoadVehicles(bool part_of_load)
|
||||
{
|
||||
Vehicle *v;
|
||||
|
||||
@ -232,7 +234,7 @@ void AfterLoadVehicles(bool clear_te_id)
|
||||
|
||||
v->UpdateDeltaXY(v->direction);
|
||||
|
||||
if (clear_te_id) v->fill_percent_te_id = INVALID_TE_ID;
|
||||
if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
|
||||
v->first = NULL;
|
||||
if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
|
||||
if (v->type == VEH_ROAD) v->u.road.first_engine = INVALID_ENGINE;
|
||||
@ -240,19 +242,45 @@ void AfterLoadVehicles(bool clear_te_id)
|
||||
v->cargo.InvalidateCache();
|
||||
}
|
||||
|
||||
/* AfterLoadVehicles may also be called in case of NewGRF reload, in this
|
||||
* case we may not convert orders again. */
|
||||
if (part_of_load) {
|
||||
/* Create shared vehicle chain for very old games (pre 5,2) and create
|
||||
* OrderList from shared vehicle chains. For this to work correctly, the
|
||||
* following conditions must be fulfilled:
|
||||
* a) both next_shared and previous_shared are not set for pre 5,2 games
|
||||
* b) both next_shared and previous_shared are set for later games
|
||||
*/
|
||||
std::map<Order*, OrderList*> mapping;
|
||||
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (v->orders.old != NULL) {
|
||||
if (CheckSavegameVersion(105)) { // Pre-105 didn't save an OrderList
|
||||
if (mapping[v->orders.old] == NULL) {
|
||||
/* This adds the whole shared vehicle chain for case b */
|
||||
v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v);
|
||||
} else {
|
||||
v->orders.list = mapping[v->orders.old];
|
||||
/* For old games (case a) we must create the shared vehicle chain */
|
||||
if (CheckSavegameVersionOldStyle(5, 2)) {
|
||||
v->AddToShared(v->orders.list->GetFirstSharedVehicle());
|
||||
}
|
||||
}
|
||||
} else { // OrderList was saved as such, only recalculate not saved values
|
||||
if (v->PreviousShared() == NULL) {
|
||||
new (v->orders.list) OrderList(v->orders.list->GetFirstOrder(), v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
/* Fill the first pointers */
|
||||
if (v->Previous() == NULL) {
|
||||
for (Vehicle *u = v; u != NULL; u = u->Next()) {
|
||||
u->first = v;
|
||||
}
|
||||
|
||||
/* Shared orders are only valid for first vehicles in chains. */
|
||||
if (v->previous_shared == NULL) {
|
||||
for (Vehicle *u = v; u != NULL; u = u->NextShared()) {
|
||||
u->first_shared = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -315,7 +343,6 @@ Vehicle::Vehicle()
|
||||
this->group_id = DEFAULT_GROUP;
|
||||
this->fill_percent_te_id = INVALID_TE_ID;
|
||||
this->first = this;
|
||||
this->first_shared = this;
|
||||
this->colormap = PAL_NONE;
|
||||
}
|
||||
|
||||
@ -2168,7 +2195,8 @@ static const SaveLoad _common_veh_desc[] = {
|
||||
SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, 88, SL_MAX_VERSION),
|
||||
|
||||
SLE_VAR(Vehicle, cur_order_index, SLE_UINT8),
|
||||
SLE_VAR(Vehicle, num_orders, SLE_UINT8),
|
||||
/* num_orders is now part of OrderList and is not saved but counted */
|
||||
SLE_CONDNULL(1, 0, 104),
|
||||
|
||||
/* This next line is for version 4 and prior compatibility.. it temporarily reads
|
||||
type and flags (which were both 4 bits) into type. Later on this is
|
||||
@ -2189,7 +2217,8 @@ static const SaveLoad _common_veh_desc[] = {
|
||||
SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, wait_time), SLE_UINT16, 67, SL_MAX_VERSION),
|
||||
SLE_CONDVARX(cpp_offsetof(Vehicle, current_order) + cpp_offsetof(Order, travel_time), SLE_UINT16, 67, SL_MAX_VERSION),
|
||||
|
||||
SLE_REF(Vehicle, orders, REF_ORDER),
|
||||
SLE_CONDREF(Vehicle, orders, REF_ORDER, 0, 104),
|
||||
SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, 105, SL_MAX_VERSION),
|
||||
|
||||
SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30),
|
||||
SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION),
|
||||
@ -2409,7 +2438,6 @@ void Load_VEHS()
|
||||
_vehicles_to_autoreplace.Reset();
|
||||
|
||||
int index;
|
||||
Vehicle *v;
|
||||
|
||||
_cargo_count = 0;
|
||||
|
||||
@ -2456,22 +2484,6 @@ void Load_VEHS()
|
||||
/* Advanced vehicle lists got added */
|
||||
if (CheckSavegameVersion(60)) v->group_id = DEFAULT_GROUP;
|
||||
}
|
||||
|
||||
/* Check for shared order-lists (we now use pointers for that) */
|
||||
if (CheckSavegameVersionOldStyle(5, 2)) {
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
Vehicle *u;
|
||||
|
||||
FOR_ALL_VEHICLES_FROM(u, v->index + 1) {
|
||||
/* If a vehicle has the same orders, add the link to eachother
|
||||
* in both vehicles */
|
||||
if (v->orders == u->orders) {
|
||||
u->AddToShared(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler _veh_chunk_handlers[] = {
|
||||
@ -2651,47 +2663,51 @@ void Vehicle::SetNext(Vehicle *next)
|
||||
|
||||
void Vehicle::AddToShared(Vehicle *shared_chain)
|
||||
{
|
||||
assert(!this->IsOrderListShared());
|
||||
assert(this->previous_shared == NULL && this->next_shared == NULL);
|
||||
|
||||
if (!shared_chain->orders.list) {
|
||||
assert(shared_chain->previous_shared == NULL);
|
||||
assert(shared_chain->next_shared == NULL);
|
||||
this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain);
|
||||
}
|
||||
|
||||
this->next_shared = shared_chain->next_shared;
|
||||
this->previous_shared = shared_chain;
|
||||
this->first_shared = shared_chain->first_shared;
|
||||
|
||||
shared_chain->next_shared = this;
|
||||
|
||||
if (this->next_shared != NULL) this->next_shared->previous_shared = this;
|
||||
|
||||
shared_chain->orders.list->AddVehicle(this);
|
||||
}
|
||||
|
||||
void Vehicle::RemoveFromShared()
|
||||
{
|
||||
Vehicle *new_first;
|
||||
/* Remember if we were first and the old window number before RemoveVehicle()
|
||||
* as this changes first if needed. */
|
||||
bool were_first = (this->FirstShared() == this);
|
||||
uint32 old_window_number = (this->FirstShared()->index << 16) | (this->type << 11) | VLW_SHARED_ORDERS | this->owner;
|
||||
|
||||
if (this->FirstShared() == this) {
|
||||
/* We are the first shared one, so update all the first pointers of our next shared ones. */
|
||||
new_first = this->NextShared();
|
||||
for (Vehicle *u = new_first; u != NULL; u = u->NextShared()) {
|
||||
u->first_shared = new_first;
|
||||
}
|
||||
} else {
|
||||
this->orders.list->RemoveVehicle(this);
|
||||
|
||||
if (!were_first) {
|
||||
/* We are not the first shared one, so only relink our previous one. */
|
||||
new_first = this->FirstShared();
|
||||
this->previous_shared->next_shared = this->NextShared();
|
||||
}
|
||||
|
||||
if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared;
|
||||
|
||||
uint32 old_window_number = (this->FirstShared()->index << 16) | (this->type << 11) | VLW_SHARED_ORDERS | this->owner;
|
||||
|
||||
if (new_first->NextShared() == NULL) {
|
||||
if (this->orders.list->GetNumVehicles() == 1) {
|
||||
/* When there is only one vehicle, remove the shared order list window. */
|
||||
DeleteWindowById(GetWindowClassForVehicleType(this->type), old_window_number);
|
||||
InvalidateVehicleOrder(new_first, 0);
|
||||
} else if (this->FirstShared() == this) {
|
||||
/* If we were the first one, update to the new first one. */
|
||||
InvalidateWindowData(GetWindowClassForVehicleType(this->type), old_window_number, (new_first->index << 16) | (1 << 15));
|
||||
InvalidateVehicleOrder(this->FirstShared(), 0);
|
||||
} else if (were_first) {
|
||||
/* If we were the first one, update to the new first one.
|
||||
* Note: FirstShared() is already the new first */
|
||||
InvalidateWindowData(GetWindowClassForVehicleType(this->type), old_window_number, (this->FirstShared()->index << 16) | (1 << 15));
|
||||
}
|
||||
|
||||
this->first_shared = this;
|
||||
this->next_shared = NULL;
|
||||
this->previous_shared = NULL;
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ DECLARE_OLD_POOL(Vehicle, Vehicle, 9, 125)
|
||||
/* Some declarations of functions, so we can make them friendly */
|
||||
struct SaveLoad;
|
||||
extern const SaveLoad *GetVehicleDescription(VehicleType vt);
|
||||
extern void AfterLoadVehicles(bool clear_te_id);
|
||||
extern void AfterLoadVehicles(bool part_of_load);
|
||||
struct LoadgameState;
|
||||
extern bool LoadOldVehicle(LoadgameState *ls, int num);
|
||||
|
||||
@ -206,10 +206,9 @@ private:
|
||||
|
||||
Vehicle *next_shared; ///< pointer to the next vehicle that shares the order
|
||||
Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain
|
||||
Vehicle *first_shared; ///< NOSAVE: pointer to the first vehicle in the shared order chain
|
||||
public:
|
||||
friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code
|
||||
friend void AfterLoadVehicles(bool clear_te_id); ///< So we can set the previous and first pointers while loading
|
||||
friend void AfterLoadVehicles(bool part_of_load); ///< So we can set the previous and first pointers while loading
|
||||
friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading
|
||||
|
||||
char *name; ///< Name of vehicle
|
||||
@ -302,10 +301,12 @@ public:
|
||||
|
||||
byte vehstatus; ///< Status
|
||||
Order current_order; ///< The current order (+ status, like: loading)
|
||||
VehicleOrderID num_orders; ///< How many orders there are in the list
|
||||
VehicleOrderID cur_order_index; ///< The index to the current order
|
||||
|
||||
Order *orders; ///< Pointer to the first order for this vehicle
|
||||
union {
|
||||
OrderList *list; ///< Pointer to the order list for this vehicle
|
||||
Order *old; ///< Only used during conversion of old save games
|
||||
} orders;
|
||||
|
||||
byte vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
|
||||
uint16 load_unload_time_rem;
|
||||
@ -481,6 +482,12 @@ public:
|
||||
inline Vehicle *First() const { return this->first; }
|
||||
|
||||
|
||||
/**
|
||||
* Get the first order of the vehicles order list.
|
||||
* @return first order of order list.
|
||||
*/
|
||||
inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
|
||||
|
||||
/**
|
||||
* Adds this vehicle to a shared vehicle chain.
|
||||
* @param shared_chain a vehicle of the chain with shared vehicles.
|
||||
@ -494,29 +501,34 @@ public:
|
||||
void RemoveFromShared();
|
||||
|
||||
/**
|
||||
* Get the next vehicle of this vehicle.
|
||||
* @note articulated parts are also counted as vehicles.
|
||||
* @return the next vehicle or NULL when there isn't a next vehicle.
|
||||
* Get the next vehicle of the shared vehicle chain.
|
||||
* @return the next shared vehicle or NULL when there isn't a next vehicle.
|
||||
*/
|
||||
inline Vehicle *NextShared() const { return this->next_shared; }
|
||||
|
||||
/**
|
||||
* Get the previous vehicle of the shared vehicle chain
|
||||
* @return the previous shared vehicle or NULL when there isn't a previous vehicle.
|
||||
*/
|
||||
inline Vehicle *PreviousShared() const { return this->previous_shared; }
|
||||
|
||||
/**
|
||||
* Get the first vehicle of this vehicle chain.
|
||||
* @return the first vehicle of the chain.
|
||||
*/
|
||||
inline Vehicle *FirstShared() const { return this->first_shared; }
|
||||
inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstSharedVehicle(); }
|
||||
|
||||
/**
|
||||
* Check if we share our orders with another vehicle.
|
||||
* @return true if there are other vehicles sharing the same order
|
||||
*/
|
||||
inline bool IsOrderListShared() const { return this->previous_shared != NULL || this->next_shared != NULL; };
|
||||
inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
|
||||
|
||||
/**
|
||||
* Get the number of orders this vehicle has.
|
||||
* @return the number of orders this vehicle has.
|
||||
*/
|
||||
inline VehicleOrderID GetNumOrders() const { return this->num_orders; }
|
||||
inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
|
||||
|
||||
/**
|
||||
* Copy certain configurations and statistics of a vehicle after successful autoreplace/renew
|
||||
@ -676,34 +688,14 @@ struct FreeUnitIDGenerator {
|
||||
};
|
||||
|
||||
/* 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;
|
||||
}
|
||||
static inline Order *GetVehicleOrder(const Vehicle *v, int index) { return (v->orders.list == NULL) ? NULL : v->orders.list->GetOrderAt(index); }
|
||||
|
||||
/**
|
||||
* Returns the last order of a vehicle, or NULL if it doesn't exists
|
||||
* @param v Vehicle to query
|
||||
* @return last order of a vehicle, if available
|
||||
*/
|
||||
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;
|
||||
}
|
||||
static inline Order *GetLastVehicleOrder(const Vehicle *v) { return (v->orders.list == NULL) ? NULL : v->orders.list->GetLastOrder(); }
|
||||
|
||||
/**
|
||||
* Returns the Trackdir on which the vehicle is currently located.
|
||||
|
Loading…
Reference in New Issue
Block a user