ai_scanner.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../stdafx.h"
00013 #include "../debug.h"
00014 #include "../fileio_func.h"
00015 #include "../network/network.h"
00016 #include "../core/random_func.hpp"
00017 
00018 #include "../script/squirrel_class.hpp"
00019 #include "ai_info.hpp"
00020 #include "ai_scanner.hpp"
00021 #include "../script/api/script_controller.hpp"
00022 
00023 
00024 AIScannerInfo::AIScannerInfo() :
00025   ScriptScanner(),
00026   info_dummy(NULL)
00027 {
00028 }
00029 
00030 void AIScannerInfo::Initialize()
00031 {
00032   ScriptScanner::Initialize("AIScanner");
00033 
00034   /* Create the dummy AI */
00035   free(this->main_script);
00036   this->main_script = strdup("%_dummy");
00037   extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir);
00038   Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
00039 }
00040 
00041 void AIScannerInfo::SetDummyAI(class AIInfo *info)
00042 {
00043   this->info_dummy = info;
00044 }
00045 
00046 AIScannerInfo::~AIScannerInfo()
00047 {
00048   delete this->info_dummy;
00049 }
00050 
00051 void AIScannerInfo::GetScriptName(ScriptInfo *info, char *name, int len)
00052 {
00053   snprintf(name, len, "%s", info->GetName());
00054 }
00055 
00056 void AIScannerInfo::RegisterAPI(class Squirrel *engine)
00057 {
00058   AIInfo::RegisterAPI(engine);
00059 }
00060 
00061 AIInfo *AIScannerInfo::SelectRandomAI() const
00062 {
00063   uint num_random_ais = 0;
00064   for (ScriptInfoList::const_iterator it = this->info_single_list.begin(); it != this->info_single_list.end(); it++) {
00065     AIInfo *i = static_cast<AIInfo *>((*it).second);
00066     if (i->UseAsRandomAI()) num_random_ais++;
00067   }
00068 
00069   if (num_random_ais == 0) {
00070     DEBUG(script, 0, "No suitable AI found, loading 'dummy' AI.");
00071     return this->info_dummy;
00072   }
00073 
00074   /* Find a random AI */
00075   uint pos;
00076   if (_networking) {
00077     pos = InteractiveRandomRange(num_random_ais);
00078   } else {
00079     pos = RandomRange(num_random_ais);
00080   }
00081 
00082   /* Find the Nth item from the array */
00083   ScriptInfoList::const_iterator it = this->info_single_list.begin();
00084 
00085 #define GetAIInfo(it) static_cast<AIInfo *>((*it).second)
00086   while (!GetAIInfo(it)->UseAsRandomAI()) it++;
00087   for (; pos > 0; pos--) {
00088     it++;
00089     while (!GetAIInfo(it)->UseAsRandomAI()) it++;
00090   }
00091   return GetAIInfo(it);
00092 #undef GetAIInfo
00093 }
00094 
00095 AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match)
00096 {
00097   if (this->info_list.size() == 0) return NULL;
00098   if (nameParam == NULL) return NULL;
00099 
00100   char ai_name[1024];
00101   ttd_strlcpy(ai_name, nameParam, sizeof(ai_name));
00102   strtolower(ai_name);
00103 
00104   AIInfo *info = NULL;
00105   int version = -1;
00106 
00107   if (versionParam == -1) {
00108     /* We want to load the latest version of this AI; so find it */
00109     if (this->info_single_list.find(ai_name) != this->info_single_list.end()) return static_cast<AIInfo *>(this->info_single_list[ai_name]);
00110 
00111     /* If we didn't find a match AI, maybe the user included a version */
00112     char *e = strrchr(ai_name, '.');
00113     if (e == NULL) return NULL;
00114     *e = '\0';
00115     e++;
00116     versionParam = atoi(e);
00117     /* FALL THROUGH, like we were calling this function with a version. */
00118   }
00119 
00120   if (force_exact_match) {
00121     /* Try to find a direct 'name.version' match */
00122     char ai_name_tmp[1024];
00123     snprintf(ai_name_tmp, sizeof(ai_name_tmp), "%s.%d", ai_name, versionParam);
00124     strtolower(ai_name_tmp);
00125     if (this->info_list.find(ai_name_tmp) != this->info_list.end()) return static_cast<AIInfo *>(this->info_list[ai_name_tmp]);
00126   }
00127 
00128   /* See if there is a compatible AI which goes by that name, with the highest
00129    *  version which allows loading the requested version */
00130   ScriptInfoList::iterator it = this->info_list.begin();
00131   for (; it != this->info_list.end(); it++) {
00132     AIInfo *i = static_cast<AIInfo *>((*it).second);
00133     if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) {
00134       version = (*it).second->GetVersion();
00135       info = i;
00136     }
00137   }
00138 
00139   return info;
00140 }
00141 
00142 
00143 void AIScannerLibrary::Initialize()
00144 {
00145   ScriptScanner::Initialize("AIScanner");
00146 }
00147 
00148 void AIScannerLibrary::GetScriptName(ScriptInfo *info, char *name, int len)
00149 {
00150   AILibrary *library = static_cast<AILibrary *>(info);
00151   snprintf(name, len, "%s.%s", library->GetCategory(), library->GetInstanceName());
00152 }
00153 
00154 void AIScannerLibrary::RegisterAPI(class Squirrel *engine)
00155 {
00156   AILibrary::RegisterAPI(engine);
00157 }
00158 
00159 AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version)
00160 {
00161   /* Internally we store libraries as 'library.version' */
00162   char library_name[1024];
00163   snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
00164   strtolower(library_name);
00165 
00166   /* Check if the library + version exists */
00167   ScriptInfoList::iterator iter = this->info_list.find(library_name);
00168   if (iter == this->info_list.end()) return NULL;
00169 
00170   return static_cast<AILibrary *>((*iter).second);
00171 }