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