36 TileIndex _backup_orders_tile; |
38 TileIndex _backup_orders_tile; |
37 BackuppedOrders _backup_orders_data; |
39 BackuppedOrders _backup_orders_data; |
38 |
40 |
39 DEFINE_OLD_POOL_GENERIC(Order, Order) |
41 DEFINE_OLD_POOL_GENERIC(Order, Order) |
40 |
42 |
|
43 void Order::Free() |
|
44 { |
|
45 this->type = OT_NOTHING; |
|
46 this->flags = 0; |
|
47 this->dest = 0; |
|
48 this->next = NULL; |
|
49 } |
|
50 |
|
51 void Order::MakeGoToStation(StationID destination) |
|
52 { |
|
53 this->type = OT_GOTO_STATION; |
|
54 this->flags = 0; |
|
55 this->dest = destination; |
|
56 } |
|
57 |
|
58 void Order::MakeGoToDepot(DepotID destination, bool order, CargoID cargo, byte subtype) |
|
59 { |
|
60 this->type = OT_GOTO_DEPOT; |
|
61 this->flags = order ? OFB_PART_OF_ORDERS : OFB_NON_STOP; |
|
62 this->dest = destination; |
|
63 this->SetRefit(cargo, subtype); |
|
64 } |
|
65 |
|
66 void Order::MakeGoToWaypoint(WaypointID destination) |
|
67 { |
|
68 this->type = OT_GOTO_WAYPOINT; |
|
69 this->flags = 0; |
|
70 this->dest = destination; |
|
71 } |
|
72 |
|
73 void Order::MakeLoading(bool ordered) |
|
74 { |
|
75 this->type = OT_LOADING; |
|
76 if (!ordered) this->flags = 0; |
|
77 } |
|
78 |
|
79 void Order::MakeLeaveStation() |
|
80 { |
|
81 this->type = OT_LEAVESTATION; |
|
82 this->flags = 0; |
|
83 } |
|
84 |
|
85 void Order::MakeDummy() |
|
86 { |
|
87 this->type = OT_DUMMY; |
|
88 this->flags = 0; |
|
89 } |
|
90 |
|
91 void Order::SetRefit(CargoID cargo, byte subtype) |
|
92 { |
|
93 this->refit_cargo = cargo; |
|
94 this->refit_subtype = subtype; |
|
95 } |
|
96 |
|
97 void Order::FreeChain() |
|
98 { |
|
99 if (next != NULL) next->FreeChain(); |
|
100 delete this; |
|
101 } |
|
102 |
|
103 bool Order::Equals(const Order &other) const |
|
104 { |
|
105 return |
|
106 this->type == other.type && |
|
107 this->flags == other.flags && |
|
108 this->dest == other.dest; |
|
109 } |
|
110 |
|
111 static bool HasOrderPoolFree(uint amount) |
|
112 { |
|
113 const Order *order; |
|
114 |
|
115 /* There is always room if not all blocks in the pool are reserved */ |
|
116 if (_Order_pool.CanAllocateMoreBlocks()) return true; |
|
117 |
|
118 FOR_ALL_ORDERS(order) if (!order->IsValid() && --amount == 0) return true; |
|
119 |
|
120 return false; |
|
121 } |
|
122 |
|
123 uint32 Order::Pack() const |
|
124 { |
|
125 return this->dest << 16 | this->flags << 8 | this->type; |
|
126 } |
|
127 |
|
128 Order::Order(uint32 packed) |
|
129 { |
|
130 this->type = (OrderType)GB(packed, 0, 8); |
|
131 this->flags = GB(packed, 8, 8); |
|
132 this->dest = GB(packed, 16, 16); |
|
133 this->next = NULL; |
|
134 this->index = 0; // avoid compiler warning |
|
135 this->refit_cargo = CT_NO_REFIT; |
|
136 this->refit_subtype = 0; |
|
137 this->wait_time = 0; |
|
138 this->travel_time = 0; |
|
139 } |
|
140 |
|
141 /** |
|
142 * |
|
143 * Unpacks a order from savegames with version 4 and lower |
|
144 * |
|
145 */ |
|
146 static Order UnpackVersion4Order(uint16 packed) |
|
147 { |
|
148 return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4)); |
|
149 } |
|
150 |
41 /** |
151 /** |
42 * |
152 * |
43 * Unpacks a order from savegames made with TTD(Patch) |
153 * Unpacks a order from savegames made with TTD(Patch) |
44 * |
154 * |
45 */ |
155 */ |
46 Order UnpackOldOrder(uint16 packed) |
156 Order UnpackOldOrder(uint16 packed) |
47 { |
157 { |
48 Order order; |
158 Order order = UnpackVersion4Order(packed); |
49 order.type = (OrderType)GB(packed, 0, 4); |
159 |
50 order.flags = GB(packed, 4, 4); |
160 /* |
51 order.dest = GB(packed, 8, 8); |
161 * Sanity check |
52 order.next = NULL; |
162 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station |
53 |
163 */ |
54 order.refit_cargo = CT_NO_REFIT; |
164 if (!order.IsValid() && (order.GetLoadType() != 0 || order.GetUnloadType() != 0 || order.GetDestination() != 0)) { |
55 order.refit_subtype = 0; |
165 order.MakeDummy(); |
56 order.wait_time = 0; |
166 } |
57 order.travel_time = 0; |
167 |
58 order.index = 0; // avoid compiler warning |
|
59 |
|
60 // Sanity check |
|
61 // TTD stores invalid orders as OT_NOTHING with non-zero flags/station |
|
62 if (!order.IsValid() && (order.flags != 0 || order.dest != 0)) { |
|
63 order.type = OT_DUMMY; |
|
64 order.flags = 0; |
|
65 } |
|
66 |
|
67 return order; |
|
68 } |
|
69 |
|
70 /** |
|
71 * |
|
72 * Unpacks a order from savegames with version 4 and lower |
|
73 * |
|
74 */ |
|
75 static Order UnpackVersion4Order(uint16 packed) |
|
76 { |
|
77 Order order; |
|
78 order.type = (OrderType)GB(packed, 0, 4); |
|
79 order.flags = GB(packed, 4, 4); |
|
80 order.dest = GB(packed, 8, 8); |
|
81 order.next = NULL; |
|
82 order.index = 0; // avoid compiler warning |
|
83 order.refit_cargo = CT_NO_REFIT; |
|
84 order.refit_subtype = 0; |
|
85 order.wait_time = 0; |
|
86 order.travel_time = 0; |
|
87 return order; |
168 return order; |
88 } |
169 } |
89 |
170 |
90 /** |
171 /** |
91 * |
172 * |
107 static void SwapOrders(Order *order1, Order *order2) |
188 static void SwapOrders(Order *order1, Order *order2) |
108 { |
189 { |
109 Order temp_order; |
190 Order temp_order; |
110 |
191 |
111 temp_order = *order1; |
192 temp_order = *order1; |
112 AssignOrder(order1, *order2); |
193 order1->AssignOrder(*order2); |
113 order1->next = order2->next; |
194 order1->next = order2->next; |
114 AssignOrder(order2, temp_order); |
195 order2->AssignOrder(temp_order); |
115 order2->next = temp_order.next; |
196 order2->next = temp_order.next; |
116 } |
197 } |
117 |
198 |
118 /** |
199 /** |
119 * |
200 * |
120 * Assign data to an order (from an other order) |
201 * Assign data to an order (from an other order) |
121 * This function makes sure that the index is maintained correctly |
202 * This function makes sure that the index is maintained correctly |
122 * |
203 * |
123 */ |
204 */ |
124 void AssignOrder(Order *order, Order data) |
205 void Order::AssignOrder(const Order &other) |
125 { |
206 { |
126 order->type = data.type; |
207 this->type = other.type; |
127 order->flags = data.flags; |
208 this->flags = other.flags; |
128 order->dest = data.dest; |
209 this->dest = other.dest; |
129 |
210 |
130 order->refit_cargo = data.refit_cargo; |
211 this->refit_cargo = other.refit_cargo; |
131 order->refit_subtype = data.refit_subtype; |
212 this->refit_subtype = other.refit_subtype; |
132 |
213 |
133 order->wait_time = data.wait_time; |
214 this->wait_time = other.wait_time; |
134 order->travel_time = data.travel_time; |
215 this->travel_time = other.travel_time; |
135 } |
216 } |
136 |
217 |
137 |
218 |
138 /** |
219 /** |
139 * Delete all news items regarding defective orders about a vehicle |
220 * Delete all news items regarding defective orders about a vehicle |
173 CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
254 CommandCost CmdInsertOrder(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
174 { |
255 { |
175 Vehicle *v; |
256 Vehicle *v; |
176 VehicleID veh = GB(p1, 0, 16); |
257 VehicleID veh = GB(p1, 0, 16); |
177 VehicleOrderID sel_ord = GB(p1, 16, 16); |
258 VehicleOrderID sel_ord = GB(p1, 16, 16); |
178 Order new_order = UnpackOrder(p2); |
259 Order new_order(p2); |
179 |
260 |
180 if (!IsValidVehicleID(veh)) return CMD_ERROR; |
261 if (!IsValidVehicleID(veh)) return CMD_ERROR; |
181 |
262 |
182 v = GetVehicle(veh); |
263 v = GetVehicle(veh); |
183 |
264 |
184 if (!CheckOwnership(v->owner)) return CMD_ERROR; |
265 if (!CheckOwnership(v->owner)) return CMD_ERROR; |
185 |
266 |
186 /* Check if the inserted order is to the correct destination (owner, type), |
267 /* Check if the inserted order is to the correct destination (owner, type), |
187 * and has the correct flags if any */ |
268 * and has the correct flags if any */ |
188 switch (new_order.type) { |
269 switch (new_order.GetType()) { |
189 case OT_GOTO_STATION: { |
270 case OT_GOTO_STATION: { |
190 const Station *st; |
271 if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR; |
191 |
272 |
192 if (!IsValidStationID(new_order.dest)) return CMD_ERROR; |
273 const Station *st = GetStation(new_order.GetDestination()); |
193 st = GetStation(new_order.dest); |
|
194 |
274 |
195 if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) { |
275 if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) { |
196 return CMD_ERROR; |
276 return CMD_ERROR; |
197 } |
277 } |
198 |
278 |
220 break; |
300 break; |
221 |
301 |
222 default: return CMD_ERROR; |
302 default: return CMD_ERROR; |
223 } |
303 } |
224 |
304 |
|
305 if (new_order.GetNonStopType() != OFB_NO_NON_STOP && v->type != VEH_TRAIN) return CMD_ERROR; |
|
306 |
225 /* Order flags can be any of the following for stations: |
307 /* Order flags can be any of the following for stations: |
226 * [full-load | unload] [+ transfer] [+ non-stop] |
308 * [full-load | unload] [+ transfer] [+ non-stop] |
227 * non-stop orders (if any) are only valid for trains */ |
309 * non-stop orders (if any) are only valid for trains */ |
228 switch (new_order.flags) { |
310 switch (new_order.GetLoadType() | new_order.GetUnloadType()) { |
229 case 0: |
311 case 0: |
230 case OFB_FULL_LOAD: |
312 case OFB_FULL_LOAD: |
231 case OFB_FULL_LOAD | OFB_TRANSFER: |
313 case OFB_FULL_LOAD | OFB_TRANSFER: |
232 case OFB_UNLOAD: |
314 case OFB_UNLOAD: |
233 case OFB_UNLOAD | OFB_TRANSFER: |
315 case OFB_UNLOAD | OFB_TRANSFER: |
234 case OFB_TRANSFER: |
316 case OFB_TRANSFER: |
235 break; |
317 break; |
236 |
318 |
237 case OFB_NON_STOP: |
|
238 case OFB_NON_STOP | OFB_FULL_LOAD: |
|
239 case OFB_NON_STOP | OFB_FULL_LOAD | OFB_TRANSFER: |
|
240 case OFB_NON_STOP | OFB_UNLOAD: |
|
241 case OFB_NON_STOP | OFB_UNLOAD | OFB_TRANSFER: |
|
242 case OFB_NON_STOP | OFB_TRANSFER: |
|
243 if (v->type != VEH_TRAIN) return CMD_ERROR; |
|
244 break; |
|
245 |
|
246 default: return CMD_ERROR; |
319 default: return CMD_ERROR; |
247 } |
320 } |
248 break; |
321 break; |
249 } |
322 } |
250 |
323 |
251 case OT_GOTO_DEPOT: { |
324 case OT_GOTO_DEPOT: { |
252 if (v->type == VEH_AIRCRAFT) { |
325 if (v->type == VEH_AIRCRAFT) { |
253 const Station* st; |
326 if (!IsValidStationID(new_order.GetDestination())) return CMD_ERROR; |
254 |
327 |
255 if (!IsValidStationID(new_order.dest)) return CMD_ERROR; |
328 const Station *st = GetStation(new_order.GetDestination()); |
256 st = GetStation(new_order.dest); |
|
257 |
329 |
258 if (!CheckOwnership(st->owner) || |
330 if (!CheckOwnership(st->owner) || |
259 !(st->facilities & FACIL_AIRPORT) || |
331 !(st->facilities & FACIL_AIRPORT) || |
260 st->Airport()->nof_depots == 0 || |
332 st->Airport()->nof_depots == 0 || |
261 !CanAircraftUseStation(v->engine_type, st)) { |
333 !CanAircraftUseStation(v->engine_type, st)) { |
262 return CMD_ERROR; |
334 return CMD_ERROR; |
263 } |
335 } |
264 } else { |
336 } else { |
265 const Depot* dp; |
337 if (!IsValidDepotID(new_order.GetDestination())) return CMD_ERROR; |
266 |
338 |
267 if (!IsValidDepotID(new_order.dest)) return CMD_ERROR; |
339 const Depot *dp = GetDepot(new_order.GetDestination()); |
268 dp = GetDepot(new_order.dest); |
|
269 |
340 |
270 if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR; |
341 if (!CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR; |
271 |
342 |
272 switch (v->type) { |
343 switch (v->type) { |
273 case VEH_TRAIN: |
344 case VEH_TRAIN: |
284 |
355 |
285 default: return CMD_ERROR; |
356 default: return CMD_ERROR; |
286 } |
357 } |
287 } |
358 } |
288 |
359 |
|
360 if (new_order.GetNonStopType() != OFB_NO_NON_STOP && v->type != VEH_TRAIN) return CMD_ERROR; |
|
361 |
289 /* Order flags can be any of the following for depots: |
362 /* Order flags can be any of the following for depots: |
290 * order [+ halt] [+ non-stop] |
363 * order [+ halt] [+ non-stop] |
291 * non-stop orders (if any) are only valid for trains */ |
364 * non-stop orders (if any) are only valid for trains */ |
292 switch (new_order.flags) { |
365 switch (new_order.GetDepotOrderType() | new_order.GetDepotActionType()) { |
293 case OFB_PART_OF_ORDERS: |
366 case OFB_PART_OF_ORDERS: |
294 case OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT: |
367 case OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT: |
295 break; |
368 break; |
296 |
369 |
297 case OFB_NON_STOP | OFB_PART_OF_ORDERS: |
|
298 case OFB_NON_STOP | OFB_PART_OF_ORDERS | OFB_HALT_IN_DEPOT: |
|
299 if (v->type != VEH_TRAIN) return CMD_ERROR; |
|
300 break; |
|
301 |
|
302 default: return CMD_ERROR; |
370 default: return CMD_ERROR; |
303 } |
371 } |
304 break; |
372 break; |
305 } |
373 } |
306 |
374 |
307 case OT_GOTO_WAYPOINT: { |
375 case OT_GOTO_WAYPOINT: { |
308 const Waypoint* wp; |
|
309 |
376 |
310 if (v->type != VEH_TRAIN) return CMD_ERROR; |
377 if (v->type != VEH_TRAIN) return CMD_ERROR; |
311 |
378 |
312 if (!IsValidWaypointID(new_order.dest)) return CMD_ERROR; |
379 if (!IsValidWaypointID(new_order.GetDestination())) return CMD_ERROR; |
313 wp = GetWaypoint(new_order.dest); |
380 const Waypoint *wp = GetWaypoint(new_order.GetDestination()); |
314 |
381 |
315 if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR; |
382 if (!CheckOwnership(GetTileOwner(wp->xy))) return CMD_ERROR; |
316 |
383 |
317 /* Order flags can be any of the following for waypoints: |
384 /* Order flags can be any of the following for waypoints: |
318 * [non-stop] |
385 * [non-stop] |
319 * non-stop orders (if any) are only valid for trains */ |
386 * non-stop orders (if any) are only valid for trains */ |
320 switch (new_order.flags) { |
387 switch (new_order.GetNonStopType()) { |
321 case 0: break; |
388 case OFB_NO_NON_STOP: break; |
322 |
389 |
323 case OFB_NON_STOP: |
390 case OFB_NON_STOP: |
324 if (v->type != VEH_TRAIN) return CMD_ERROR; |
391 if (v->type != VEH_TRAIN) return CMD_ERROR; |
325 break; |
392 break; |
326 |
393 |
687 |
748 |
688 /* Is it a valid order? */ |
749 /* Is it a valid order? */ |
689 if (sel_ord >= v->num_orders) return CMD_ERROR; |
750 if (sel_ord >= v->num_orders) return CMD_ERROR; |
690 |
751 |
691 order = GetVehicleOrder(v, sel_ord); |
752 order = GetVehicleOrder(v, sel_ord); |
692 if ((order->type != OT_GOTO_STATION || GetStation(order->dest)->IsBuoy()) && |
753 if ((!order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->IsBuoy()) && |
693 (order->type != OT_GOTO_DEPOT || p2 == OF_UNLOAD) && |
754 (!order->IsType(OT_GOTO_DEPOT) || p2 == OF_UNLOAD) && |
694 (order->type != OT_GOTO_WAYPOINT || p2 != OF_NON_STOP)) { |
755 (!order->IsType(OT_GOTO_WAYPOINT) || p2 != OF_NON_STOP)) { |
695 return CMD_ERROR; |
756 return CMD_ERROR; |
696 } |
757 } |
697 |
758 |
698 if (flags & DC_EXEC) { |
759 if (flags & DC_EXEC) { |
699 switch (p2) { |
760 switch (p2) { |
700 case OF_FULL_LOAD: |
761 case OF_FULL_LOAD: |
701 ToggleBit(order->flags, OF_FULL_LOAD); |
762 if (order->IsType(OT_GOTO_DEPOT)) { |
702 if (order->type != OT_GOTO_DEPOT) ClrBit(order->flags, OF_UNLOAD); |
763 order->SetDepotOrderType(order->GetDepotOrderType() ^ OFB_SERVICE_IF_NEEDED); |
703 break; |
764 } else { |
704 case OF_UNLOAD: |
765 order->SetLoadType(order->GetUnloadType() ^ OFB_FULL_LOAD); |
705 ToggleBit(order->flags, OF_UNLOAD); |
766 order->SetUnloadType(order->GetUnloadType() & ~OFB_UNLOAD); |
706 ClrBit(order->flags, OF_FULL_LOAD); |
767 } |
707 break; |
768 break; |
708 case OF_NON_STOP: |
769 case OF_UNLOAD: |
709 ToggleBit(order->flags, OF_NON_STOP); |
770 order->SetUnloadType(order->GetUnloadType() ^ OFB_UNLOAD); |
710 break; |
771 order->SetLoadType(0); |
711 case OF_TRANSFER: |
772 break; |
712 ToggleBit(order->flags, OF_TRANSFER); |
773 case OF_NON_STOP: |
713 break; |
774 order->SetNonStopType(order->GetNonStopType() ^ OFB_NON_STOP); |
714 default: NOT_REACHED(); |
775 break; |
|
776 case OF_TRANSFER: |
|
777 order->SetUnloadType(order->GetUnloadType() ^ OFB_TRANSFER); |
|
778 break; |
|
779 default: NOT_REACHED(); |
715 } |
780 } |
716 |
781 |
717 /* Update the windows and full load flags, also for vehicles that share the same order list */ |
782 /* Update the windows and full load flags, also for vehicles that share the same order list */ |
718 { |
783 { |
719 Vehicle* u; |
784 Vehicle* u; |
904 if (order == NULL) return CMD_ERROR; |
969 if (order == NULL) return CMD_ERROR; |
905 |
970 |
906 if (flags & DC_EXEC) { |
971 if (flags & DC_EXEC) { |
907 Vehicle *u; |
972 Vehicle *u; |
908 |
973 |
909 order->refit_cargo = cargo; |
974 order->SetRefit(cargo, subtype); |
910 order->refit_subtype = subtype; |
|
911 |
975 |
912 u = GetFirstVehicleFromSharedList(v); |
976 u = GetFirstVehicleFromSharedList(v); |
913 for (; u != NULL; u = u->next_shared) { |
977 for (; u != NULL; u = u->next_shared) { |
914 /* Update any possible open window of the vehicle */ |
978 /* Update any possible open window of the vehicle */ |
915 InvalidateVehicleOrder(u); |
979 InvalidateVehicleOrder(u); |
916 |
980 |
917 /* If the vehicle already got the current depot set as current order, then update current order as well */ |
981 /* If the vehicle already got the current depot set as current order, then update current order as well */ |
918 if (u->cur_order_index == order_number && HasBit(u->current_order.flags, OF_PART_OF_ORDERS)) { |
982 if (u->cur_order_index == order_number && HasBit(u->current_order.GetDepotOrderType(), OF_PART_OF_ORDERS)) { |
919 u->current_order.refit_cargo = cargo; |
983 u->current_order.SetRefit(cargo, subtype); |
920 u->current_order.refit_subtype = subtype; |
|
921 } |
984 } |
922 } |
985 } |
923 } |
986 } |
924 |
987 |
925 return CommandCost(); |
988 return CommandCost(); |
998 /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the |
1061 /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the |
999 * order number is one more than the current amount of orders, and because |
1062 * order number is one more than the current amount of orders, and because |
1000 * in network the commands are queued before send, the second insert always |
1063 * in network the commands are queued before send, the second insert always |
1001 * fails in test mode. By bypassing the test-mode, that no longer is a problem. */ |
1064 * fails in test mode. By bypassing the test-mode, that no longer is a problem. */ |
1002 for (uint i = 0; bak->order[i].IsValid(); i++) { |
1065 for (uint i = 0; bak->order[i].IsValid(); i++) { |
1003 if (!DoCommandP(0, v->index + (i << 16), PackOrder(&bak->order[i]), NULL, |
1066 if (!DoCommandP(0, v->index + (i << 16), bak->order[i].Pack(), NULL, |
1004 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) { |
1067 CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) { |
1005 break; |
1068 break; |
1006 } |
1069 } |
1007 |
1070 |
1008 /* Copy timetable if enabled */ |
1071 /* Copy timetable if enabled */ |
1172 if (v->last_station_visited == destination && type == OT_GOTO_STATION) { |
1233 if (v->last_station_visited == destination && type == OT_GOTO_STATION) { |
1173 v->last_station_visited = INVALID_STATION; |
1234 v->last_station_visited = INVALID_STATION; |
1174 } |
1235 } |
1175 |
1236 |
1176 order = &v->current_order; |
1237 order = &v->current_order; |
1177 if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type && |
1238 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type && |
1178 v->current_order.dest == destination) { |
1239 v->current_order.GetDestination() == destination) { |
1179 order->type = OT_DUMMY; |
1240 order->MakeDummy(); |
1180 order->flags = 0; |
|
1181 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
1241 InvalidateWindow(WC_VEHICLE_VIEW, v->index); |
1182 } |
1242 } |
1183 |
1243 |
1184 /* Clear the order from the order-list */ |
1244 /* Clear the order from the order-list */ |
1185 invalidate = false; |
1245 invalidate = false; |
1186 FOR_VEHICLE_ORDERS(v, order) { |
1246 FOR_VEHICLE_ORDERS(v, order) { |
1187 if ((v->type == VEH_AIRCRAFT && order->type == OT_GOTO_DEPOT ? OT_GOTO_STATION : order->type) == type && |
1247 if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type && |
1188 order->dest == destination) { |
1248 order->GetDestination() == destination) { |
1189 order->type = OT_DUMMY; |
1249 order->MakeDummy(); |
1190 order->flags = 0; |
|
1191 invalidate = true; |
1250 invalidate = true; |
1192 } |
1251 } |
1193 } |
1252 } |
1194 |
1253 |
1195 /* Only invalidate once, and if needed */ |
1254 /* Only invalidate once, and if needed */ |
1273 Date GetServiceIntervalClamped(uint index) |
1332 Date GetServiceIntervalClamped(uint index) |
1274 { |
1333 { |
1275 return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS); |
1334 return (_patches.servint_ispercent) ? Clamp(index, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(index, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS); |
1276 } |
1335 } |
1277 |
1336 |
1278 |
|
1279 /** |
1337 /** |
1280 * |
1338 * |
1281 * Check if a vehicle has any valid orders |
1339 * Check if a vehicle has any valid orders |
1282 * |
1340 * |
1283 * @return false if there are no valid orders |
1341 * @return false if there are no valid orders |
1284 * |
1342 * |
1285 */ |
1343 */ |
1286 bool CheckForValidOrders(const Vehicle* v) |
1344 static bool CheckForValidOrders(const Vehicle *v) |
1287 { |
1345 { |
1288 const Order *order; |
1346 const Order *order; |
1289 |
1347 |
1290 FOR_VEHICLE_ORDERS(v, order) if (order->type != OT_DUMMY) return true; |
1348 FOR_VEHICLE_ORDERS(v, order) if (!order->IsType(OT_DUMMY)) return true; |
1291 |
1349 |
1292 return false; |
1350 return false; |
|
1351 } |
|
1352 |
|
1353 /** |
|
1354 * Handle the orders of a vehicle and determine the next place |
|
1355 * to go to if needed. |
|
1356 * @param v the vehicle to do this for. |
|
1357 * @return true *if* the vehicle is eligible for reversing |
|
1358 * (basically only when leaving a station). |
|
1359 */ |
|
1360 bool ProcessOrders(Vehicle *v) |
|
1361 { |
|
1362 switch (v->current_order.GetType()) { |
|
1363 case OT_GOTO_DEPOT: |
|
1364 /* Let a depot order in the orderlist interrupt. */ |
|
1365 if (!(v->current_order.GetDepotOrderType() & OFB_PART_OF_ORDERS)) return false; |
|
1366 |
|
1367 if ((v->current_order.GetDepotOrderType() & OFB_SERVICE_IF_NEEDED) && !VehicleNeedsService(v)) { |
|
1368 UpdateVehicleTimetable(v, true); |
|
1369 v->cur_order_index++; |
|
1370 } |
|
1371 break; |
|
1372 |
|
1373 case OT_LOADING: |
|
1374 return false; |
|
1375 |
|
1376 case OT_LEAVESTATION: |
|
1377 if (v->type != VEH_AIRCRAFT) return false; |
|
1378 break; |
|
1379 |
|
1380 default: break; |
|
1381 } |
|
1382 |
|
1383 /** |
|
1384 * Reversing because of order change is allowed only just after leaving a |
|
1385 * station (and the difficulty setting to allowed, of course) |
|
1386 * this can be detected because only after OT_LEAVESTATION, current_order |
|
1387 * will be reset to nothing. (That also happens if no order, but in that case |
|
1388 * it won't hit the point in code where may_reverse is checked) |
|
1389 */ |
|
1390 bool may_reverse = v->current_order.IsType(OT_NOTHING); |
|
1391 |
|
1392 /* Check if we've reached the waypoint? */ |
|
1393 if (v->current_order.IsType(OT_GOTO_WAYPOINT) && v->tile == v->dest_tile) { |
|
1394 UpdateVehicleTimetable(v, true); |
|
1395 v->cur_order_index++; |
|
1396 } |
|
1397 |
|
1398 /* Check if we've reached a non-stop station while TTDPatch nonstop is enabled.. */ |
|
1399 if (_patches.new_nonstop && |
|
1400 v->current_order.GetNonStopType() & OFB_NON_STOP && |
|
1401 IsTileType(v->tile, MP_STATION) && |
|
1402 v->current_order.GetDestination() == GetStationIndex(v->tile)) { |
|
1403 v->last_station_visited = v->current_order.GetDestination(); |
|
1404 UpdateVehicleTimetable(v, true); |
|
1405 v->cur_order_index++; |
|
1406 } |
|
1407 |
|
1408 /* Get the current order */ |
|
1409 if (v->cur_order_index >= v->num_orders) v->cur_order_index = 0; |
|
1410 |
|
1411 const Order *order = GetVehicleOrder(v, v->cur_order_index); |
|
1412 |
|
1413 /* If no order, do nothing. */ |
|
1414 if (order == NULL || (v->type == VEH_AIRCRAFT && order->IsType(OT_DUMMY) && !CheckForValidOrders(v))) { |
|
1415 if (v->type == VEH_AIRCRAFT) { |
|
1416 /* Aircraft do something vastly different here, so handle separately */ |
|
1417 extern void HandleMissingAircraftOrders(Vehicle *v); |
|
1418 HandleMissingAircraftOrders(v); |
|
1419 return false; |
|
1420 } |
|
1421 |
|
1422 v->current_order.Free(); |
|
1423 v->dest_tile = 0; |
|
1424 if (v->type == VEH_ROAD) ClearSlot(v); |
|
1425 return false; |
|
1426 } |
|
1427 |
|
1428 /* If it is unchanged, keep it. */ |
|
1429 if (order->Equals(v->current_order) && |
|
1430 (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || GetStation(order->GetDestination())->dock_tile != 0)) { |
|
1431 return false; |
|
1432 } |
|
1433 |
|
1434 /* Otherwise set it, and determine the destination tile. */ |
|
1435 v->current_order = *order; |
|
1436 |
|
1437 InvalidateVehicleOrder(v); |
|
1438 switch (v->type) { |
|
1439 default: |
|
1440 NOT_REACHED(); |
|
1441 |
|
1442 case VEH_ROAD: |
|
1443 case VEH_TRAIN: |
|
1444 break; |
|
1445 |
|
1446 case VEH_AIRCRAFT: |
|
1447 case VEH_SHIP: |
|
1448 InvalidateWindowClasses(v->GetVehicleListWindowClass()); |
|
1449 break; |
|
1450 } |
|
1451 |
|
1452 switch (order->GetType()) { |
|
1453 case OT_GOTO_STATION: |
|
1454 v->dest_tile = v->GetOrderStationLocation(order->GetDestination()); |
|
1455 break; |
|
1456 |
|
1457 case OT_GOTO_DEPOT: |
|
1458 if (v->type != VEH_AIRCRAFT) v->dest_tile = GetDepot(order->GetDestination())->xy; |
|
1459 break; |
|
1460 |
|
1461 case OT_GOTO_WAYPOINT: |
|
1462 v->dest_tile = GetWaypoint(order->GetDestination())->xy; |
|
1463 break; |
|
1464 |
|
1465 default: |
|
1466 v->dest_tile = 0; |
|
1467 return false; |
|
1468 } |
|
1469 |
|
1470 return may_reverse; |
|
1471 } |
|
1472 |
|
1473 /** |
|
1474 * Check whether the given vehicle should stop at the given station |
|
1475 * based on this order and the non-stop settings. |
|
1476 * @param v the vehicle that might be stopping. |
|
1477 * @param station the station to stop at. |
|
1478 * @return true if the vehicle should stop. |
|
1479 */ |
|
1480 bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const |
|
1481 { |
|
1482 return |
|
1483 v->last_station_visited != station && // Do stop only when we've not just been there |
|
1484 type == OT_GOTO_STATION && // Do stop only when going to a station |
|
1485 /* Finally do stop when the non-stop flag is not set, or when we should stop at |
|
1486 * this station according to the new_nonstop setting. */ |
|
1487 (!(this->flags & OFB_NON_STOP) || ((this->dest != station) == _patches.new_nonstop)); |
1293 } |
1488 } |
1294 |
1489 |
1295 void InitializeOrders() |
1490 void InitializeOrders() |
1296 { |
1491 { |
1297 _Order_pool.CleanPool(); |
1492 _Order_pool.CleanPool(); |
1298 _Order_pool.AddBlockToPool(); |
1493 _Order_pool.AddBlockToPool(); |
1299 |
1494 |
1300 _backup_orders_tile = 0; |
1495 _backup_orders_tile = 0; |
1301 } |
1496 } |
1302 |
1497 |
|
1498 const SaveLoad *GetOrderDescription() { |
1303 static const SaveLoad _order_desc[] = { |
1499 static const SaveLoad _order_desc[] = { |
1304 SLE_VAR(Order, type, SLE_UINT8), |
1500 SLE_VAR(Order, type, SLE_UINT8), |
1305 SLE_VAR(Order, flags, SLE_UINT8), |
1501 SLE_VAR(Order, flags, SLE_UINT8), |
1306 SLE_VAR(Order, dest, SLE_UINT16), |
1502 SLE_VAR(Order, dest, SLE_UINT16), |
1307 SLE_REF(Order, next, REF_ORDER), |
1503 SLE_REF(Order, next, REF_ORDER), |