ai_core.cpp

Go to the documentation of this file.
00001 /* $Id: ai_core.cpp 15562 2009-02-23 20:57:55Z yexo $ */
00002 
00005 #include "../stdafx.h"
00006 #include "../core/bitmath_func.hpp"
00007 #include "../company_base.h"
00008 #include "../company_func.h"
00009 #include "../debug.h"
00010 #include "../network/network.h"
00011 #include "../settings_type.h"
00012 #include "../window_func.h"
00013 #include "../command_func.h"
00014 #include "ai.hpp"
00015 #include "ai_scanner.hpp"
00016 #include "ai_instance.hpp"
00017 #include "ai_config.hpp"
00018 
00019 /* static */ uint AI::frame_counter = 0;
00020 /* static */ AIScanner *AI::ai_scanner = NULL;
00021 
00022 /* static */ bool AI::CanStartNew()
00023 {
00024   /* Only allow new AIs on the server and only when that is allowed in multiplayer */
00025   return !_networking || (_network_server && _settings_game.ai.ai_in_multiplayer);
00026 }
00027 
00028 /* static */ void AI::StartNew(CompanyID company)
00029 {
00030   assert(IsValidCompanyID(company));
00031 
00032   /* Clients shouldn't start AIs */
00033   if (_networking && !_network_server) return;
00034 
00035   AIInfo *info = AIConfig::GetConfig(company)->GetInfo();
00036   if (info == NULL) {
00037     info = AI::ai_scanner->SelectRandomAI();
00038     assert(info != NULL);
00039     /* Load default data and store the name in the settings */
00040     AIConfig::GetConfig(company)->ChangeAI(info->GetName());
00041   }
00042 
00043   _current_company = company;
00044   Company *c = GetCompany(company);
00045 
00046   c->ai_info = info;
00047   assert(c->ai_instance == NULL);
00048   c->ai_instance = new AIInstance(info);
00049 
00050   InvalidateWindowData(WC_AI_DEBUG, 0, -1);
00051   return;
00052 }
00053 
00054 /* static */ void AI::GameLoop()
00055 {
00056   /* If we are in networking, only servers run this function, and that only if it is allowed */
00057   if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return;
00058 
00059   /* The speed with which AIs go, is limited by the 'competitor_speed' */
00060   AI::frame_counter++;
00061   assert(_settings_game.difficulty.competitor_speed <= 4);
00062   if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return;
00063 
00064   const Company *c;
00065   FOR_ALL_COMPANIES(c) {
00066     if (!IsHumanCompany(c->index)) {
00067       _current_company = c->index;
00068       c->ai_instance->GameLoop();
00069     }
00070   }
00071 
00072   /* Occasionally collect garbage; every 255 ticks do one company.
00073    * Effectively collecting garbage once every two months per AI. */
00074   if ((AI::frame_counter & 255) == 0) {
00075     CompanyID cid = (CompanyID)GB(AI::frame_counter, 8, 4);
00076     if (IsValidCompanyID(cid) && !IsHumanCompany(cid)) GetCompany(cid)->ai_instance->CollectGarbage();
00077   }
00078 
00079   _current_company = OWNER_NONE;
00080 }
00081 
00082 /* static */ uint AI::GetTick()
00083 {
00084   return AI::frame_counter;
00085 }
00086 
00087 /* static */ void AI::Stop(CompanyID company)
00088 {
00089   if (_networking && !_network_server) return;
00090 
00091   CompanyID old_company = _current_company;
00092   _current_company = company;
00093   Company *c = GetCompany(company);
00094 
00095   delete c->ai_instance;
00096   c->ai_instance = NULL;
00097 
00098   _current_company = old_company;
00099 
00100   InvalidateWindowData(WC_AI_DEBUG, 0, -1);
00101 }
00102 
00103 /* static */ void AI::KillAll()
00104 {
00105   /* It might happen there are no companies .. than we have nothing to loop */
00106   if (GetCompanyPoolSize() == 0) return;
00107 
00108   const Company *c;
00109   FOR_ALL_COMPANIES(c) {
00110     if (!IsHumanCompany(c->index)) AI::Stop(c->index);
00111   }
00112 }
00113 
00114 /* static */ void AI::Initialize()
00115 {
00116   if (AI::ai_scanner != NULL) AI::Uninitialize(true);
00117 
00118   AI::frame_counter = 0;
00119   if (AI::ai_scanner == NULL) AI::ai_scanner = new AIScanner();
00120 }
00121 
00122 /* static */ void AI::Uninitialize(bool keepConfig)
00123 {
00124   AI::KillAll();
00125 
00126   if (keepConfig) {
00127     /* Run a rescan, which indexes all AIInfos again, and check if we can
00128      *  still load all the AIS, while keeping the configs in place */
00129     Rescan();
00130   } else {
00131     delete AI::ai_scanner;
00132     AI::ai_scanner = NULL;
00133 
00134     for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00135       if (_settings_game.ai_config[c] != NULL) {
00136         delete _settings_game.ai_config[c];
00137         _settings_game.ai_config[c] = NULL;
00138       }
00139       if (_settings_newgame.ai_config[c] != NULL) {
00140         delete _settings_newgame.ai_config[c];
00141         _settings_newgame.ai_config[c] = NULL;
00142       }
00143     }
00144   }
00145 }
00146 
00147 /* static */ void AI::ResetConfig()
00148 {
00149   /* Check for both newgame as current game if we can reload the AIInfo insde
00150    *  the AIConfig. If not, remove the AI from the list (which will assign
00151    *  a random new AI on reload). */
00152   for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00153     if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasAI()) {
00154       if (!_settings_game.ai_config[c]->ResetInfo()) {
00155         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());
00156         _settings_game.ai_config[c]->ChangeAI(NULL);
00157       }
00158     }
00159     if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasAI()) {
00160       if (!_settings_newgame.ai_config[c]->ResetInfo()) {
00161         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());
00162         _settings_newgame.ai_config[c]->ChangeAI(NULL);
00163       }
00164     }
00165   }
00166 }
00167 
00168 /* static */ void AI::NewEvent(CompanyID company, AIEvent *event)
00169 {
00170   /* AddRef() and Release() need to be called at least once, so do it here */
00171   event->AddRef();
00172 
00173   /* Clients should ignore events */
00174   if (_networking && !_network_server) {
00175     event->Release();
00176     return;
00177   }
00178 
00179   /* Only AIs can have an event-queue */
00180   if (!IsValidCompanyID(company) || IsHumanCompany(company)) {
00181     event->Release();
00182     return;
00183   }
00184 
00185   /* Queue the event */
00186   CompanyID old_company = _current_company;
00187   _current_company = company;
00188   AIEventController::InsertEvent(event);
00189   _current_company = old_company;
00190 
00191   event->Release();
00192 }
00193 
00194 /* static */ void AI::BroadcastNewEvent(AIEvent *event, CompanyID skip_company)
00195 {
00196   /* AddRef() and Release() need to be called at least once, so do it here */
00197   event->AddRef();
00198 
00199   /* Clients should ignore events */
00200   if (_networking && !_network_server) {
00201     event->Release();
00202     return;
00203   }
00204 
00205   /* Try to send the event to all AIs */
00206   for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00207     if (c != skip_company) AI::NewEvent(c, event);
00208   }
00209 
00210   event->Release();
00211 }
00212 
00213 void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
00214 {
00215   AIObject::SetLastCommandRes(success);
00216 
00217   if (!success) {
00218     AIObject::SetLastError(AIError::StringToError(_error_message));
00219   } else {
00220     AIObject::IncreaseDoCommandCosts(AIObject::GetLastCost());
00221   }
00222 
00223   GetCompany(_current_company)->ai_instance->Continue();
00224 }
00225 
00226 /* static */ void AI::Save(CompanyID company)
00227 {
00228   if (!_networking || _network_server) {
00229     assert(IsValidCompanyID(company));
00230     assert(GetCompany(company)->ai_instance != NULL);
00231 
00232     CompanyID old_company = _current_company;
00233     _current_company = company;
00234     GetCompany(company)->ai_instance->Save();
00235     _current_company = old_company;
00236   } else {
00237     AIInstance::SaveEmpty();
00238   }
00239 }
00240 
00241 /* static */ void AI::Load(CompanyID company, int version)
00242 {
00243   if (!_networking || _network_server) {
00244     assert(IsValidCompanyID(company));
00245     assert(GetCompany(company)->ai_instance != NULL);
00246 
00247     CompanyID old_company = _current_company;
00248     _current_company = company;
00249     GetCompany(company)->ai_instance->Load(version);
00250     _current_company = old_company;
00251   } else {
00252     /* Read, but ignore, the load data */
00253     AIInstance::LoadEmpty();
00254   }
00255 }
00256 
00257 /* static */ int AI::GetStartNextTime()
00258 {
00259   /* Find the first company which doesn't exist yet */
00260   for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00261     if (!IsValidCompanyID(c)) return AIConfig::GetConfig(c)->GetSetting("start_date");
00262   }
00263 
00264   /* Currently no AI can be started, check again in a year. */
00265   return DAYS_IN_YEAR;
00266 }
00267 
00268 /* static */ char *AI::GetConsoleList(char *p, const char *last)
00269 {
00270   return AI::ai_scanner->GetAIConsoleList(p, last);
00271 }
00272 
00273 /* static */ const AIInfoList *AI::GetInfoList()
00274 {
00275   return AI::ai_scanner->GetAIInfoList();
00276 }
00277 
00278 /* static */ const AIInfoList *AI::GetUniqueInfoList()
00279 {
00280   return AI::ai_scanner->GetUniqueAIInfoList();
00281 }
00282 
00283 /* static */ AIInfo *AI::FindInfo(const char *name, int version)
00284 {
00285   return AI::ai_scanner->FindInfo(name, version);
00286 }
00287 
00288 /* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
00289 {
00290   return AI::ai_scanner->ImportLibrary(library, class_name, version, vm, GetCompany(_current_company)->ai_instance->GetController());
00291 }
00292 
00293 /* static */ void AI::Rescan()
00294 {
00295   AI::ai_scanner->RescanAIDir();
00296   ResetConfig();
00297 }

Generated on Mon Mar 23 00:25:17 2009 for OpenTTD by  doxygen 1.5.6