src/ai/api/ai_transactionmode.cpp
author rubidium
Sun, 25 Mar 2007 12:38:29 +0000
branchnoai
changeset 9521 b9dabdbe1dc5
parent 9486 a9b5f6b8667c
child 9560 ff2dde050a4c
permissions -rw-r--r--
(svn r9441) [NoAI] -Codechange: make the Squirrel method registration happen in the same order as the methods occur in the class.
/* $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();

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