File diff r10695:3124a970a753 → r10696:8dfe83e30d01
src/ai/ai_core.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file ai_core.cpp Implementation of AI. */
 

	
 
#include "../stdafx.h"
 
#include "../openttd.h"
 
#include "../company_type.h"
 
#include "../company_base.h"
 
#include "../company_func.h"
 
#include "../debug.h"
 
#include "../network/network.h"
 
#include "../settings_type.h"
 
#include "../window_type.h"
 
#include "../window_func.h"
 
#include "../command_func.h"
 
#include "ai.hpp"
 
#include "ai_info.hpp"
 
#include "ai_scanner.hpp"
 
#include "ai_instance.hpp"
 
#include "ai_config.hpp"
 

	
 
/* static */ uint AI::frame_counter = 0;
 
/* static */ AIScanner *AI::ai_scanner = NULL;
 

	
 
/* static */ bool AI::CanStartNew()
 
{
 
	/* Only allow new AIs on the server and only when that is allowed in multiplayer */
 
	return !_networking || (_network_server && _settings_game.ai.ai_in_multiplayer);
 
}
 

	
 
/* static */ void AI::StartNew(CompanyID company)
 
{
 
	assert(IsValidCompanyID(company));
 

	
 
	/* Clients shouldn't start AIs */
 
	if (_networking && !_network_server) return;
 

	
 
	AIInfo *info = AIConfig::GetConfig(company)->GetInfo();
 
	if (info == NULL) {
 
		info = AI::ai_scanner->SelectRandomAI();
 
		assert(info != NULL);
 
		/* Load default data and store the name in the settings */
 
		AIConfig::GetConfig(company)->ChangeAI(info->GetDirName());
 
	}
 

	
 
	_current_company = company;
 
	Company *c = GetCompany(company);
 

	
 
	c->ai_info = info;
 
	c->ai_instance = new AIInstance(info);
 

	
 
	InvalidateWindowData(WC_AI_DEBUG, 0, -1);
 
	return;
 
}
 

	
 
/* static */ void AI::GameLoop()
 
{
 
	/* If we are in networking, only servers run this function, and that only if it is allowed */
 
	if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return;
 

	
 
	/* The speed with which AIs go, is limited by the 'competitor_speed' */
 
	AI::frame_counter++;
 
	assert(_settings_game.difficulty.competitor_speed <= 4);
 
	if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return;
 

	
 
	const Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		if (!IsHumanCompany(c->index)) {
 
			_current_company = c->index;
 
			c->ai_instance->GameLoop();
 
		}
 
	}
 

	
 
	_current_company = OWNER_NONE;
 
}
 

	
 
/* static */ uint AI::GetTick()
 
{
 
	return AI::frame_counter;
 
}
 

	
 
/* static */ void AI::Stop(CompanyID company)
 
{
 
	if (_networking && !_network_server) return;
 

	
 
	_current_company = company;
 
	Company *c = GetCompany(company);
 

	
 
	delete c->ai_instance;
 
	c->ai_instance = NULL;
 

	
 
	InvalidateWindowData(WC_AI_DEBUG, 0, -1);
 
}
 

	
 
/* static */ void AI::KillAll()
 
{
 
	/* It might happen there are no companies .. than we have nothing to loop */
 
	if (GetCompanyPoolSize() == 0) return;
 

	
 
	const Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		if (!IsHumanCompany(c->index)) AI::Stop(c->index);
 
	}
 
}
 

	
 
/* static */ void AI::Initialize()
 
{
 
	if (AI::ai_scanner != NULL) AI::Uninitialize(true);
 

	
 
	AI::frame_counter = 0;
 
	if (AI::ai_scanner == NULL) AI::ai_scanner = new AIScanner();
 
}
 

	
 
/* static */ void AI::Uninitialize(bool keepConfig)
 
{
 
	AI::KillAll();
 

	
 
	if (keepConfig) {
 
		/* Run a rescan, which indexes all AIInfos again, and check if we can
 
		 *  still load all the AIS, while keeping the configs in place */
 
		Rescan();
 
	} else {
 
		delete AI::ai_scanner;
 
		AI::ai_scanner = NULL;
 

	
 
		for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
			if (_settings_game.ai_config[c] != NULL) {
 
				delete _settings_game.ai_config[c];
 
				_settings_game.ai_config[c] = NULL;
 
			}
 
			if (_settings_newgame.ai_config[c] != NULL) {
 
				delete _settings_newgame.ai_config[c];
 
				_settings_newgame.ai_config[c] = NULL;
 
			}
 
		}
 
	}
 
}
 

	
 
/* static */ void AI::ResetConfig()
 
{
 
	/* Check for both newgame as current game if we can reload the AIInfo insde
 
	 *  the AIConfig. If not, remove the AI from the list (which will assign
 
	 *  a random new AI on reload). */
 
	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
		if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasAI()) {
 
			if (!_settings_game.ai_config[c]->ResetInfo()) {
 
				DEBUG(ai, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName());
 
				_settings_game.ai_config[c]->ChangeAI(NULL);
 
			}
 
		}
 
		if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasAI()) {
 
			if (!_settings_newgame.ai_config[c]->ResetInfo()) {
 
				DEBUG(ai, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName());
 
				_settings_newgame.ai_config[c]->ChangeAI(NULL);
 
			}
 
		}
 
	}
 
}
 

	
 
/* static */ void AI::NewEvent(CompanyID company, AIEvent *event)
 
{
 
	/* Clients should ignore events */
 
	if (_networking && !_network_server) return;
 

	
 
	/* Only AIs can have an event-queue */
 
	if (!IsValidCompanyID(company) || IsHumanCompany(company)) return;
 

	
 
	/* Queue the event */
 
	CompanyID old_company = _current_company;
 
	_current_company = company;
 
	AIEventController::InsertEvent(event);
 
	_current_company = old_company;
 
}
 

	
 
/* static */ void AI::BroadcastNewEvent(AIEvent *event, CompanyID skip_company)
 
{
 
	/* Clients should ignore events */
 
	if (_networking && !_network_server) return;
 

	
 
	/* Try to send the event to all AIs */
 
	for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
		if (c != skip_company) AI::NewEvent(c, event);
 
	}
 
}
 

	
 
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	AIObject::SetLastCommandRes(success);
 

	
 
	if (!success) {
 
		AIObject::SetLastError(AIError::StringToError(_error_message));
 
	} else {
 
		AIObject::IncreaseDoCommandCosts(AIObject::GetLastCost());
 
	}
 

	
 
	GetCompany(_current_company)->ai_instance->Continue();
 
}
 

	
 
/* static */ void AI::Save(CompanyID company)
 
{
 
	if (!_networking || _network_server) {
 
		assert(IsValidCompanyID(company));
 
		assert(GetCompany(company)->ai_instance != NULL);
 

	
 
		CompanyID old_company = _current_company;
 
		_current_company = company;
 
		GetCompany(company)->ai_instance->Save();
 
		_current_company = old_company;
 
	} else {
 
		AIInstance::SaveEmpty();
 
	}
 
}
 

	
 
/* static */ void AI::Load(CompanyID company)
 
{
 
	if (!_networking || _network_server) {
 
		assert(IsValidCompanyID(company));
 
		assert(GetCompany(company)->ai_instance != NULL);
 

	
 
		CompanyID old_company = _current_company;
 
		_current_company = company;
 
		GetCompany(company)->ai_instance->Load();
 
		_current_company = old_company;
 
	} else {
 
		/* Read, but ignore, the load data */
 
		AIInstance::LoadEmpty();
 
	}
 
}
 

	
 
/* static */ char *AI::GetConsoleList(char *p, const char *last)
 
{
 
	return AI::ai_scanner->GetAIConsoleList(p, last);
 
}
 

	
 
/* static */ const AIInfoList *AI::GetInfoList()
 
{
 
	return AI::ai_scanner->GetAIInfoList();
 
}
 

	
 
/* static */ AIInfo *AI::GetCompanyInfo(const char *name)
 
{
 
	return AI::ai_scanner->FindAI(name);
 
}
 

	
 
/* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
 
{
 
	return AI::ai_scanner->ImportLibrary(library, class_name, version, vm, GetCompany(_current_company)->ai_instance->GetController());
 
}
 

	
 
/* static */ void AI::Rescan()
 
{
 
	AI::ai_scanner->RescanAIDir();
 
	ResetConfig();
 
}