2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file order_sl.cpp Code handling saving and loading of orders */
10 #include "../stdafx.h"
13 #include "compat/order_sl_compat.h"
15 #include "saveload_internal.h"
16 #include "../order_backup.h"
17 #include "../settings_type.h"
18 #include "../network/network.h"
20 #include "../safeguards.h"
23 * Converts this order from an old savegame's version;
24 * it moves all bits to the new location.
26 void Order::ConvertFromOldSavegame()
28 uint8_t old_flags
= this->flags
;
31 /* First handle non-stop - use value from savegame if possible, else use value from config file */
32 if (_settings_client
.gui
.sg_new_nonstop
|| (IsSavegameVersionBefore(SLV_22
) && _savegame_type
!= SGT_TTO
&& _savegame_type
!= SGT_TTD
&& _settings_client
.gui
.new_nonstop
)) {
34 this->SetNonStopType((old_flags
& 8) ? ONSF_NO_STOP_AT_ANY_STATION
: ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
);
36 this->SetNonStopType((old_flags
& 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS
: ONSF_STOP_EVERYWHERE
);
39 switch (this->GetType()) {
40 /* Only a few types need the other savegame conversions. */
41 case OT_GOTO_DEPOT
: case OT_GOTO_STATION
: case OT_LOADING
: break;
45 if (this->GetType() != OT_GOTO_DEPOT
) {
46 /* Then the load flags */
47 if ((old_flags
& 2) != 0) { // OFB_UNLOAD
48 this->SetLoadType(OLFB_NO_LOAD
);
49 } else if ((old_flags
& 4) == 0) { // !OFB_FULL_LOAD
50 this->SetLoadType(OLF_LOAD_IF_POSSIBLE
);
52 /* old OTTD versions stored full_load_any in config file - assume it was enabled when loading */
53 this->SetLoadType(_settings_client
.gui
.sg_full_load_any
|| IsSavegameVersionBefore(SLV_22
) ? OLF_FULL_LOAD_ANY
: OLFB_FULL_LOAD
);
56 if (this->IsType(OT_GOTO_STATION
)) this->SetStopLocation(OSL_PLATFORM_FAR_END
);
58 /* Finally fix the unload flags */
59 if ((old_flags
& 1) != 0) { // OFB_TRANSFER
60 this->SetUnloadType(OUFB_TRANSFER
);
61 } else if ((old_flags
& 2) != 0) { // OFB_UNLOAD
62 this->SetUnloadType(OUFB_UNLOAD
);
64 this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE
);
67 /* Then the depot action flags */
68 this->SetDepotActionType(((old_flags
& 6) == 4) ? ODATFB_HALT
: ODATF_SERVICE_ONLY
);
70 /* Finally fix the depot type flags */
71 uint t
= ((old_flags
& 6) == 6) ? ODTFB_SERVICE
: ODTF_MANUAL
;
72 if ((old_flags
& 2) != 0) t
|= ODTFB_PART_OF_ORDERS
;
73 this->SetDepotOrderType((OrderDepotTypeFlags
)t
);
78 * Unpacks a order from savegames with version 4 and lower
79 * @param packed packed order
80 * @return unpacked order
82 static Order
UnpackVersion4Order(uint16_t packed
)
84 return Order(GB(packed
, 0, 4), GB(packed
, 4, 4), GB(packed
, 8, 8));
88 * Unpacks a order from savegames made with TTD(Patch)
89 * @param packed packed order
90 * @return unpacked order
92 Order
UnpackOldOrder(uint16_t packed
)
94 Order order
= UnpackVersion4Order(packed
);
98 * TTD stores invalid orders as OT_NOTHING with non-zero flags/station
100 if (order
.IsType(OT_NOTHING
) && packed
!= 0) order
.MakeDummy();
105 SaveLoadTable
GetOrderDescription()
107 static const SaveLoad _order_desc
[] = {
108 SLE_VAR(Order
, type
, SLE_UINT8
),
109 SLE_VAR(Order
, flags
, SLE_UINT8
),
110 SLE_VAR(Order
, dest
, SLE_UINT16
),
111 SLE_REF(Order
, next
, REF_ORDER
),
112 SLE_CONDVAR(Order
, refit_cargo
, SLE_UINT8
, SLV_36
, SL_MAX_VERSION
),
113 SLE_CONDVAR(Order
, wait_time
, SLE_UINT16
, SLV_67
, SL_MAX_VERSION
),
114 SLE_CONDVAR(Order
, travel_time
, SLE_UINT16
, SLV_67
, SL_MAX_VERSION
),
115 SLE_CONDVAR(Order
, max_speed
, SLE_UINT16
, SLV_172
, SL_MAX_VERSION
),
121 struct ORDRChunkHandler
: ChunkHandler
{
122 ORDRChunkHandler() : ChunkHandler('ORDR', CH_TABLE
) {}
124 void Save() const override
126 const SaveLoadTable slt
= GetOrderDescription();
129 for (Order
*order
: Order::Iterate()) {
130 SlSetArrayIndex(order
->index
);
131 SlObject(order
, slt
);
135 void Load() const override
137 if (IsSavegameVersionBefore(SLV_5
, 2)) {
138 /* Version older than 5.2 did not have a ->next pointer. Convert them
139 * (in the old days, the orderlist was 5000 items big) */
140 size_t len
= SlGetFieldLength();
142 if (IsSavegameVersionBefore(SLV_5
)) {
143 /* Pre-version 5 had another layout for orders
144 * (uint16_t instead of uint32_t) */
145 len
/= sizeof(uint16_t);
146 std::vector
<uint16_t> orders(len
);
148 SlCopy(&orders
[0], len
, SLE_UINT16
);
150 for (size_t i
= 0; i
< len
; ++i
) {
151 Order
*o
= new (i
) Order();
152 o
->AssignOrder(UnpackVersion4Order(orders
[i
]));
154 } else if (IsSavegameVersionBefore(SLV_5
, 2)) {
155 len
/= sizeof(uint32_t);
156 std::vector
<uint32_t> orders(len
);
158 SlCopy(&orders
[0], len
, SLE_UINT32
);
160 for (size_t i
= 0; i
< len
; ++i
) {
161 new (i
) Order(GB(orders
[i
], 0, 8), GB(orders
[i
], 8, 8), GB(orders
[i
], 16, 16));
165 /* Update all the next pointer */
166 for (Order
*o
: Order::Iterate()) {
167 size_t order_index
= o
->index
;
168 /* Delete invalid orders */
169 if (o
->IsType(OT_NOTHING
)) {
173 /* The orders were built like this:
174 * While the order is valid, set the previous will get its next pointer set */
175 Order
*prev
= Order::GetIfValid(order_index
- 1);
176 if (prev
!= nullptr) prev
->next
= o
;
179 const std::vector
<SaveLoad
> slt
= SlCompatTableHeader(GetOrderDescription(), _order_sl_compat
);
183 while ((index
= SlIterateArray()) != -1) {
184 Order
*order
= new (index
) Order();
185 SlObject(order
, slt
);
190 void FixPointers() const override
192 /* Orders from old savegames have pointers corrected in Load_ORDR */
193 if (IsSavegameVersionBefore(SLV_5
, 2)) return;
195 for (Order
*o
: Order::Iterate()) {
196 SlObject(o
, GetOrderDescription());
201 SaveLoadTable
GetOrderListDescription()
203 static const SaveLoad _orderlist_desc
[] = {
204 SLE_REF(OrderList
, first
, REF_ORDER
),
207 return _orderlist_desc
;
210 struct ORDLChunkHandler
: ChunkHandler
{
211 ORDLChunkHandler() : ChunkHandler('ORDL', CH_TABLE
) {}
213 void Save() const override
215 const SaveLoadTable slt
= GetOrderListDescription();
218 for (OrderList
*list
: OrderList::Iterate()) {
219 SlSetArrayIndex(list
->index
);
224 void Load() const override
226 const std::vector
<SaveLoad
> slt
= SlCompatTableHeader(GetOrderListDescription(), _orderlist_sl_compat
);
230 while ((index
= SlIterateArray()) != -1) {
231 /* set num_orders to 0 so it's a valid OrderList */
232 OrderList
*list
= new (index
) OrderList(0);
238 void FixPointers() const override
240 for (OrderList
*list
: OrderList::Iterate()) {
241 SlObject(list
, GetOrderListDescription());
246 SaveLoadTable
GetOrderBackupDescription()
248 static const SaveLoad _order_backup_desc
[] = {
249 SLE_VAR(OrderBackup
, user
, SLE_UINT32
),
250 SLE_VAR(OrderBackup
, tile
, SLE_UINT32
),
251 SLE_VAR(OrderBackup
, group
, SLE_UINT16
),
252 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_192
),
253 SLE_CONDVAR(OrderBackup
, service_interval
, SLE_UINT16
, SLV_192
, SL_MAX_VERSION
),
254 SLE_SSTR(OrderBackup
, name
, SLE_STR
),
255 SLE_CONDREF(OrderBackup
, clone
, REF_VEHICLE
, SLV_192
, SL_MAX_VERSION
),
256 SLE_VAR(OrderBackup
, cur_real_order_index
, SLE_UINT8
),
257 SLE_CONDVAR(OrderBackup
, cur_implicit_order_index
, SLE_UINT8
, SLV_176
, SL_MAX_VERSION
),
258 SLE_CONDVAR(OrderBackup
, current_order_time
, SLE_UINT32
, SLV_176
, SL_MAX_VERSION
),
259 SLE_CONDVAR(OrderBackup
, lateness_counter
, SLE_INT32
, SLV_176
, SL_MAX_VERSION
),
260 SLE_CONDVAR(OrderBackup
, timetable_start
, SLE_FILE_I32
| SLE_VAR_U64
, SLV_176
, SLV_TIMETABLE_START_TICKS_FIX
),
261 SLE_CONDVAR(OrderBackup
, timetable_start
, SLE_UINT64
, SLV_TIMETABLE_START_TICKS_FIX
, SL_MAX_VERSION
),
262 SLE_CONDVAR(OrderBackup
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, SLV_176
, SLV_180
),
263 SLE_CONDVAR(OrderBackup
, vehicle_flags
, SLE_UINT16
, SLV_180
, SL_MAX_VERSION
),
264 SLE_REF(OrderBackup
, orders
, REF_ORDER
),
267 return _order_backup_desc
;
270 struct BKORChunkHandler
: ChunkHandler
{
271 BKORChunkHandler() : ChunkHandler('BKOR', CH_TABLE
) {}
273 void Save() const override
275 const SaveLoadTable slt
= GetOrderBackupDescription();
278 /* We only save this when we're a network server
279 * as we want this information on our clients. For
280 * normal games this information isn't needed. */
281 if (!_networking
|| !_network_server
) return;
283 for (OrderBackup
*ob
: OrderBackup::Iterate()) {
284 SlSetArrayIndex(ob
->index
);
289 void Load() const override
291 const std::vector
<SaveLoad
> slt
= SlCompatTableHeader(GetOrderBackupDescription(), _order_backup_sl_compat
);
295 while ((index
= SlIterateArray()) != -1) {
296 /* set num_orders to 0 so it's a valid OrderList */
297 OrderBackup
*ob
= new (index
) OrderBackup();
302 void FixPointers() const override
304 for (OrderBackup
*ob
: OrderBackup::Iterate()) {
305 SlObject(ob
, GetOrderBackupDescription());
310 static const BKORChunkHandler BKOR
;
311 static const ORDRChunkHandler ORDR
;
312 static const ORDLChunkHandler ORDL
;
313 static const ChunkHandlerRef order_chunk_handlers
[] = {
319 extern const ChunkHandlerTable
_order_chunk_handlers(order_chunk_handlers
);