(svn r12913) -Add: ability to backup and restore a player's economic data and data for a vehicle (or chain of vehicles)

Autoreplace uses this with the following benefits:
  -Mass autoreplace (the button in the depot window) will now estimate costs correctly
  -Autoreplace now either replaces correctly or manages to keep the original vehicle (no more broken trains)
  Thanks to Ammler for testing this
This commit is contained in:
bjarni
2008-04-27 20:09:29 +00:00
parent d6c971fd9b
commit 783e20a263
8 changed files with 208 additions and 30 deletions

View File

@@ -712,12 +712,7 @@ void CallVehicleTicks()
v->leave_depot_instantly = false;
v->vehstatus &= ~VS_STOPPED;
}
CommandCost cost = MaybeReplaceVehicle(v, 0, true);
if (CmdSucceeded(cost) && cost.GetCost() != 0) {
/* Looks like we can replace this vehicle so we go ahead and do so */
MaybeReplaceVehicle(v, DC_EXEC, true);
}
MaybeReplaceVehicle(v, DC_EXEC, true);
v = w;
}
_current_player = OWNER_NONE;
@@ -2689,6 +2684,87 @@ void Vehicle::SetNext(Vehicle *next)
}
}
/** Backs up a chain of vehicles
* @return a pointer to the chain
*/
Vehicle* Vehicle::BackupVehicle() const
{
int length = CountVehiclesInChain(this);
Vehicle *list = MallocT<Vehicle>(length);
Vehicle *copy = list; // store the pointer so we have something to return later
const Vehicle *original = this;
for (; 0 < length; original = original->next, copy++, length--) {
memcpy(copy, original, sizeof(Vehicle));
}
return list;
}
/** Restore a backed up row of vehicles
* @return a pointer to the first vehicle in chain
*/
Vehicle* Vehicle::RestoreBackupVehicle()
{
Vehicle *backup = this;
Player *p = GetPlayer(backup->owner);
while (true) {
Vehicle *dest = GetVehicle(backup->index);
/* The vehicle should be free since we are restoring something we just sold. */
assert(!dest->IsValid());
memcpy(dest, backup, sizeof(Vehicle));
/* We decreased the engine count when we sold the engines so we will increase it again. */
if (IsEngineCountable(backup)) p->num_engines[backup->engine_type]++;
Vehicle *dummy = dest;
dest->old_new_hash = &dummy;
dest->left_coord = INVALID_COORD;
UpdateVehiclePosHash(dest, INVALID_COORD, 0);
if (backup->next == NULL) break;
backup++;
}
return GetVehicle(this->index);
}
/** Restores a backed up vehicle
* @param *v A vehicle we should sell and take the windows from (NULL for not using this)
* @return The vehicle we restored (front for trains) or v if we didn't have anything to restore
*/
Vehicle *BackuppedVehicle::Restore(Vehicle *v)
{
if (!ContainsBackup()) return v;
if (v != NULL) {
ChangeVehicleViewWindow(v, INVALID_VEHICLE);
DoCommand(0, v->index, 1, DC_EXEC, GetCmdSellVeh(v));
}
v = this->vehicles->RestoreBackupVehicle();
ChangeVehicleViewWindow(INVALID_VEHICLE, v);
if (orders != NULL) RestoreVehicleOrdersBruteForce(v, orders);
if (economy != NULL) economy->Restore();
return v;
}
/** Backs up a vehicle
* This should never be called when the object already contains a backup
* @param v the vehicle to backup
* @param p If it's set to the vehicle's owner then economy is backed up. If NULL then economy backup will be skipped.
*/
void BackuppedVehicle::Backup(const Vehicle *v, Player *p)
{
assert(!ContainsBackup());
if (p != NULL) {
assert(p->index == v->owner);
economy = new PlayerMoneyBackup(p);
}
vehicles = v->BackupVehicle();
if (orders != NULL) BackupVehicleOrders(v, orders);
}
void StopAllVehicles()
{
Vehicle *v;