truelight@2395: /* $Id$ */ truelight@2395: truelight@9360: /** @file ai.cpp handles the communication between the AI layer and the OpenTTD core */ truelight@9360: truelight@9360: #include "../../stdafx.h" truelight@9360: #include "../../openttd.h" truelight@9360: #include "../../variables.h" truelight@9360: #include "../../command.h" truelight@9360: #include "../../network/network.h" truelight@9360: #include "../../helpers.hpp" truelight@9390: #include "../../debug.h" truelight@2395: #include "ai.h" truelight@9360: #include "ai_base.hpp" truelight@9390: #include "ai_controller.hpp" truelight@9390: #include "ai_factory.hpp" truelight@9360: truelight@9361: static AIController *_ai_player[MAX_PLAYERS]; truelight@9360: static uint _ai_frame_counter; truelight@9360: static bool _ai_enabled; truelight@2715: truelight@2395: /** truelight@2395: * Run 1 tick of the AI. Don't overdo it, keep it realistic. truelight@2395: */ tron@2551: static void AI_RunTick(PlayerID player) truelight@2395: { truelight@2395: _current_player = player; truelight@2395: truelight@9390: /* If this is NULL, it means we couldn't find an AI for this player */ truelight@9390: if (_ai_player[player] == NULL) return; truelight@9390: truelight@9361: _ai_player[player]->IncreaseTick(); truelight@9361: _ai_player[player]->GameLoop(); truelight@2395: } truelight@2395: truelight@2395: truelight@2395: /** truelight@2395: * The gameloop for AIs. truelight@2395: * Handles one tick for all the AIs. truelight@2395: */ rubidium@6573: void AI_RunGameLoop() truelight@2395: { truelight@2395: /* Don't do anything if ai is disabled */ truelight@9360: if (!_ai_enabled) return; truelight@2395: Darkvater@5332: /* Don't do anything if we are a network-client, or the AI has been disabled */ Darkvater@5332: if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return; truelight@2682: truelight@2395: /* New tick */ truelight@9360: _ai_frame_counter++; truelight@2395: truelight@2395: /* Make sure the AI follows the difficulty rule.. */ tron@2446: assert(_opt.diff.competitor_speed <= 4); truelight@9360: if ((_ai_frame_counter & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return; truelight@2395: truelight@2395: /* Check for AI-client (so joining a network with an AI) */ Darkvater@4854: if (!_networking || _network_server) { truelight@2395: /* Check if we want to run AIs (server or SP only) */ tron@4000: const Player* p; truelight@2395: truelight@2395: FOR_ALL_PLAYERS(p) { tron@2767: if (p->is_active && p->is_ai) { truelight@2395: /* Run the script */ truelight@2395: AI_RunTick(p->index); truelight@2395: } truelight@2395: } truelight@2395: } truelight@2395: truelight@2395: _current_player = OWNER_NONE; truelight@2395: } truelight@2395: truelight@2395: /** truelight@2395: * A new AI sees the day of light. You can do here what ever you think is needed. truelight@2395: */ tron@2551: void AI_StartNewAI(PlayerID player) truelight@2395: { Darkvater@4850: assert(IsValidPlayer(player)); truelight@9360: if (!_ai_enabled) return; truelight@9360: if (_networking && !_network_server) return; truelight@2702: truelight@9390: _ai_player[player] = AIFactoryBase::SelectRandomAI(); truelight@9390: if (_ai_player[player] == NULL) { truelight@9390: DEBUG(ai, 0, "Couldn't find a suitable AI to start for company '%d'", player); truelight@9390: /* XXX -- We have no clean way to handle this yet! */ rubidium@9383: } truelight@2395: } truelight@2395: truelight@2395: /** truelight@2395: * This AI player died. Give it some chance to make a final puf. truelight@2395: */ tron@2551: void AI_PlayerDied(PlayerID player) truelight@2395: { truelight@9360: if (!_ai_enabled) return; truelight@9360: truelight@2395: /* Called if this AI died */ truelight@9361: delete _ai_player[player]; truelight@2395: } truelight@2395: truelight@2395: /** truelight@2395: * Initialize some AI-related stuff. truelight@2395: */ rubidium@6573: void AI_Initialize() truelight@2395: { truelight@2706: /* First, make sure all AIs are DEAD! */ truelight@2706: AI_Uninitialize(); truelight@2706: tron@2767: memset(&_ai_player, 0, sizeof(_ai_player)); truelight@9360: _ai_frame_counter = 0; truelight@9360: _ai_enabled = true; truelight@9400: truelight@9400: AIFactoryBase::RunInitializers(); truelight@2395: } truelight@2395: truelight@2395: /** truelight@2395: * Deinitializer for AI-related stuff. truelight@2395: */ rubidium@6573: void AI_Uninitialize() truelight@2395: { tron@4000: const Player* p; truelight@2395: truelight@2395: FOR_ALL_PLAYERS(p) { tron@2767: if (p->is_active && p->is_ai) AI_PlayerDied(p->index); truelight@2395: } truelight@2395: } truelight@9360: truelight@9360: /** truelight@9360: * Is it allowed to start a new AI. truelight@9360: * This function checks some boundries to see if we should launch a new AI. truelight@9360: * @return True if we can start a new AI. truelight@9360: */ truelight@9360: bool AI_AllowNewAI() truelight@9360: { truelight@9360: /* If disabled, no AI */ truelight@9360: if (!_ai_enabled) return false; truelight@9360: truelight@9360: /* If in network, but no server, no AI */ truelight@9360: if (_networking && !_network_server) return false; truelight@9360: truelight@9360: /* If in network, and server, possible AI */ truelight@9360: if (_networking && _network_server) { truelight@9360: /* Do we want AIs in multiplayer? */ truelight@9360: if (!_patches.ai_in_multiplayer) return false; truelight@9360: } truelight@9360: truelight@9360: return true; truelight@9360: }