(svn r11796) [NoAI] -Sync: with trunk r11502:11795.
/* $Id$ */
/** @file ai_transactionmode.cpp class to switch the AI to Transaction mode */
#include "ai_transactionmode.hpp"
#include "ai_execmode.hpp"
#include "../../command_func.h"
#include "../../debug.h"
#include <stack>
bool AITransactionMode::ModeProc(TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCost costs)
{
AITransactionMode *instance = (AITransactionMode *)AIObject::GetDoCommandModeInstance();
/* Don't record if we are stopped */
if (instance->stopped) return false;
AITransactionModeCommand command;
/* Store all params in a nice list, so we can execute them later */
command.tile = tile;
command.p1 = p1;
command.p2 = p2;
command.procc = procc;
command.text = (_cmd_text == NULL) ? NULL : strdup(_cmd_text);
instance->command_stack.push(command);
instance->costs.AddCost(costs);
/* Now we return 'false', as we don't want to execute the commands just yet */
return false;
}
AITransactionMode::AITransactionMode()
{
this->costs = CommandCost();
this->stopped = false;
this->last_mode = this->GetDoCommandMode();
this->last_instance = this->GetDoCommandModeInstance();
this->SetDoCommandMode(&AITransactionMode::ModeProc, this);
}
AITransactionMode::~AITransactionMode()
{
this->SetDoCommandMode(this->last_mode, this->last_instance);
/* Clean up the command_stack nicely (as in: free the cmd_text) */
AITransactionModeCommand command;
while (!this->command_stack.empty()) {
command = this->command_stack.front();
free(command.text);
this->command_stack.pop();
}
/* Clean up the reverse_stack too */
while (!this->reverse_stack.empty()) {
command = this->reverse_stack.front();
free(command.text);
this->reverse_stack.pop();
}
}
bool AITransactionMode::Execute()
{
/* Make sure we are stopped */
this->Stop();
/* Remove the costs this transaction costs from the total costs, so any
* 'accounting' running on the background will get the real costs for
* executing, and not the double value of both testing and executing */
this->IncreaseDoCommandCosts(-this->GetCosts());
/* Switch to a forced execute mode */
AIExecMode exec;
/* Reverse stack should be empty */
assert(this->reverse_stack.empty());
AITransactionModeCommand command;
while (!this->command_stack.empty()) {
command = this->command_stack.front();
_cmd_text = command.text;
/* Make sure we return 'false' if the command fails to execute. This allows rollback of failed builds. */
if (!this->DoCommand(command.tile, command.p1, command.p2, command.procc)) return false;
/* Add the command to the reverse stack */
this->reverse_stack.push(command);
/* Remove the item from the list */
this->command_stack.pop();
}
/* Everything went okay, clean the reverse stack */
while (!this->reverse_stack.empty()) {
command = this->reverse_stack.front();
free(command.text);
this->reverse_stack.pop();
}
/* Reverse stack should be empty again */
assert(this->reverse_stack.empty());
return true;
}
void AITransactionMode::Stop()
{
this->stopped = true;
}
void AITransactionMode::Rollback()
{
AITransactionModeCommand command;
DEBUG(ai, 0, "AITransactionMode::Rollback is not yet implemented");
return;
while (!this->reverse_stack.empty()) {
command = this->reverse_stack.front();
_cmd_text = command.text;
/* Find the reverse, and issue it */
/* TODO -- Make a table which reverses every command.procc */
this->DoCommand(command.tile, command.p1, command.p2, command.procc);
/* Remove the item from the list */
this->reverse_stack.pop();
}
}
Money AITransactionMode::GetCosts()
{
return this->costs.GetCost();
}
void AITransactionMode::Append(AITransactionMode *transaction)
{
/* Can't append to myself! */
if (transaction == this) return;
/* Simply move the queue from transaction to ourself */
while (!transaction->command_stack.empty()) {
this->command_stack.push(transaction->command_stack.front());
transaction->command_stack.pop();
}
}