src/ai/api/ai_transactionmode.cpp
author truelight
Tue, 27 Mar 2007 10:22:39 +0000
branchnoai
changeset 9560 ff2dde050a4c
parent 9486 a9b5f6b8667c
child 9629 66dde6412125
permissions -rw-r--r--
(svn r9498) [NoAI] -Add: added regression for AITransactionMode()
-Fix: AITransActionMode() now substracts the costs he makes when executing, to keep the GetCosts in global space correct
-Fix: Reset NewVehicleID on building a vehicle
-Update: remove the need for a local variable in ai_sign.cpp
/* $Id$ */

/** @file ai_transactionmode.cpp class to switch the AI to Transaction mode */

#include "ai_transactionmode.hpp"
#include "ai_execmode.hpp"
#include "../../command.h"
#include "../../debug.h"
#include <stack>

bool AITransactionMode::ModeProc(TileIndex tile, uint32 p1, uint32 p2, uint procc, int32 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 += costs;

	/* Now we return 'false', as we don't want to execute the commands just yet */
	return false;
}

AITransactionMode::AITransactionMode()
{
	this->costs         = 0;
	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();
	}
}

int32 AITransactionMode::GetCosts()
{
	return this->costs;
}

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();
	}
}