4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file order_sl.cpp Code handling saving and loading of orders */
12 #include "../stdafx.h"
13 #include "../order_backup.h"
14 #include "../settings_type.h"
15 #include "../network/network.h"
17 #include "saveload_internal.h"
19 #include "../safeguards.h"
22 * Converts this order from an old savegame's version;
23 * it moves all bits to the new location.
25 void Order::ConvertFromOldSavegame()
27 uint8 old_flags
= this->flags
;
30 /* First handle non-stop - use value from savegame if possible, else use value from config file */
31 if (_settings_client
.gui
.sg_new_nonstop
|| (IsSavegameVersionBefore(22) && _savegame_type
!= SGT_TTO
&& _savegame_type
!= SGT_TTD
&& _settings_client
.gui
.new_nonstop
)) {
33 this->SetNonStopType((old_flags
& 8) ? ONSF_NO_STOP_AT_ANY_STATION
: ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
);
35 this->SetNonStopType((old_flags
& 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
: ONSF_STOP_EVERYWHERE
);
38 switch (this->GetType()) {
39 /* Only a few types need the other savegame conversions. */
40 case OT_GOTO_DEPOT
: case OT_GOTO_STATION
: case OT_LOADING
: break;
44 if (this->GetType() != OT_GOTO_DEPOT
) {
45 /* Then the load flags */
46 if ((old_flags
& 2) != 0) { // OFB_UNLOAD
47 this->SetLoadType(OLFB_NO_LOAD
);
48 } else if ((old_flags
& 4) == 0) { // !OFB_FULL_LOAD
49 this->SetLoadType(OLF_LOAD_IF_POSSIBLE
);
51 /* old OTTD versions stored full_load_any in config file - assume it was enabled when loading */
52 this->SetLoadType(_settings_client
.gui
.sg_full_load_any
|| IsSavegameVersionBefore(22) ? OLF_FULL_LOAD_ANY
: OLFB_FULL_LOAD
);
55 if (this->IsType(OT_GOTO_STATION
)) this->SetStopLocation(OSL_PLATFORM_FAR_END
);
57 /* Finally fix the unload flags */
58 if ((old_flags
& 1) != 0) { // OFB_TRANSFER
59 this->SetUnloadType(OUFB_TRANSFER
);
60 } else if ((old_flags
& 2) != 0) { // OFB_UNLOAD
61 this->SetUnloadType(OUFB_UNLOAD
);
63 this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE
);
66 /* Then the depot action flags */
67 this->SetDepotActionType(((old_flags
& 6) == 4) ? ODATFB_HALT
: ODATF_SERVICE_ONLY
);
69 /* Finally fix the depot type flags */
70 uint t
= ((old_flags
& 6) == 6) ? ODTFB_SERVICE
: ODTF_MANUAL
;
71 if ((old_flags
& 2) != 0) t
|= ODTFB_PART_OF_ORDERS
;
72 this->SetDepotOrderType((OrderDepotTypeFlags
)t
);
77 * Unpacks a order from savegames with version 4 and lower
78 * @param packed packed order
79 * @return unpacked order
81 static Order
UnpackVersion4Order(uint16 packed
)
83 return Order(GB(packed
, 8, 8) << 16 | GB(packed
, 4, 4) << 8 | GB(packed
, 0, 4));
87 * Unpacks a order from savegames made with TTD(Patch)
88 * @param packed packed order
89 * @return unpacked order
91 Order
UnpackOldOrder(uint16 packed
)
93 Order order
= UnpackVersion4Order(packed
);
97 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
99 if (order
.IsType(OT_NOTHING
) && packed
!= 0) order
.MakeDummy();
104 const SaveLoad
*GetOrderDescription()
106 static const SaveLoad _order_desc
[] = {
107 SLE_VAR(Order
, type
, SLE_UINT8
),
108 SLE_VAR(Order
, flags
, SLE_UINT8
),
109 SLE_VAR(Order
, dest
, SLE_UINT16
),
110 SLE_REF(Order
, next
, REF_ORDER
),
111 SLE_CONDVAR(Order
, refit_cargo
, SLE_UINT8
, 36, SL_MAX_VERSION
),
112 SLE_CONDNULL(1, 36, 181), // refit_subtype
113 SLE_CONDVAR(Order
, wait_time
, SLE_UINT16
, 67, SL_MAX_VERSION
),
114 SLE_CONDVAR(Order
, travel_time
, SLE_UINT16
, 67, SL_MAX_VERSION
),
115 SLE_CONDVAR(Order
, max_speed
, SLE_UINT16
, 172, SL_MAX_VERSION
),
117 /* Leftover from the minor savegame version stuff
118 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
119 SLE_CONDNULL(10, 5, 35),
126 static void Save_ORDR()
130 FOR_ALL_ORDERS(order
) {
131 SlSetArrayIndex(order
->index
);
132 SlObject(order
, GetOrderDescription());
136 static void Load_ORDR()
138 if (IsSavegameVersionBefore(5, 2)) {
139 /* Version older than 5.2 did not have a ->next pointer. Convert them
140 * (in the old days, the orderlist was 5000 items big) */
141 size_t len
= SlGetFieldLength();
143 if (IsSavegameVersionBefore(5)) {
144 /* Pre-version 5 had another layout for orders
145 * (uint16 instead of uint32) */
146 len
/= sizeof(uint16
);
147 uint16
*orders
= MallocT
<uint16
>(len
+ 1);
149 SlArray(orders
, len
, SLE_UINT16
);
151 for (size_t i
= 0; i
< len
; ++i
) {
152 Order
*o
= new (i
) Order();
153 o
->AssignOrder(UnpackVersion4Order(orders
[i
]));
157 } else if (IsSavegameVersionBefore(5, 2)) {
158 len
/= sizeof(uint32
);
159 uint32
*orders
= MallocT
<uint32
>(len
+ 1);
161 SlArray(orders
, len
, SLE_UINT32
);
163 for (size_t i
= 0; i
< len
; ++i
) {
164 new (i
) Order(orders
[i
]);
170 /* Update all the next pointer */
173 /* Delete invalid orders */
174 if (o
->IsType(OT_NOTHING
)) {
178 /* The orders were built like this:
179 * While the order is valid, set the previous will get its next pointer set */
180 Order
*prev
= Order::GetIfValid(order_index
- 1);
181 if (prev
!= NULL
) prev
->next
= o
;
186 while ((index
= SlIterateArray()) != -1) {
187 Order
*order
= new (index
) Order();
188 SlObject(order
, GetOrderDescription());
189 if (IsSavegameVersionBefore(190)) {
190 order
->SetTravelTimetabled(order
->GetTravelTime() > 0);
191 order
->SetWaitTimetabled(order
->GetWaitTime() > 0);
197 static void Ptrs_ORDR()
199 /* Orders from old savegames have pointers corrected in Load_ORDR */
200 if (IsSavegameVersionBefore(5, 2)) return;
205 SlObject(o
, GetOrderDescription());
209 const SaveLoad
*GetOrderListDescription()
211 static const SaveLoad _orderlist_desc
[] = {
212 SLE_REF(OrderList
, first
, REF_ORDER
),
216 return _orderlist_desc
;
219 static void Save_ORDL()
223 FOR_ALL_ORDER_LISTS(list
) {
224 SlSetArrayIndex(list
->index
);
225 SlObject(list
, GetOrderListDescription());
229 static void Load_ORDL()
233 while ((index
= SlIterateArray()) != -1) {
234 /* set num_orders to 0 so it's a valid OrderList */
235 OrderList
*list
= new (index
) OrderList(0);
236 SlObject(list
, GetOrderListDescription());
241 static void Ptrs_ORDL()
245 FOR_ALL_ORDER_LISTS(list
) {
246 SlObject(list
, GetOrderListDescription());
250 const SaveLoad
*GetOrderBackupDescription()
252 static const SaveLoad _order_backup_desc
[] = {
253 SLE_VAR(OrderBackup
, user
, SLE_UINT32
),
254 SLE_VAR(OrderBackup
, tile
, SLE_UINT32
),
255 SLE_VAR(OrderBackup
, group
, SLE_UINT16
),
256 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, 0, 191),
257 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_UINT16
, 192, SL_MAX_VERSION
),
258 SLE_STR(OrderBackup
, name
, SLE_STR
, 0),
259 SLE_CONDNULL(2, 0, 191), // clone (2 bytes of pointer, i.e. garbage)
260 SLE_CONDREF(OrderBackup
, clone
, REF_VEHICLE
, 192, SL_MAX_VERSION
),
261 SLE_VAR(OrderBackup
, cur_real_order_index
, SLE_UINT8
),
262 SLE_CONDVAR(OrderBackup
, cur_implicit_order_index
, SLE_UINT8
, 176, SL_MAX_VERSION
),
263 SLE_CONDVAR(OrderBackup
, current_order_time
, SLE_UINT32
, 176, SL_MAX_VERSION
),
264 SLE_CONDVAR(OrderBackup
, lateness_counter
, SLE_INT32
, 176, SL_MAX_VERSION
),
265 SLE_CONDVAR(OrderBackup
, timetable_start
, SLE_INT32
, 176, SL_MAX_VERSION
),
266 SLE_CONDVAR(OrderBackup
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, 176, 179),
267 SLE_CONDVAR(OrderBackup
, vehicle_flags
, SLE_UINT16
, 180, SL_MAX_VERSION
),
268 SLE_REF(OrderBackup
, orders
, REF_ORDER
),
272 return _order_backup_desc
;
275 static void Save_BKOR()
277 /* We only save this when we're a network server
278 * as we want this information on our clients. For
279 * normal games this information isn't needed. */
280 if (!_networking
|| !_network_server
) return;
283 FOR_ALL_ORDER_BACKUPS(ob
) {
284 SlSetArrayIndex(ob
->index
);
285 SlObject(ob
, GetOrderBackupDescription());
293 while ((index
= SlIterateArray()) != -1) {
294 /* set num_orders to 0 so it's a valid OrderList */
295 OrderBackup
*ob
= new (index
) OrderBackup();
296 SlObject(ob
, GetOrderBackupDescription());
300 static void Ptrs_BKOR()
303 FOR_ALL_ORDER_BACKUPS(ob
) {
304 SlObject(ob
, GetOrderBackupDescription());
308 extern const ChunkHandler _order_chunk_handlers
[] = {
309 { 'BKOR', Save_BKOR
, Load_BKOR
, Ptrs_BKOR
, NULL
, CH_ARRAY
},
310 { 'ORDR', Save_ORDR
, Load_ORDR
, Ptrs_ORDR
, NULL
, CH_ARRAY
},
311 { 'ORDL', Save_ORDL
, Load_ORDL
, Ptrs_ORDL
, NULL
, CH_ARRAY
| CH_LAST
},