summaryrefslogtreecommitdiff
path: root/order.h
blob: 08bbc752985c767d5a904169c8a02c4026d5b54c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/* $Id$ */

/** @file order.h
  */

#ifndef ORDER_H
#define ORDER_H

#include "macros.h"
#include "pool.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 */

/** Order flag masks - these are for direct bit operations */
enum OrderFlagMasks {
	//Flags for stations:
	/** vehicle will transfer cargo (i. e. not deliver to nearby industry/town even if accepted there) */
	OF_TRANSFER           = 0x1,
	/** If OF_TRANSFER is not set, drop any cargo loaded. If accepted, deliver, otherwise cargo remains at the station.
      * No new cargo is loaded onto the vehicle whatsoever */
	OF_UNLOAD             = 0x2,
	/** Wait for full load of all vehicles, or of at least one cargo type, depending on patch setting
	  * @todo make this two different flags */
	OF_FULL_LOAD          = 0x4,

	//Flags for depots:
	/** The current depot-order was initiated because it was in the vehicle's order list */
	OF_PART_OF_ORDERS	  = 0x2,
	/** if OF_PART_OF_ORDERS is not set, this will cause the vehicle to be stopped in the depot */
	OF_HALT_IN_DEPOT      = 0x4,
	/** if OF_PART_OF_ORDERS is set, this will cause the order only be come active if the vehicle needs servicing */
	OF_SERVICE_IF_NEEDED  = 0x4, //used when OF_PART_OF_ORDERS is set.

	//Common flags
	/** This causes the vehicle not to stop at intermediate OR the destination station (depending on patch settings)
	  * @todo make this two different flags */
	OF_NON_STOP           = 0x8
};

/** Order flags bits - these are for the *BIT macros
  * for descrption of flags, see OrderFlagMasks
  * @see OrderFlagMasks
  */
enum {
	OFB_TRANSFER          = 0,
	OFB_UNLOAD            = 1,
	OFB_FULL_LOAD         = 2,
	OFB_PART_OF_ORDERS    = 1,
	OFB_HALT_IN_DEPOT     = 2,
	OFB_SERVICE_IF_NEEDED = 2,
	OFB_NON_STOP          = 3
};


/* Possible clone options */
enum {
	CO_SHARE   = 0,
	CO_COPY    = 1,
	CO_UNSHARE = 2
};

/* Modes for the order checker */
enum {
	OC_INIT     = 0, //the order checker can initialize a news message
	OC_VALIDATE = 1, //the order checker validates a news message
};

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

#define MAX_BACKUP_ORDER_COUNT 40

typedef struct {
	VehicleID clone;
	OrderID orderindex;
	Order order[MAX_BACKUP_ORDER_COUNT + 1];
	uint16 service_interval;
	char name[32];
} BackuppedOrders;

VARDEF TileIndex _backup_orders_tile;
VARDEF BackuppedOrders _backup_orders_data[1];

extern MemoryPool _order_pool;

/**
 * Get the pointer to the order with index 'index'
 */
static inline Order *GetOrder(uint index)
{
	return (Order*)GetItemFromPool(&_order_pool, index);
}

/**
 * Get the current size of the OrderPool
 */
static inline uint16 GetOrderPoolSize(void)
{
	return _order_pool.total_items;
}

#define FOR_ALL_ORDERS_FROM(order, start) for (order = GetOrder(start); order != NULL; order = (order->index + 1 < GetOrderPoolSize()) ? GetOrder(order->index + 1) : NULL)
#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)

static inline bool HasOrderPoolFree(uint amount)
{
	const Order *order;

	/* There is always room if not all blocks in the pool are reserved */
	if (_order_pool.current_blocks < _order_pool.max_blocks)
		return true;

	FOR_ALL_ORDERS(order)
		if (order->type == OT_NOTHING)
			if (--amount == 0)
				return true;

	return false;
}

static inline bool IsOrderPoolFull(void)
{
	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    = GB(packed,  0,  8);
	order.flags   = GB(packed,  8,  8);
	order.station = GB(packed, 16, 16);
	order.next    = NULL;
	order.index   = 0; // avoid compiler warning
	return order;
}

/* Functions */
void BackupVehicleOrders(const 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(uint data_a, uint data_b);
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 */