order_backup.cpp

Go to the documentation of this file.
00001 /* $Id: order_backup.cpp 21933 2011-01-31 20:44:15Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "command_func.h"
00014 #include "core/pool_func.hpp"
00015 #include "network/network.h"
00016 #include "network/network_func.h"
00017 #include "order_backup.h"
00018 #include "vehicle_base.h"
00019 
00020 OrderBackupPool _order_backup_pool("BackupOrder");
00021 INSTANTIATE_POOL_METHODS(OrderBackup)
00022 
00023 
00024 OrderBackup::~OrderBackup()
00025 {
00026   free(this->name);
00027 
00028   if (CleaningPool()) return;
00029 
00030   Order *o = this->orders;
00031   while (o != NULL) {
00032     Order *next = o->next;
00033     delete o;
00034     o = next;
00035   }
00036 }
00037 
00043 OrderBackup::OrderBackup(const Vehicle *v, uint32 user)
00044 {
00045   this->user             = user;
00046   this->tile             = v->tile;
00047   this->orderindex       = v->cur_auto_order_index;
00048   this->group            = v->group_id;
00049   this->service_interval = v->service_interval;
00050 
00051   if (v->name != NULL) this->name = strdup(v->name);
00052 
00053   /* If we have shared orders, store the vehicle we share the order with. */
00054   if (v->IsOrderListShared()) {
00055     this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
00056   } else {
00057     /* Else copy the orders */
00058     Order **tail = &this->orders;
00059 
00060     /* Count the number of orders */
00061     const Order *order;
00062     FOR_VEHICLE_ORDERS(v, order) {
00063       Order *copy = new Order();
00064       copy->AssignOrder(*order);
00065       *tail = copy;
00066       tail = &copy->next;
00067     }
00068   }
00069 }
00070 
00075 void OrderBackup::DoRestore(Vehicle *v)
00076 {
00077   /* If we have a custom name, process that */
00078   v->name = this->name;
00079   this->name = NULL;
00080 
00081   /* If we had shared orders, recover that */
00082   if (this->clone != NULL) {
00083     DoCommand(0, v->index | CO_SHARE << 30, this->clone->index, DC_EXEC, CMD_CLONE_ORDER);
00084   } else if (this->orders != NULL && OrderList::CanAllocateItem()) {
00085     v->orders.list = new OrderList(this->orders, v);
00086     this->orders = NULL;
00087   }
00088 
00089   uint num_orders = v->GetNumOrders();
00090   if (num_orders != 0) {
00091     v->cur_real_order_index = v->cur_auto_order_index = this->orderindex % num_orders;
00092     v->UpdateRealOrderIndex();
00093   }
00094   v->service_interval = this->service_interval;
00095 
00096   /* Restore vehicle group */
00097   DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP);
00098 }
00099 
00106 /* static */ void OrderBackup::Backup(const Vehicle *v, uint32 user)
00107 {
00108   /* Don't use reset as that broadcasts over the network to reset the variable,
00109    * which is what we are doing at the moment. */
00110   OrderBackup *ob;
00111   FOR_ALL_ORDER_BACKUPS(ob) {
00112     if (ob->user == user) delete ob;
00113   }
00114   new OrderBackup(v, user);
00115 }
00116 
00123 /* static */ void OrderBackup::Restore(Vehicle *v, uint32 user)
00124 {
00125   OrderBackup *ob;
00126   FOR_ALL_ORDER_BACKUPS(ob) {
00127     if (v->tile != ob->tile || ob->user != user) continue;
00128 
00129     ob->DoRestore(v);
00130     delete ob;
00131   }
00132 }
00133 
00140 /* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32 user)
00141 {
00142   OrderBackup *ob;
00143   FOR_ALL_ORDER_BACKUPS(ob) {
00144     if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob;
00145   }
00146 }
00147 
00157 CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00158 {
00159   /* No need to check anything. If the tile or user don't exist we just ignore it. */
00160   if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2);
00161 
00162   return CommandCost();
00163 }
00164 
00171 /* static */ void OrderBackup::ResetUser(uint32 user)
00172 {
00173   assert(_network_server);
00174 
00175   OrderBackup *ob;
00176   FOR_ALL_ORDER_BACKUPS(ob) {
00177     /* If it's not an backup of us, so ignore it. */
00178     if (ob->user != user) continue;
00179 
00180     DoCommandP(0, 0, user, CMD_CLEAR_ORDER_BACKUP);
00181     return;
00182   }
00183 }
00184 
00191 /* static */ void OrderBackup::Reset(TileIndex t, bool from_gui)
00192 {
00193   /* The user has CLIENT_ID_SERVER as default when network play is not active,
00194    * but compiled it. A network client has its own variable for the unique
00195    * client/user identifier. Finally if networking isn't compiled in the
00196    * default is just plain and simple: 0. */
00197 #ifdef ENABLE_NETWORK
00198   uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER;
00199 #else
00200   uint32 user = 0;
00201 #endif
00202 
00203   OrderBackup *ob;
00204   FOR_ALL_ORDER_BACKUPS(ob) {
00205     /* If it's not an backup of us, so ignore it. */
00206     if (ob->user != user) continue;
00207     /* If it's not for our chosen tile either, ignore it. */
00208     if (t != INVALID_TILE && t != ob->tile) continue;
00209 
00210     if (from_gui) {
00211       /* We need to circumvent the "prevention" from this command being executed
00212        * while the game is paused, so use the internal method. Nor do we want
00213        * this command to get its cost estimated when shift is pressed. */
00214       DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false);
00215     } else {
00216       /* The command came from the game logic, i.e. the clearing of a tile.
00217        * In that case we have no need to actually sync this, just do it. */
00218       delete ob;
00219     }
00220   }
00221 }
00222 
00227 /* static */ void OrderBackup::ClearGroup(GroupID group)
00228 {
00229   OrderBackup *ob;
00230   FOR_ALL_ORDER_BACKUPS(ob) {
00231     if (ob->group == group) ob->group = DEFAULT_GROUP;
00232   }
00233 }
00234 
00242 /* static */ void OrderBackup::ClearVehicle(const Vehicle *v)
00243 {
00244   assert(v != NULL);
00245   OrderBackup *ob;
00246   FOR_ALL_ORDER_BACKUPS(ob) {
00247     if (ob->clone == v) {
00248       /* Get another item in the shared list. */
00249       ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared();
00250       /* But if that isn't there, remove it. */
00251       if (ob->clone == NULL) delete ob;
00252     }
00253   }
00254 }
00255 
00256 void InitializeOrderBackups()
00257 {
00258   _order_backup_pool.CleanPool();
00259 }

Generated on Fri Feb 4 20:53:44 2011 for OpenTTD by  doxygen 1.6.1