src/ai/api/ai_object.cpp
author truelight
Mon, 19 Mar 2007 14:30:56 +0000
branchnoai
changeset 9486 a9b5f6b8667c
parent 9473 dcbcd1c4496d
child 9496 05ebee9884b3
permissions -rw-r--r--
(svn r9336) [NoAI] -Fix: remove 'flags' for AI DoCommand and detect its value automaticly
/* $Id$ */

/** @file ai_object.cpp handles the commands-related functions of the AIObject class */

#include "ai_object.hpp"
#include "../../command.h"
#include "../../player.h"
#include "../ai.h"
#include "../ai_threads.h"

void AIObject::SetDoCommandDelay(uint ticks)
{
	assert(ticks > 0);
	AIObject::GetDoCommandStruct(_current_player)->delay = ticks;
}

uint AIObject::GetDoCommandDelay()
{
	return AIObject::GetDoCommandStruct(_current_player)->delay;
}

void AIObject::SetDoCommandMode(AIModeProc *proc, AIObject *instance)
{
	AIObject::GetDoCommandStruct(_current_player)->mode = proc;
	AIObject::GetDoCommandStruct(_current_player)->mode_instance = instance;
}

AIModeProc *AIObject::GetDoCommandMode()
{
	return AIObject::GetDoCommandStruct(_current_player)->mode;
}

AIObject *AIObject::GetDoCommandModeInstance()
{
	return AIObject::GetDoCommandStruct(_current_player)->mode_instance;
}

void AIObject::SetDoCommandCosts(int32 value)
{
	AIObject::GetDoCommandStruct(_current_player)->costs = value;
}

void AIObject::IncreaseDoCommandCosts(int32 value)
{
	AIObject::GetDoCommandStruct(_current_player)->costs += value;
}

int32 AIObject::GetDoCommandCosts()
{
	return AIObject::GetDoCommandStruct(_current_player)->costs;
}

AIObject::AIDoCommandStruct *AIObject::GetDoCommandStruct(PlayerID player)
{
	/* Storage for data on per-AI level */
	static AIObject::AIDoCommandStruct command_struct[MAX_PLAYERS];

	return &command_struct[player];
}

void AIObject::ResetInternalPlayerData()
{
	AIObject::AIDoCommandStruct *command_struct = GetDoCommandStruct(_current_player);
	command_struct->mode = NULL;
	command_struct->delay = 1;
	command_struct->costs = 0;
}

bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint procc)
{
	uint32 flags = 0;
	PlayerID old_lp;
	int32 res = 0;
	const char* tmp_cmdtext;

	flags |= DC_NO_WATER;
	if (procc != CMD_LANDSCAPE_CLEAR) flags |= DC_AUTO;

	/* The test already resets _cmd_text, so backup the pointer */
	tmp_cmdtext = _cmd_text;

	/* First, do a test-run to see if we can do this */
	res = ::DoCommand(tile, p1, p2, flags, procc);
	/* The command failed, so return */
	if (::CmdFailed(res)) return false;

	/* Restore _cmd_text */
	_cmd_text = tmp_cmdtext;

	/* Check what the callback wants us to do */
	if (AIObject::GetDoCommandMode() != NULL && !AIObject::GetDoCommandMode()(tile, p1, p2, procc, res)) {
		AIObject::IncreaseDoCommandCosts(res);
		return true;
	}

	/* If we did a DC_EXEC, and the command did not return an error, execute it
	 * over the network */
	if (flags & DC_AUTO)     procc |= CMD_AUTO;
	if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;

#ifdef ENABLE_NETWORK
	/* Send the command */
	if (_networking) {
		/* NetworkSend_Command needs _local_player to be set correctly, so
		 * adjust it, and put it back right after the function */
		old_lp = _local_player;
		_local_player = _current_player;
		::NetworkSend_Command(tile, p1, p2, procc, CcAI);
		_local_player = old_lp;

		/* Suspend the AI till the command is really executed */
		AI_SuspendPlayer(_current_player, -AIObject::GetDoCommandDelay());
		/* Check if the callback still agrees with us, else return error */
		if (!AI_GetCallbackResult(_current_player)) res = CMD_ERROR;
	} else {
#else
	{
#endif
		/* For SinglePlayer we execute the command immediatly */
		::DoCommandP(tile, p1, p2, NULL, procc);
		/* Suspend the AI player for 1 tick, so it simulates MultiPlayer */
		AI_SuspendPlayer(_current_player, AIObject::GetDoCommandDelay());
	}

	if (::CmdFailed(res)) return false;

	AIObject::IncreaseDoCommandCosts(res);
	return true;
}