1 /* $Id: order_sl.cpp 25041 2013-02-24 16:41:51Z frosch $ */
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
),
116 SLE_CONDVAR(Order
, jump_counter
, SLE_INT8
, SL_PATCH_PACK_1_12
, SL_MAX_VERSION
),
118 /* Leftover from the minor savegame version stuff
119 * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
120 SLE_CONDNULL(10, 5, 35),
127 static void Save_ORDR()
131 FOR_ALL_ORDERS(order
) {
132 SlSetArrayIndex(order
->index
);
133 SlObject(order
, GetOrderDescription());
137 static void Load_ORDR()
139 if (IsSavegameVersionBefore(5, 2)) {
140 /* Version older than 5.2 did not have a ->next pointer. Convert them
141 * (in the old days, the orderlist was 5000 items big) */
142 size_t len
= SlGetFieldLength();
144 if (IsSavegameVersionBefore(5)) {
145 /* Pre-version 5 had another layout for orders
146 * (uint16 instead of uint32) */
147 len
/= sizeof(uint16
);
148 uint16
*orders
= MallocT
<uint16
>(len
+ 1);
150 SlArray(orders
, len
, SLE_UINT16
);
152 for (size_t i
= 0; i
< len
; ++i
) {
153 Order
*o
= new (i
) Order();
154 o
->AssignOrder(UnpackVersion4Order(orders
[i
]));
158 } else if (IsSavegameVersionBefore(5, 2)) {
159 len
/= sizeof(uint32
);
160 uint32
*orders
= MallocT
<uint32
>(len
+ 1);
162 SlArray(orders
, len
, SLE_UINT32
);
164 for (size_t i
= 0; i
< len
; ++i
) {
165 new (i
) Order(orders
[i
]);
171 /* Update all the next pointer */
174 /* Delete invalid orders */
175 if (o
->IsType(OT_NOTHING
)) {
179 /* The orders were built like this:
180 * While the order is valid, set the previous will get its next pointer set */
181 Order
*prev
= Order::GetIfValid(order_index
- 1);
182 if (prev
!= NULL
) prev
->next
= o
;
187 while ((index
= SlIterateArray()) != -1) {
188 Order
*order
= new (index
) Order();
189 SlObject(order
, GetOrderDescription());
190 if (IsSavegameVersionBefore(190) || IsPatchPackSavegameVersionBefore(SL_PATCH_PACK_1_8
)) {
191 order
->SetTravelTimetabled(order
->GetTravelTime() > 0);
192 order
->SetWaitTimetabled(order
->GetWaitTime() > 0);
198 const SaveLoad
*GetOrderExtraInfoDescription()
200 static const SaveLoad _order_extra_info_desc
[] = {
201 SLE_ARR(OrderExtraInfo
, cargo_type_flags
, SLE_UINT8
, NUM_CARGO
),
205 return _order_extra_info_desc
;
212 FOR_ALL_ORDERS(order
) {
213 if (order
->extra
!= NULL
) {
214 SlSetArrayIndex(order
->index
);
215 SlObject(order
->extra
.get(), GetOrderExtraInfoDescription());
223 while ((index
= SlIterateArray()) != -1) {
224 Order
*order
= Order::GetIfValid(index
);
225 assert(order
!= NULL
);
226 order
->AllocExtraInfo();
227 SlObject(order
->extra
.get(), GetOrderExtraInfoDescription());
231 static void Ptrs_ORDR()
233 /* Orders from old savegames have pointers corrected in Load_ORDR */
234 if (IsSavegameVersionBefore(5, 2)) return;
239 SlObject(o
, GetOrderDescription());
243 const SaveLoad
*GetOrderListDescription()
245 static const SaveLoad _orderlist_desc
[] = {
246 SLE_REF(OrderList
, first
, REF_ORDER
),
247 SLE_CONDVAR(OrderList
, current_sep_mode
, SLE_UINT
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
248 SLE_CONDVAR(OrderList
, num_sep_vehicles
, SLE_UINT
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
249 SLE_CONDVAR(OrderList
, separation_counter
, SLE_UINT
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
250 SLE_CONDVAR(OrderList
, separation_counter
, SLE_UINT
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
251 SLE_CONDVAR(OrderList
, is_separation_valid
, SLE_BOOL
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
252 SLE_CONDVAR(OrderList
, current_separation
, SLE_INT
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
253 SLE_CONDVAR(OrderList
, last_timetable_init
, SLE_INT
, SL_PATCH_PACK_1_6
, SL_MAX_VERSION
),
257 return _orderlist_desc
;
260 static void Save_ORDL()
264 FOR_ALL_ORDER_LISTS(list
) {
265 SlSetArrayIndex(list
->index
);
266 SlObject(list
, GetOrderListDescription());
270 static void Load_ORDL()
274 while ((index
= SlIterateArray()) != -1) {
275 /* set num_orders to 0 so it's a valid OrderList */
276 OrderList
*list
= new (index
) OrderList(0);
277 SlObject(list
, GetOrderListDescription());
282 static void Ptrs_ORDL()
286 FOR_ALL_ORDER_LISTS(list
) {
287 SlObject(list
, GetOrderListDescription());
291 const SaveLoad
*GetOrderBackupDescription()
293 static const SaveLoad _order_backup_desc
[] = {
294 SLE_VAR(OrderBackup
, user
, SLE_UINT32
),
295 SLE_VAR(OrderBackup
, tile
, SLE_UINT32
),
296 SLE_VAR(OrderBackup
, group
, SLE_UINT16
),
297 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, 0, 191),
298 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_UINT16
, 191, SL_PATCH_PACK
-1),
299 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, SL_PATCH_PACK
, SL_PATCH_PACK_1_7
),
300 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_UINT16
, SL_PATCH_PACK_1_8
, SL_MAX_VERSION
),
301 SLE_STR(OrderBackup
, name
, SLE_STR
, 0),
302 SLE_CONDNULL(2, 0, 191), // clone (2 bytes of pointer, i.e. garbage)
303 SLE_CONDREF(OrderBackup
, clone
, REF_VEHICLE
, 192, SL_PATCH_PACK
-1),
304 SLE_CONDNULL(2, SL_PATCH_PACK
, SL_PATCH_PACK_1_7
), // clone (2 bytes of pointer, i.e. garbage)
305 SLE_CONDREF(OrderBackup
, clone
, REF_VEHICLE
, SL_PATCH_PACK_1_8
, SL_MAX_VERSION
),
306 SLE_VAR(OrderBackup
, cur_real_order_index
, SLE_UINT8
),
307 SLE_CONDVAR(OrderBackup
, cur_implicit_order_index
, SLE_UINT8
, 176, SL_MAX_VERSION
),
308 SLE_CONDVAR(OrderBackup
, current_order_time
, SLE_UINT32
, 176, SL_MAX_VERSION
),
309 SLE_CONDVAR(OrderBackup
, lateness_counter
, SLE_INT32
, 176, SL_MAX_VERSION
),
310 SLE_CONDVAR(OrderBackup
, timetable_start
, SLE_INT32
, 176, SL_MAX_VERSION
),
311 SLE_CONDVAR(OrderBackup
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, 176, 179),
312 SLE_CONDVAR(OrderBackup
, vehicle_flags
, SLE_UINT16
, 180, SL_MAX_VERSION
),
313 SLE_REF(OrderBackup
, orders
, REF_ORDER
),
317 return _order_backup_desc
;
320 static void Save_BKOR()
322 /* We only save this when we're a network server
323 * as we want this information on our clients. For
324 * normal games this information isn't needed. */
325 if (!_networking
|| !_network_server
) return;
328 FOR_ALL_ORDER_BACKUPS(ob
) {
329 SlSetArrayIndex(ob
->index
);
330 SlObject(ob
, GetOrderBackupDescription());
338 while ((index
= SlIterateArray()) != -1) {
339 /* set num_orders to 0 so it's a valid OrderList */
340 OrderBackup
*ob
= new (index
) OrderBackup();
341 SlObject(ob
, GetOrderBackupDescription());
345 static void Ptrs_BKOR()
348 FOR_ALL_ORDER_BACKUPS(ob
) {
349 SlObject(ob
, GetOrderBackupDescription());
353 extern const ChunkHandler _order_chunk_handlers
[] = {
354 { 'BKOR', Save_BKOR
, Load_BKOR
, Ptrs_BKOR
, NULL
, CH_ARRAY
},
355 { 'ORDR', Save_ORDR
, Load_ORDR
, Ptrs_ORDR
, NULL
, CH_ARRAY
},
356 { 'ORDL', Save_ORDL
, Load_ORDL
, Ptrs_ORDL
, NULL
, CH_ARRAY
},
357 { 'ORDX', Save_ORDX
, Load_ORDX
, NULL
, NULL
, CH_SPARSE_ARRAY
| CH_LAST
},