diff options
Diffstat (limited to 'src/order_backup.cpp')
-rw-r--r-- | src/order_backup.cpp | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/src/order_backup.cpp b/src/order_backup.cpp new file mode 100644 index 000000000..3a462e3ce --- /dev/null +++ b/src/order_backup.cpp @@ -0,0 +1,146 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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/>. + */ + +/** @file order_backup.cpp Handling of order backups. */ + +#include "stdafx.h" +#include "command_func.h" +#include "core/pool_func.hpp" +#include "order_backup.h" +#include "order_base.h" +#include "vehicle_base.h" +#include "settings_type.h" + +OrderBackupPool _order_backup_pool("BackupOrder"); +INSTANTIATE_POOL_METHODS(OrderBackup) + +OrderBackup::~OrderBackup() +{ + free(this->name); + free(this->orders); +} + +OrderBackup::OrderBackup(const Vehicle *v) +{ + this->tile = v->tile; + this->orderindex = v->cur_order_index; + this->group = v->group_id; + this->service_interval = v->service_interval; + + if (v->name != NULL) this->name = strdup(v->name); + + /* If we have shared orders, store the vehicle we share the order with. */ + if (v->IsOrderListShared()) { + const Vehicle *u = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared(); + + this->clone = u->index; + } else { + /* Else copy the orders */ + + /* We do not have shared orders */ + this->clone = INVALID_VEHICLE; + + /* Count the number of orders */ + uint cnt = 0; + const Order *order; + FOR_VEHICLE_ORDERS(v, order) cnt++; + + /* Allocate memory for the orders plus an end-of-orders marker */ + this->orders = MallocT<Order>(cnt + 1); + + Order *dest = this->orders; + + /* Copy the orders */ + FOR_VEHICLE_ORDERS(v, order) { + memcpy(dest, order, sizeof(Order)); + dest++; + } + /* End the list with an empty order */ + dest->Free(); + } +} + +void OrderBackup::RestoreTo(const Vehicle *v) +{ + /* If we have a custom name, process that */ + if (this->name != NULL) DoCommandP(0, v->index, 0, CMD_RENAME_VEHICLE, NULL, this->name); + + /* If we had shared orders, recover that */ + if (this->clone != INVALID_VEHICLE) { + DoCommandP(0, v->index | (this->clone << 16), CO_SHARE, CMD_CLONE_ORDER); + } else { + + /* CMD_NO_TEST_IF_IN_NETWORK is used here, because CMD_INSERT_ORDER checks if the + * order number is one more than the current amount of orders, and because + * in network the commands are queued before send, the second insert always + * fails in test mode. By bypassing the test-mode, that no longer is a problem. */ + for (uint i = 0; !this->orders[i].IsType(OT_NOTHING); i++) { + Order o = this->orders[i]; + /* Conditional orders need to have their destination to be valid on insertion. */ + if (o.IsType(OT_CONDITIONAL)) o.SetConditionSkipToOrder(0); + + if (!DoCommandP(0, v->index + (i << 16), o.Pack(), + CMD_INSERT_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) { + break; + } + + /* Copy timetable if enabled */ + if (_settings_game.order.timetabling && !DoCommandP(0, v->index | (i << 16) | (1 << 25), + o.wait_time << 16 | o.travel_time, + CMD_CHANGE_TIMETABLE | CMD_NO_TEST_IF_IN_NETWORK)) { + break; + } + } + + /* Fix the conditional orders' destination. */ + for (uint i = 0; !this->orders[i].IsType(OT_NOTHING); i++) { + if (!this->orders[i].IsType(OT_CONDITIONAL)) continue; + + if (!DoCommandP(0, v->index + (i << 16), MOF_LOAD | (this->orders[i].GetConditionSkipToOrder() << 4), + CMD_MODIFY_ORDER | CMD_NO_TEST_IF_IN_NETWORK)) { + break; + } + } + } + + /* Restore vehicle order-index and service interval */ + DoCommandP(0, v->index, this->orderindex | (this->service_interval << 16), CMD_RESTORE_ORDER_INDEX); + + /* Restore vehicle group */ + DoCommandP(0, this->group, v->index, CMD_ADD_VEHICLE_GROUP); + + delete this; +} + +/* static */ OrderBackup *OrderBackup::GetByTile(TileIndex t) +{ + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + if (ob->tile == t) return ob; + } + return NULL; +} + +/* static */ void OrderBackup::Reset() +{ + _order_backup_pool.CleanPool(); +} + +/* static */ void OrderBackup::ClearGroup(GroupID group) +{ + OrderBackup *ob; + FOR_ALL_ORDER_BACKUPS(ob) { + if (ob->group == group) ob->group = DEFAULT_GROUP; + } +} + +void InitializeOrderBackups() +{ + _order_backup_pool.CleanPool(); +} |