src/ai/core/ai.cpp
author truelight
Tue, 13 Mar 2007 18:36:29 +0000
branchnoai
changeset 9361 7bb2bd22b16e
parent 9360 c20d0a9e0a5c
child 9365 c3d08e0b1083
permissions -rw-r--r--
(svn r9144) [NoAI] -Change: moved command functions to AIObject, and made AIBase depend on AIObject
-Change: split AIBase into AIBase and AIController, where the last should be extended by the real AI
-Remove: removed the SP queue-code, as it is no longer needed with the new message system
/* $Id$ */

/** @file ai.cpp handles the communication between the AI layer and the OpenTTD core */

#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../variables.h"
#include "../../command.h"
#include "../../network/network.h"
#include "../../helpers.hpp"
#include "ai.h"
#include "ai_base.hpp"
#include "../NoAI/NoAI.hpp"

static AIController *_ai_player[MAX_PLAYERS];
static uint _ai_frame_counter;
static bool _ai_enabled;

/**
 * Run 1 tick of the AI. Don't overdo it, keep it realistic.
 */
static void AI_RunTick(PlayerID player)
{
	_current_player = player;

	_ai_player[player]->IncreaseTick();
	_ai_player[player]->GameLoop();
}


/**
 * The gameloop for AIs.
 *  Handles one tick for all the AIs.
 */
void AI_RunGameLoop()
{
	/* Don't do anything if ai is disabled */
	if (!_ai_enabled) return;

	/* Don't do anything if we are a network-client, or the AI has been disabled */
	if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return;

	/* New tick */
	_ai_frame_counter++;

	/* Make sure the AI follows the difficulty rule.. */
	assert(_opt.diff.competitor_speed <= 4);
	if ((_ai_frame_counter & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;

	/* Check for AI-client (so joining a network with an AI) */
	if (!_networking || _network_server) {
		/* Check if we want to run AIs (server or SP only) */
		const Player* p;

		FOR_ALL_PLAYERS(p) {
			if (p->is_active && p->is_ai) {
				/* Run the script */
				AI_RunTick(p->index);
			}
		}
	}

	_current_player = OWNER_NONE;
}

/**
 * A new AI sees the day of light. You can do here what ever you think is needed.
 */
void AI_StartNewAI(PlayerID player)
{
	assert(IsValidPlayer(player));
	if (!_ai_enabled) return;
	if (_networking && !_network_server) return;

	/* Called if a new AI is booted */
	_ai_player[player] = new NoAI();
}

/**
 * This AI player died. Give it some chance to make a final puf.
 */
void AI_PlayerDied(PlayerID player)
{
	if (!_ai_enabled) return;

	/* Called if this AI died */
	delete _ai_player[player];
}

/**
 * Initialize some AI-related stuff.
 */
void AI_Initialize()
{
	/* First, make sure all AIs are DEAD! */
	AI_Uninitialize();

	memset(&_ai_player, 0, sizeof(_ai_player));
	_ai_frame_counter = 0;
	_ai_enabled = true;
}

/**
 * Deinitializer for AI-related stuff.
 */
void AI_Uninitialize()
{
	const Player* p;

	FOR_ALL_PLAYERS(p) {
		if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
	}
}

/**
 * Is it allowed to start a new AI.
 * This function checks some boundries to see if we should launch a new AI.
 * @return True if we can start a new AI.
 */
bool AI_AllowNewAI()
{
	/* If disabled, no AI */
	if (!_ai_enabled) return false;

	/* If in network, but no server, no AI */
	if (_networking && !_network_server) return false;

	/* If in network, and server, possible AI */
	if (_networking && _network_server) {
		/* Do we want AIs in multiplayer? */
		if (!_patches.ai_in_multiplayer) return false;
	}

	return true;
}